package web import ( "context" "time" ) // UserInfo represents user information with tracking details type UserInfo struct { UserID string `json:"user_id"` UserName string `json:"user_name"` Trace string `json:"trace"` VisitTime time.Time `json:"visit_time"` FromIP string `json:"from_ip"` Province string `json:"province"` City string `json:"city"` } // contextKey is the type for context keys to prevent collisions type contextKey string const ( // Context keys for each field UserIDKey contextKey = "userID" UserNameKey contextKey = "userName" TraceKey contextKey = "trace" VisitTimeKey contextKey = "visitTime" FromIPKey contextKey = "fromIP" ProvinceKey contextKey = "province" CityKey contextKey = "city" ) // GetUserID returns user ID from context func GetUserID(ctx context.Context) string { if ctx == nil { return "" } if val, ok := ctx.Value(UserIDKey).(string); ok { return val } return "" } // SetUserID sets user ID in context and returns new context func SetUserID(ctx context.Context, userID string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, UserIDKey, userID) } // GetUserName returns user name from context func GetUserName(ctx context.Context) string { if ctx == nil { return "" } if val, ok := ctx.Value(UserNameKey).(string); ok { return val } return "" } // SetUserName sets user name in context and returns new context func SetUserName(ctx context.Context, userName string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, UserNameKey, userName) } // GetTrace returns trace ID from context func GetTrace(ctx context.Context) string { if ctx == nil { return "" } if val, ok := ctx.Value(TraceKey).(string); ok { return val } return "" } // SetTrace sets trace ID in context and returns new context func SetTrace(ctx context.Context, trace string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, TraceKey, trace) } // GetVisitTime returns visit time from context func GetVisitTime(ctx context.Context) time.Time { if ctx == nil { return time.Time{} } if val, ok := ctx.Value(VisitTimeKey).(time.Time); ok { return val } return time.Time{} } // SetVisitTime sets visit time in context and returns new context func SetVisitTime(ctx context.Context, visitTime time.Time) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, VisitTimeKey, visitTime) } // GetFromIP returns from IP from context func GetFromIP(ctx context.Context) string { if ctx == nil { return "" } if val, ok := ctx.Value(FromIPKey).(string); ok { return val } return "" } // SetFromIP sets from IP in context and returns new context func SetFromIP(ctx context.Context, fromIP string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, FromIPKey, fromIP) } // GetProvince returns province from context func GetProvince(ctx context.Context) string { if ctx == nil { return "" } if val, ok := ctx.Value(ProvinceKey).(string); ok { return val } return "" } // SetProvince sets province in context and returns new context func SetProvince(ctx context.Context, province string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, ProvinceKey, province) } // GetCity returns city from context func GetCity(ctx context.Context) string { if ctx == nil { return "" } if val, ok := ctx.Value(CityKey).(string); ok { return val } return "" } // SetCity sets city in context and returns new context func SetCity(ctx context.Context, city string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, CityKey, city) } // FromContext builds UserInfo from individual context fields // Returns nil if no fields are found func FromContext(ctx context.Context) *UserInfo { if ctx == nil { return nil } info := &UserInfo{} hasData := false if userID := GetUserID(ctx); userID != "" { info.UserID = userID hasData = true } if userName := GetUserName(ctx); userName != "" { info.UserName = userName hasData = true } if trace := GetTrace(ctx); trace != "" { info.Trace = trace hasData = true } if visitTime := GetVisitTime(ctx); !visitTime.IsZero() { info.VisitTime = visitTime hasData = true } if fromIP := GetFromIP(ctx); fromIP != "" { info.FromIP = fromIP hasData = true } if province := GetProvince(ctx); province != "" { info.Province = province hasData = true } if city := GetCity(ctx); city != "" { info.City = city hasData = true } if !hasData { return nil } return info } // ToContext sets all UserInfo fields to context and returns new context func ToContext(ctx context.Context, userInfo *UserInfo) context.Context { if ctx == nil { ctx = context.Background() } if userInfo == nil { return ctx } ctx = SetUserID(ctx, userInfo.UserID) ctx = SetUserName(ctx, userInfo.UserName) ctx = SetTrace(ctx, userInfo.Trace) ctx = SetVisitTime(ctx, userInfo.VisitTime) ctx = SetFromIP(ctx, userInfo.FromIP) ctx = SetProvince(ctx, userInfo.Province) ctx = SetCity(ctx, userInfo.City) return ctx } // NewUserInfo creates a new UserInfo instance func NewUserInfo() *UserInfo { return &UserInfo{ VisitTime: time.Now(), } } // WithUserID sets the user ID func (u *UserInfo) WithUserID(userID string) *UserInfo { u.UserID = userID return u } // WithUserName sets the user name func (u *UserInfo) WithUserName(userName string) *UserInfo { u.UserName = userName return u } // WithTrace sets the trace ID func (u *UserInfo) WithTrace(trace string) *UserInfo { u.Trace = trace return u } // WithFromIP sets the from IP address func (u *UserInfo) WithFromIP(ip string) *UserInfo { u.FromIP = ip return u } // WithVisitTime sets the visit time func (u *UserInfo) WithVisitTime(visitTime time.Time) *UserInfo { u.VisitTime = visitTime return u } // WithProvince sets the province func (u *UserInfo) WithProvince(province string) *UserInfo { u.Province = province return u } // WithCity sets the city func (u *UserInfo) WithCity(city string) *UserInfo { u.City = city return u }