package service import ( "context" "fmt" "github.com/topfans/backend/pkg/logger" pbCommon "github.com/topfans/backend/pkg/proto/common" pb "github.com/topfans/backend/pkg/proto/user" "go.uber.org/zap" ) // UserInfo 用户信息(简化版,用于好友列表展示) type UserInfo struct { UserID int64 Nickname string Avatar string FanLevel int32 Social int32 // 好友数量 } // UserServiceClient 用户服务RPC客户端接口 type UserServiceClient interface { // ValidateUser 验证用户是否存在 ValidateUser(ctx context.Context, userID int64) (bool, error) // ValidateFanProfile 验证粉丝档案是否存在 ValidateFanProfile(ctx context.Context, userID, starID int64) (bool, error) // GetUsersByIDs 批量查询用户信息和粉丝档案 // 返回 map[userID]UserInfo GetUsersByIDs(ctx context.Context, userIDs []int64, starID int64) (map[int64]*UserInfo, error) // UpdateFanProfileSocial 更新粉丝档案的social字段(好友数量) UpdateFanProfileSocial(ctx context.Context, userID, starID int64, delta int32) error } // userServiceClient 用户服务RPC客户端实现 type userServiceClient struct { client pb.UserSocialService } // NewUserServiceClient 创建用户服务RPC客户端 func NewUserServiceClient(client pb.UserSocialService) UserServiceClient { return &userServiceClient{ client: client, } } // ValidateUser 验证用户是否存在 func (c *userServiceClient) ValidateUser(ctx context.Context, userID int64) (bool, error) { // 调用userService的GetUser接口 resp, err := c.client.GetUser(ctx, &pb.GetUserRequest{ UserId: userID, }) if err != nil { logger.Logger.Error("Failed to validate user via RPC", zap.Int64("user_id", userID), zap.Error(err), ) return false, fmt.Errorf("RPC调用失败: %w", err) } // 检查响应 if resp.Base == nil || resp.Base.Code != pbCommon.StatusCode_STATUS_OK { logger.Logger.Warn("User validation failed", zap.Int64("user_id", userID), zap.Int32("code", int32(resp.Base.Code)), ) return false, nil } return resp.User != nil && resp.User.IsActive, nil } // ValidateFanProfile 验证粉丝档案是否存在 func (c *userServiceClient) ValidateFanProfile(ctx context.Context, userID, starID int64) (bool, error) { // 调用userService的GetFanProfile接口 resp, err := c.client.GetFanProfile(ctx, &pb.GetFanProfileRequest{ UserId: userID, StarId: starID, }) if err != nil { logger.Logger.Error("Failed to validate fan profile via RPC", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err), ) return false, fmt.Errorf("RPC调用失败: %w", err) } // 检查响应 if resp.Base == nil || resp.Base.Code != pbCommon.StatusCode_STATUS_OK { logger.Logger.Warn("Fan profile validation failed", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("code", int32(resp.Base.Code)), ) return false, nil } // FanProfile 不需要检查 IsActive,只要存在就是有效的 return resp.Profile != nil, nil } // GetUsersByIDs 批量查询用户信息和粉丝档案 func (c *userServiceClient) GetUsersByIDs(ctx context.Context, userIDs []int64, starID int64) (map[int64]*UserInfo, error) { if len(userIDs) == 0 { return make(map[int64]*UserInfo), nil } // 去重 uniqueIDs := make(map[int64]bool) for _, id := range userIDs { uniqueIDs[id] = true } // 批量查询 result := make(map[int64]*UserInfo) // TODO: 优化为真正的批量查询接口 // 目前userService没有批量查询接口,需要逐个查询 // 后续可以在userService中添加BatchGetUsers和BatchGetFanProfiles接口 for userID := range uniqueIDs { // 获取粉丝档案信息(包含昵称和头像) profileResp, err := c.client.GetFanProfile(ctx, &pb.GetFanProfileRequest{ UserId: userID, StarId: starID, }) if err != nil || profileResp.Base == nil || profileResp.Base.Code != pbCommon.StatusCode_STATUS_OK || profileResp.Profile == nil { logger.Logger.Warn("Failed to get fan profile", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err), ) continue } // 合并信息 result[userID] = &UserInfo{ UserID: userID, Nickname: profileResp.Profile.Nickname, Avatar: profileResp.Profile.AvatarUrl, // 从 FanProfile 获取头像 FanLevel: profileResp.Profile.Level, Social: profileResp.Profile.Social, } } return result, nil } // UpdateFanProfileSocial 更新粉丝档案的social字段(好友数量) func (c *userServiceClient) UpdateFanProfileSocial(ctx context.Context, userID, starID int64, delta int32) error { // 调用userService的UpdateFanProfileSocial接口 resp, err := c.client.UpdateFanProfileSocial(ctx, &pb.UpdateFanProfileSocialRequest{ UserId: userID, StarId: starID, Delta: delta, }) if err != nil { logger.Logger.Error("Failed to update fan profile social via RPC", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("delta", delta), zap.Error(err), ) return fmt.Errorf("RPC调用失败: %w", err) } // 检查响应 if resp.Base == nil || resp.Base.Code != 0 { logger.Logger.Warn("Update fan profile social failed", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("delta", delta), zap.Int32("code", int32(resp.Base.Code)), ) return fmt.Errorf("更新好友数量失败: %s", resp.Base.Message) } logger.Logger.Info("Update fan profile social successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("delta", delta), zap.Int32("new_social", resp.NewSocial), ) return nil } // ========== Mock实现(用于测试) ========== // MockUserServiceClient Mock的用户服务RPC客户端(用于测试) type MockUserServiceClient struct { ValidUsers map[int64]bool // 有效的用户ID ValidFanProfile map[string]bool // 有效的粉丝档案(key: "userID_starID") UserInfos map[int64]*UserInfo // 用户信息 } // NewMockUserServiceClient 创建Mock客户端 func NewMockUserServiceClient() *MockUserServiceClient { return &MockUserServiceClient{ ValidUsers: make(map[int64]bool), ValidFanProfile: make(map[string]bool), UserInfos: make(map[int64]*UserInfo), } } // ValidateUser Mock实现 func (m *MockUserServiceClient) ValidateUser(ctx context.Context, userID int64) (bool, error) { return m.ValidUsers[userID], nil } // ValidateFanProfile Mock实现 func (m *MockUserServiceClient) ValidateFanProfile(ctx context.Context, userID, starID int64) (bool, error) { key := fmt.Sprintf("%d_%d", userID, starID) return m.ValidFanProfile[key], nil } // GetUsersByIDs Mock实现 func (m *MockUserServiceClient) GetUsersByIDs(ctx context.Context, userIDs []int64, starID int64) (map[int64]*UserInfo, error) { result := make(map[int64]*UserInfo) for _, userID := range userIDs { if info, ok := m.UserInfos[userID]; ok { result[userID] = info } } return result, nil } // UpdateFanProfileSocial Mock实现 func (m *MockUserServiceClient) UpdateFanProfileSocial(ctx context.Context, userID, starID int64, delta int32) error { // Mock实现:直接返回成功 return nil } // AddMockUser 添加Mock用户 func (m *MockUserServiceClient) AddMockUser(userID int64, nickname, avatar string, fanLevel, social int32) { m.ValidUsers[userID] = true m.UserInfos[userID] = &UserInfo{ UserID: userID, Nickname: nickname, Avatar: avatar, FanLevel: fanLevel, Social: social, } } // AddMockFanProfile 添加Mock粉丝档案 func (m *MockUserServiceClient) AddMockFanProfile(userID, starID int64) { key := fmt.Sprintf("%d_%d", userID, starID) m.ValidFanProfile[key] = true }