package provider import ( "context" "fmt" "dubbo.apache.org/dubbo-go/v3/common/constant" appErrors "github.com/topfans/backend/pkg/errors" "github.com/topfans/backend/pkg/logger" pbCommon "github.com/topfans/backend/pkg/proto/common" pb "github.com/topfans/backend/pkg/proto/user" "github.com/topfans/backend/services/userService/service" "go.uber.org/zap" ) // UserProvider 用户信息Provider实现 type UserProvider struct { userService service.UserService identityService service.IdentityService } // NewUserProvider 创建用户信息Provider实例 func NewUserProvider(userService service.UserService, identityService service.IdentityService) *UserProvider { return &UserProvider{ userService: userService, identityService: identityService, } } // GetUser 获取用户信息 func (p *UserProvider) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) { // 记录请求日志 logger.Logger.Info("Received GetUser request", zap.Int64("user_id", req.UserId), ) // 调用Service层 resp, err := p.userService.GetUser(req) if err != nil { logger.Logger.Error("GetUser failed", zap.Int64("user_id", req.UserId), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.GetUserResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Debug("GetUser successful", zap.Int64("user_id", req.UserId), ) return resp, nil } // GetFanProfile 获取粉丝档案 func (p *UserProvider) GetFanProfile(ctx context.Context, req *pb.GetFanProfileRequest) (*pb.GetFanProfileResponse, error) { // 记录请求日志 logger.Logger.Info("Received GetFanProfile request", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), ) // 调用Service层 resp, err := p.userService.GetFanProfile(req) if err != nil { logger.Logger.Error("GetFanProfile failed", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.GetFanProfileResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Debug("GetFanProfile successful", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), ) return resp, nil } // GetCurrentUser 获取当前登录用户信息 // 假设:Gin 网关已经验证 Token,并通过 Dubbo attachments 传递 user_id 和 star_id func (p *UserProvider) GetCurrentUser(ctx context.Context, req *pb.GetCurrentUserRequest) (*pb.GetCurrentUserResponse, error) { // 记录请求日志 logger.Logger.Info("Received GetCurrentUser request") // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, starID, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.GetCurrentUserResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } logger.Logger.Debug("User info extracted from Dubbo attachments", zap.Int64("user_id", userID), zap.Int64("star_id", starID), ) // 调用Service层的GetMyProfile(使用GetMyProfileRequest) myProfileReq := &pb.GetMyProfileRequest{} resp, err := p.userService.GetMyProfile(myProfileReq, userID, starID) if err != nil { logger.Logger.Error("GetCurrentUser failed", zap.Int64("user_id", userID), zap.Error(err), ) return &pb.GetCurrentUserResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, }, err } // 转换为GetCurrentUserResponse格式 currentUserResp := &pb.GetCurrentUserResponse{ Base: resp.Base, User: resp.User, FanProfile: resp.FanProfile, FanProfiles: resp.FanProfiles, } logger.Logger.Debug("GetCurrentUser successful", zap.Int64("user_id", userID), ) return currentUserResp, nil } // GetMyProfile 获取个人信息页 func (p *UserProvider) GetMyProfile(ctx context.Context, req *pb.GetMyProfileRequest) (*pb.GetMyProfileResponse, error) { // 记录请求日志 logger.Logger.Info("Received GetMyProfile request") // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, starID, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.GetMyProfileResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 调用Service层 resp, err := p.userService.GetMyProfile(req, userID, starID) if err != nil { logger.Logger.Error("GetMyProfile failed", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.GetMyProfileResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Debug("GetMyProfile successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), ) return resp, nil } // CheckNickname 检查昵称是否已被注册 func (p *UserProvider) CheckNickname(ctx context.Context, req *pb.CheckNicknameRequest) (*pb.CheckNicknameResponse, error) { // 记录请求日志 logger.Logger.Info("Received CheckNickname request", zap.String("nickname", req.Nickname), ) // 调用Service层 resp, err := p.userService.CheckNickname(req) if err != nil { logger.Logger.Error("CheckNickname failed", zap.String("nickname", req.Nickname), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.CheckNicknameResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("CheckNickname successful", zap.String("nickname", req.Nickname), zap.Bool("exists", resp.Exists), ) return resp, nil } // CheckMobile 检查手机号是否已被注册 func (p *UserProvider) CheckMobile(ctx context.Context, req *pb.CheckMobileRequest) (*pb.CheckMobileResponse, error) { // 记录请求日志 logger.Logger.Info("Received CheckMobile request", zap.String("mobile", req.Mobile), ) // 调用Service层 resp, err := p.userService.CheckMobile(req) if err != nil { logger.Logger.Error("CheckMobile failed", zap.String("mobile", req.Mobile), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.CheckMobileResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("CheckMobile successful", zap.String("mobile", req.Mobile), zap.Bool("exists", resp.Exists), ) return resp, nil } // UpdateNickname 修改昵称 func (p *UserProvider) UpdateNickname(ctx context.Context, req *pb.UpdateNicknameRequest) (*pb.UpdateNicknameResponse, error) { // 记录请求日志 logger.Logger.Info("Received UpdateNickname request") // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, starID, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.UpdateNicknameResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 调用Service层 resp, err := p.userService.UpdateNickname(req, userID, starID) if err != nil { logger.Logger.Error("UpdateNickname failed", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.UpdateNicknameResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("UpdateNickname successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.String("new_nickname", req.Nickname), ) return resp, nil } // UpdatePassword 修改密码 func (p *UserProvider) UpdatePassword(ctx context.Context, req *pb.UpdatePasswordRequest) (*pb.UpdatePasswordResponse, error) { // 记录请求日志 logger.Logger.Info("Received UpdatePassword request") // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, _, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.UpdatePasswordResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 调用Service层 resp, err := p.userService.UpdatePassword(req, userID) if err != nil { logger.Logger.Error("UpdatePassword failed", zap.Int64("user_id", userID), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.UpdatePasswordResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("UpdatePassword successful", zap.Int64("user_id", userID), ) return resp, nil } // UpdateAvatar 更新用户头像 func (p *UserProvider) UpdateAvatar(ctx context.Context, req *pb.UpdateAvatarRequest) (*pb.UpdateAvatarResponse, error) { // 记录请求日志 logger.Logger.Info("Received UpdateAvatar request") // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, starID, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.UpdateAvatarResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 调用Service层 resp, err := p.userService.UpdateAvatar(req, userID, starID) if err != nil { logger.Logger.Error("UpdateAvatar failed", zap.Int64("user_id", userID), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.UpdateAvatarResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("UpdateAvatar successful", zap.Int64("user_id", userID), zap.String("avatar_url", req.AvatarUrl), ) return resp, nil } // GetFanIdentities 获取可选粉丝身份列表 func (p *UserProvider) GetFanIdentities(ctx context.Context, req *pb.GetFanIdentitiesRequest) (*pb.GetFanIdentitiesResponse, error) { // 记录请求日志 logger.Logger.Info("Received GetFanIdentities request", zap.String("keyword", req.Keyword), ) // 调用Service层 resp, err := p.identityService.GetFanIdentities(req) if err != nil { logger.Logger.Error("GetFanIdentities failed", zap.String("keyword", req.Keyword), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.GetFanIdentitiesResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Debug("GetFanIdentities successful", zap.String("keyword", req.Keyword), zap.Int("count", len(resp.Stars)), ) return resp, nil } // GetMyFanIdentities 获取我的粉丝身份列表 func (p *UserProvider) GetMyFanIdentities(ctx context.Context, req *pb.GetMyFanIdentitiesRequest) (*pb.GetMyFanIdentitiesResponse, error) { // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, starID, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.GetMyFanIdentitiesResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 记录请求日志 logger.Logger.Info("Received GetMyFanIdentities request", zap.Int64("user_id", userID), zap.Int64("star_id", starID), ) // 调用Service层 resp, err := p.identityService.GetMyFanIdentities(userID, starID) if err != nil { logger.Logger.Error("GetMyFanIdentities failed", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.GetMyFanIdentitiesResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Debug("GetMyFanIdentities successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int("count", len(resp.Items)), ) return resp, nil } // AddIdentity 新增粉丝身份 func (p *UserProvider) AddIdentity(ctx context.Context, req *pb.AddIdentityRequest) (*pb.AddIdentityResponse, error) { // 记录请求日志 logger.Logger.Info("Received AddIdentity request", zap.Int64("star_id", req.StarId), zap.String("nickname", req.Nickname), ) // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, _, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.AddIdentityResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 调用Service层 resp, err := p.identityService.AddIdentity(req, userID) if err != nil { logger.Logger.Error("AddIdentity failed", zap.Int64("user_id", userID), zap.Int64("star_id", req.StarId), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.AddIdentityResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("AddIdentity successful", zap.Int64("user_id", userID), zap.Int64("star_id", req.StarId), ) return resp, nil } // SwitchIdentity 切换粉丝身份 func (p *UserProvider) SwitchIdentity(ctx context.Context, req *pb.SwitchIdentityRequest) (*pb.SwitchIdentityResponse, error) { // 记录请求日志 logger.Logger.Info("Received SwitchIdentity request", zap.Int64("new_star_id", req.NewStarId), ) // 从 Dubbo attachments 获取用户信息(网关已验证并传递) userID, currentStarID, err := extractUserInfoFromDubboAttachments(ctx) if err != nil { logger.Logger.Error("Failed to extract user info from attachments", zap.Error(err), ) return &pb.SwitchIdentityResponse{ Base: &pbCommon.BaseResponse{ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, Message: "user authentication required", Timestamp: 0, }, }, err } // 调用Service层 resp, err := p.identityService.SwitchIdentity(req, userID, currentStarID) if err != nil { logger.Logger.Error("SwitchIdentity failed", zap.Int64("user_id", userID), zap.Int64("current_star_id", currentStarID), zap.Int64("new_star_id", req.NewStarId), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.SwitchIdentityResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("SwitchIdentity successful", zap.Int64("user_id", userID), zap.Int64("current_star_id", currentStarID), zap.Int64("new_star_id", req.NewStarId), ) return resp, nil } // extractUserInfoFromDubboAttachments 从 Dubbo attachments 中提取用户信息 // 网关调用:网关已验证 Token 并将 user_id 和 star_id 通过 attachments 传递 // 直接调用:可以通过 grpcurl -rpc-header 传递 user_id 和 star_id 进行测试 func extractUserInfoFromDubboAttachments(ctx context.Context) (int64, int64, error) { logger.Logger.Info("Extracting user info from Dubbo attachments") // 使用正确的 constant.AttachmentKey 获取 Dubbo attachments if attachments := ctx.Value(constant.AttachmentKey); attachments != nil { logger.Logger.Info("Found attachments in context", zap.Any("attachments", attachments), zap.String("key", fmt.Sprintf("%v", constant.AttachmentKey)), ) if attMap, ok := attachments.(map[string]interface{}); ok { logger.Logger.Info("Attachments is a map", zap.Any("map", attMap)) userID, starID := extractUserInfoFromMap(attMap) if userID > 0 && starID > 0 { logger.Logger.Info("Successfully extracted user info", zap.Int64("user_id", userID), zap.Int64("star_id", starID), ) return userID, starID, nil } else { logger.Logger.Warn("Extracted zero user_id or star_id", zap.Int64("user_id", userID), zap.Int64("star_id", starID), ) } } else { logger.Logger.Warn("Attachments is not a map[string]interface{}", zap.String("type", fmt.Sprintf("%T", attachments)), ) } } else { logger.Logger.Warn("No attachments found in context", zap.String("key", fmt.Sprintf("%v", constant.AttachmentKey)), ) } logger.Logger.Error("Failed to extract user info from Dubbo attachments") return 0, 0, fmt.Errorf("user info not found in Dubbo attachments (expected user_id and star_id from gateway)") } // extractUserInfoFromMap 从 map 中提取 user_id 和 star_id // 支持多种类型:int64, float64, string, []string, []interface{} func extractUserInfoFromMap(attMap map[string]interface{}) (int64, int64) { var userID, starID int64 // 提取 user_id if v, ok := attMap["user_id"]; ok { userID = parseIntValue(v) } // 提取 star_id if v, ok := attMap["star_id"]; ok { starID = parseIntValue(v) } return userID, starID } // parseIntValue 解析各种类型的值为 int64 func parseIntValue(v interface{}) int64 { switch val := v.(type) { case int64: return val case int: return int64(val) case float64: return int64(val) case string: var result int64 fmt.Sscanf(val, "%d", &result) return result case []string: if len(val) > 0 { var result int64 fmt.Sscanf(val[0], "%d", &result) return result } case []interface{}: if len(val) > 0 { return parseIntValue(val[0]) } } return 0 } // UpdateFanProfileSocial 更新粉丝档案的好友数量(内部RPC调用) func (p *UserProvider) UpdateFanProfileSocial(ctx context.Context, req *pb.UpdateFanProfileSocialRequest) (*pb.UpdateFanProfileSocialResponse, error) { logger.Logger.Info("Received UpdateFanProfileSocial request", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int32("delta", req.Delta), ) // 调用Service层 resp, err := p.userService.UpdateFanProfileSocial(req) if err != nil { logger.Logger.Error("UpdateFanProfileSocial failed", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int32("delta", req.Delta), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.UpdateFanProfileSocialResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("UpdateFanProfileSocial successful", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int32("delta", req.Delta), zap.Int32("new_social", resp.NewSocial), ) return resp, nil } // UpdateCrystalBalance 更新水晶余额(内部RPC调用) func (p *UserProvider) UpdateCrystalBalance(ctx context.Context, req *pb.UpdateCrystalBalanceRequest) (*pb.UpdateCrystalBalanceResponse, error) { logger.Logger.Info("Received UpdateCrystalBalance request", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int64("delta", req.Delta), ) // 调用Service层 resp, err := p.userService.UpdateCrystalBalance(req) if err != nil { logger.Logger.Error("UpdateCrystalBalance failed", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int64("delta", req.Delta), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.UpdateCrystalBalanceResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("UpdateCrystalBalance successful", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int64("delta", req.Delta), zap.Int64("new_balance", resp.NewBalance), ) return resp, nil } // UpdateAssetsCount 更新资产数量(内部RPC调用) func (p *UserProvider) UpdateAssetsCount(ctx context.Context, req *pb.UpdateAssetsCountRequest) (*pb.UpdateAssetsCountResponse, error) { logger.Logger.Info("Received UpdateAssetsCount request", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int32("delta", req.Delta), ) // 调用Service层 resp, err := p.userService.UpdateAssetsCount(req) if err != nil { logger.Logger.Error("UpdateAssetsCount failed", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int32("delta", req.Delta), zap.Error(err), ) // 如果响应为空,构建错误响应 if resp == nil { resp = &pb.UpdateAssetsCountResponse{ Base: &pbCommon.BaseResponse{ Code: appErrors.ToStatusCode(err), Message: err.Error(), Timestamp: 0, }, } } return resp, err } logger.Logger.Info("UpdateAssetsCount successful", zap.Int64("user_id", req.UserId), zap.Int64("star_id", req.StarId), zap.Int32("delta", req.Delta), zap.Int32("new_count", resp.NewCount), ) return resp, nil }