package client import ( "context" "errors" "fmt" "github.com/topfans/backend/pkg/logger" pbCommon "github.com/topfans/backend/pkg/proto/common" pbUser "github.com/topfans/backend/pkg/proto/user" "go.uber.org/zap" ) // FanProfile 粉丝档案信息 type FanProfile struct { ID int64 UserID int64 StarID int64 Nickname string Level int32 CrystalBalance int64 } // UserRPCClient User Service RPC客户端接口 type UserRPCClient interface { // GetFanProfile 获取粉丝档案(等级、水晶余额等) GetFanProfile(userID, starID int64) (*FanProfile, error) // UpdateCrystalBalance 更新水晶余额(返回更新后的余额) // changeType: 变化类型,如 task_reward/mint_cost/mint_reward/exhibition_revenue/level_up_bonus/manual_adjust // sourceID: 关联业务ID // description: 可读描述 UpdateCrystalBalance(userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error) // AddExhibitionHours 增加用户累计上架时长 // sourceID: 关联业务ID,用于升级奖励流水的溯源 // 返回: newLevel, levelDelta, crystalReward, error AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) } // userRPCClient User Service RPC客户端实现 type userRPCClient struct { client pbUser.UserSocialService } // NewUserRPCClient 创建User Service RPC客户端 func NewUserRPCClient(client pbUser.UserSocialService) UserRPCClient { return &userRPCClient{ client: client, } } // GetFanProfile 获取粉丝档案(等级、水晶余额等) func (c *userRPCClient) GetFanProfile(userID, starID int64) (*FanProfile, error) { logger.Logger.Debug("Calling UserService.GetFanProfile", zap.Int64("user_id", userID), zap.Int64("star_id", starID), ) ctx := context.Background() resp, err := c.client.GetFanProfile(ctx, &pbUser.GetFanProfileRequest{ UserId: userID, StarId: starID, }) if err != nil { logger.Logger.Error("Failed to call UserService.GetFanProfile", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err), ) return nil, err } // StatusCode_STATUS_OK = 200,不是 0 if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { errorMsg := resp.Base.Message if errorMsg == "" { errorMsg = fmt.Sprintf("UserService返回错误码: %d", resp.Base.Code) } logger.Logger.Warn("UserService.GetFanProfile returned error", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("code", int32(resp.Base.Code)), zap.String("message", errorMsg), ) return nil, errors.New(errorMsg) } logger.Logger.Debug("UserService.GetFanProfile successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("level", resp.Profile.Level), zap.Int64("crystal_balance", resp.Profile.CrystalBalance), ) return &FanProfile{ ID: resp.Profile.Id, UserID: resp.Profile.UserId, StarID: resp.Profile.StarId, Nickname: resp.Profile.Nickname, Level: resp.Profile.Level, CrystalBalance: resp.Profile.CrystalBalance, }, nil } // UpdateCrystalBalance 更新水晶余额(返回更新后的余额) func (c *userRPCClient) UpdateCrystalBalance(userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error) { logger.Logger.Debug("Calling UserService.UpdateCrystalBalance", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("delta", delta), zap.String("change_type", changeType), ) ctx := context.Background() resp, err := c.client.UpdateCrystalBalance(ctx, &pbUser.UpdateCrystalBalanceRequest{ UserId: userID, StarId: starID, Delta: delta, ChangeType: changeType, SourceId: sourceID, Description: description, }) if err != nil { logger.Logger.Error("Failed to call UserService.UpdateCrystalBalance", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("delta", delta), zap.Error(err), ) return 0, err } // StatusCode_STATUS_OK = 200,不是 0 if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { errorMsg := resp.Base.Message if errorMsg == "" { errorMsg = fmt.Sprintf("UserService返回错误码: %d", resp.Base.Code) } logger.Logger.Warn("UserService.UpdateCrystalBalance returned error", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("code", int32(resp.Base.Code)), zap.String("message", errorMsg), ) return 0, errors.New(errorMsg) } logger.Logger.Debug("UserService.UpdateCrystalBalance successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("new_balance", resp.NewBalance), ) return resp.NewBalance, nil } // AddExhibitionHours 增加用户累计上架时长 // sourceID: 关联业务ID,用于升级奖励流水的溯源(本参数暂未透传到RPC,仅Go层保留) func (c *userRPCClient) AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) { logger.Logger.Debug("Calling UserService.AddExhibitionHours", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("hours", hours), ) ctx := context.Background() resp, err := c.client.AddExhibitionHours(ctx, &pbUser.AddExhibitionHoursRequest{ UserId: userID, StarId: starID, ExhibitionHours: hours, SourceId: sourceID, }) if err != nil { logger.Logger.Error("Failed to call UserService.AddExhibitionHours", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("hours", hours), zap.Error(err), ) return 0, 0, 0, err } if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { errorMsg := resp.Base.Message if errorMsg == "" { errorMsg = fmt.Sprintf("UserService返回错误码: %d", resp.Base.Code) } logger.Logger.Warn("UserService.AddExhibitionHours returned error", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int32("code", int32(resp.Base.Code)), zap.String("message", errorMsg), ) return 0, 0, 0, errors.New(errorMsg) } logger.Logger.Debug("UserService.AddExhibitionHours successful", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("hours", hours), zap.Int32("new_level", resp.NewLevel), zap.Int32("level_delta", resp.LevelDelta), zap.Int64("crystal_reward", resp.CrystalReward), ) return resp.NewLevel, resp.LevelDelta, resp.CrystalReward, nil }