实现游戏人生获取物品列表、兑换、领取奖品
This commit is contained in:
@ -108,19 +108,19 @@ func newGamelifeClient(ctx context.Context) *gamelifeClient {
|
||||
}
|
||||
|
||||
// GetUserKeyIV retrieves or refreshes the AES key, IV, and token for a user, storing them in cache.
|
||||
func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenID string) (model.UserGamelifeCache, error) {
|
||||
func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenID string) (*model.UserGamelifeCache, error) {
|
||||
oriData := map[string]string{
|
||||
"PlatId": s.config.PlatID,
|
||||
"PopenId": popenID,
|
||||
}
|
||||
marshaled, err := json.Marshal(oriData)
|
||||
if err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("序列化 json 数据出现异常")
|
||||
return nil, ecode.Fail.Sub("序列化 json 数据出现异常")
|
||||
}
|
||||
|
||||
encrypted, err := rsa.GetRsaClient().EncryptWithRsaPublicKey(marshaled)
|
||||
if err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("序列化 json 数据出现异常")
|
||||
return nil, ecode.Fail.Sub("序列化 json 数据出现异常")
|
||||
}
|
||||
|
||||
type httpResult struct {
|
||||
@ -136,17 +136,17 @@ func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenID string) (mode
|
||||
SetResult(&result).
|
||||
Post(s.keyIVURLMap[s.config.Mode])
|
||||
if err != nil || resp.StatusCode() != 200 {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("获取用户信息失败")
|
||||
return nil, ecode.Fail.Sub("获取用户信息失败")
|
||||
}
|
||||
|
||||
decoded, err := encrypt.Base64Decode(result.Secret)
|
||||
if err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("解密用户信息失败")
|
||||
return nil, ecode.Fail.Sub("解密用户信息失败")
|
||||
}
|
||||
|
||||
plain, err := rsa.GetRsaClient().DecryptWithRsaPrivateKey(decoded)
|
||||
if err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("解密用户信息失败")
|
||||
return nil, ecode.Fail.Sub("解密用户信息失败")
|
||||
}
|
||||
|
||||
var aesResult struct {
|
||||
@ -154,17 +154,17 @@ func (s *gamelifeClient) GetUserKeyIV(ctx context.Context, popenID string) (mode
|
||||
IV string `json:"iv"`
|
||||
}
|
||||
if err := json.Unmarshal(plain, &aesResult); err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("解密用户信息失败")
|
||||
return nil, ecode.Fail.Sub("解密用户信息失败")
|
||||
}
|
||||
|
||||
cache := model.UserGamelifeCache{
|
||||
cache := &model.UserGamelifeCache{
|
||||
Aes: aesResult.Key,
|
||||
IV: aesResult.IV,
|
||||
Token: result.Key,
|
||||
}
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, popenID)
|
||||
if err := g.Redis().SetEX(ctx, cacheKey, cache, int64(consts.GameLifeUserExpire+grand.Intn(1000))); err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("设置用户信息失败")
|
||||
return nil, ecode.Fail.Sub("设置用户信息失败")
|
||||
}
|
||||
|
||||
return cache, nil
|
||||
@ -178,33 +178,38 @@ func (s *gamelifeClient) GetUrl(ctx context.Context, popenID, appName, nickname
|
||||
if !isBound {
|
||||
rootURL = s.unBoundURLMap[s.config.Mode]
|
||||
}
|
||||
|
||||
cache, err := s.getOrRefreshCache(ctx, popenID)
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, popenID, appName, nickname, bindType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cache.Params, err = s.buildQueryParams(ctx, popenID, cache, appName, nickname, bindType, isBound)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, popenID)
|
||||
ttl, err := g.Redis().TTL(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return "", ecode.Fail.Sub("获取缓存过期时间失败")
|
||||
}
|
||||
if err := g.Redis().SetEX(ctx, cacheKey, cache, ttl); err != nil {
|
||||
return "", ecode.Fail.Sub("更新缓存失败")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s?%s", rootURL, cache.Params), nil
|
||||
}
|
||||
func (s *gamelifeClient) ensureUserCache(ctx context.Context, popenID string) (*model.UserGamelifeCache, error) {
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, popenID)
|
||||
cacheData, err := g.Redis().Get(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("从缓存中获取用户信息失败")
|
||||
}
|
||||
|
||||
var cache *model.UserGamelifeCache
|
||||
if cacheData.IsEmpty() {
|
||||
cache, err = s.GetUserKeyIV(ctx, popenID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := json.Unmarshal(cacheData.Bytes(), &cache); err != nil {
|
||||
return nil, ecode.Fail.Sub("解析用户信息失败")
|
||||
}
|
||||
}
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
// GetBound retrieves the binding status of a user from the GameLife system.
|
||||
// It uses buildQueryParams to construct the encrypted user data for the POST body.
|
||||
func (s *gamelifeClient) GetBound(ctx context.Context, popenID string) (*model.UserBoundResult, error) {
|
||||
cache, err := s.getOrRefreshCache(ctx, popenID)
|
||||
cache, err := s.ensureUserCache(ctx, popenID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -252,7 +257,7 @@ func (s *gamelifeClient) GetBound(ctx context.Context, popenID string) (*model.U
|
||||
|
||||
// buildQueryParams constructs URL query parameters for GameLife requests using cached AES, IV, and token.
|
||||
// It encrypts user data and encodes it into a URL query string.
|
||||
func (s *gamelifeClient) buildQueryParams(ctx context.Context, popenID string, cache model.UserGamelifeCache, appName, nickname string, bindType int, isBound bool) (string, error) {
|
||||
func (s *gamelifeClient) buildQueryParams(ctx context.Context, popenID string, cache *model.UserGamelifeCache, appName, nickname string, bindType int, isBound bool) (string, error) {
|
||||
oriData := map[string]interface{}{
|
||||
"PopenId": popenID,
|
||||
"TimeStamp": time.Now().Unix(),
|
||||
@ -310,31 +315,11 @@ func (s *gamelifeClient) RequestActivity(ctx context.Context, in *model.QQNetbar
|
||||
return &result, nil
|
||||
|
||||
case consts.GetTaskList:
|
||||
cache, err := s.getOrRefreshCache(ctx, in.PopenId)
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.QueryUserGoodsDetailParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, in.PopenId)
|
||||
if cache.Params == "" {
|
||||
// Reconstruct Params with default values
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.TaskParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取游戏名称失败")
|
||||
}
|
||||
|
||||
cache.Params, err = s.buildQueryParams(ctx, in.PopenId, cache, value.String(), "", in.BindType, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Update cache with new Params
|
||||
ttl, err := g.Redis().TTL(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取缓存过期时间失败")
|
||||
}
|
||||
if err := g.Redis().SetEX(ctx, cacheKey, cache, ttl); err != nil {
|
||||
return nil, ecode.Fail.Sub("更新缓存失败")
|
||||
}
|
||||
return nil, ecode.Fail.Sub("获取游戏编码失败")
|
||||
}
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, in.PopenId, value.String(), in.NickName, in.BindType)
|
||||
in.TaskParam.BrandId = s.config.BrandID
|
||||
var result model.GameTaskResponse
|
||||
resp, err := client.R().
|
||||
@ -347,31 +332,11 @@ func (s *gamelifeClient) RequestActivity(ctx context.Context, in *model.QQNetbar
|
||||
}
|
||||
return &result, nil
|
||||
case consts.QueryUserRoleList:
|
||||
cache, err := s.getOrRefreshCache(ctx, in.PopenId)
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.QueryUserGoodsDetailParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, in.PopenId)
|
||||
if cache.Params == "" {
|
||||
// Reconstruct Params with default values
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.UserRoleParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取游戏名称失败")
|
||||
}
|
||||
|
||||
cache.Params, err = s.buildQueryParams(ctx, in.PopenId, cache, value.String(), "", in.BindType, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Update cache with new Params
|
||||
ttl, err := g.Redis().TTL(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取缓存过期时间失败")
|
||||
}
|
||||
if err := g.Redis().SetEX(ctx, cacheKey, cache, ttl); err != nil {
|
||||
return nil, ecode.Fail.Sub("更新缓存失败")
|
||||
}
|
||||
return nil, ecode.Fail.Sub("获取游戏编码失败")
|
||||
}
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, in.PopenId, value.String(), in.NickName, in.BindType)
|
||||
var result model.UserRoleListResponse
|
||||
resp, err := client.R().
|
||||
SetContext(ctx).
|
||||
@ -382,26 +347,113 @@ func (s *gamelifeClient) RequestActivity(ctx context.Context, in *model.QQNetbar
|
||||
return nil, ecode.Fail.Sub("请求出现异常")
|
||||
}
|
||||
return &result.RoleList, nil
|
||||
|
||||
case consts.GetGift:
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.QueryUserGoodsDetailParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取游戏编码失败")
|
||||
}
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, in.PopenId, value.String(), in.NickName, in.BindType)
|
||||
var result model.GiftResponse
|
||||
resp, err := client.R().
|
||||
SetContext(ctx).
|
||||
SetBody(in.GiftParam).
|
||||
SetResult(&result).
|
||||
Post(fmt.Sprintf("%s%s?%s", taskURL, consts.GetGift, cache.Params))
|
||||
if err != nil || resp.IsError() {
|
||||
return nil, ecode.Fail.Sub("请求出现异常")
|
||||
}
|
||||
return &result, nil
|
||||
case consts.GetUserGoodsList:
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.QueryUserGoodsDetailParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取游戏编码失败")
|
||||
}
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, in.PopenId, value.String(), in.NickName, in.BindType)
|
||||
var result model.GoodsResponse
|
||||
resp, err := client.R().
|
||||
SetContext(ctx).
|
||||
SetBody(in.GoodsParam).
|
||||
SetResult(&result).
|
||||
Post(fmt.Sprintf("%s%s?%s", taskURL, consts.GetUserGoodsList, cache.Params))
|
||||
if err != nil || resp.IsError() {
|
||||
return nil, ecode.Fail.Sub("请求出现异常")
|
||||
}
|
||||
return &result, nil
|
||||
case consts.ExchangeGoods:
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.QueryUserGoodsDetailParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取游戏编码失败")
|
||||
}
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, in.PopenId, value.String(), in.NickName, in.BindType)
|
||||
var result model.ExchangeGoodsResponse
|
||||
resp, err := client.R().
|
||||
SetContext(ctx).
|
||||
SetBody(in.ExchangeGoodsParam).
|
||||
SetResult(&result).
|
||||
Post(fmt.Sprintf("%s%s?%s", taskURL, consts.ExchangeGoods, cache.Params))
|
||||
if err != nil || resp.IsError() {
|
||||
return nil, ecode.Fail.Sub("请求出现异常")
|
||||
}
|
||||
return &result, nil
|
||||
case consts.QueryUserGoodsDetail:
|
||||
value, err := dao.Games.Ctx(ctx).Where(do.Games{GameId: in.QueryUserGoodsDetailParam.Gid}).Fields(dao.Games.Columns().GameCode).Value()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取游戏编码失败")
|
||||
}
|
||||
cache, err := s.ensureUserCacheWithParams(ctx, in.PopenId, value.String(), in.NickName, in.BindType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result model.QueryUserGoodsDetailResponse
|
||||
resp, err := client.R().
|
||||
SetContext(ctx).
|
||||
SetBody(in.QueryUserGoodsDetailParam).
|
||||
SetResult(&result).
|
||||
Post(fmt.Sprintf("%s%s?%s", taskURL, consts.QueryUserGoodsDetail, cache.Params))
|
||||
if err != nil || resp.IsError() {
|
||||
return nil, ecode.Fail.Sub("请求出现异常")
|
||||
}
|
||||
return &result, nil
|
||||
default:
|
||||
return nil, ecode.Fail.Sub(fmt.Sprintf("不支持的任务: %s", in.ServiceName))
|
||||
}
|
||||
}
|
||||
|
||||
// getOrRefreshCache retrieves user cache or refreshes it if expired.
|
||||
func (s *gamelifeClient) getOrRefreshCache(ctx context.Context, popenID string) (model.UserGamelifeCache, error) {
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, popenID)
|
||||
// ensureUserCacheWithParams ensures user cache exists and contains a valid Params string.
|
||||
// It handles cache retrieval, fallback refresh, Params generation, and cache update.
|
||||
func (s *gamelifeClient) ensureUserCacheWithParams(ctx context.Context, popenId, appname, nickname string, bindType int) (*model.UserGamelifeCache, error) {
|
||||
cacheKey := fmt.Sprintf(consts.GameLifeUserKey, popenId)
|
||||
cacheData, err := g.Redis().Get(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("从缓存中获取用户信息失败")
|
||||
return nil, ecode.Fail.Sub("从缓存中获取用户信息失败")
|
||||
}
|
||||
|
||||
var cache model.UserGamelifeCache
|
||||
var cache *model.UserGamelifeCache
|
||||
if cacheData.IsEmpty() {
|
||||
return s.GetUserKeyIV(ctx, popenID)
|
||||
cache, err = s.GetUserKeyIV(ctx, popenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := json.Unmarshal(cacheData.Bytes(), &cache); err != nil {
|
||||
return nil, ecode.Fail.Sub("解析用户信息失败")
|
||||
}
|
||||
}
|
||||
if err := json.Unmarshal(cacheData.Bytes(), &cache); err != nil {
|
||||
return model.UserGamelifeCache{}, ecode.Fail.Sub("解析用户信息失败")
|
||||
|
||||
if cache.Params == "" {
|
||||
cache.Params, err = s.buildQueryParams(ctx, popenId, cache, appname, nickname, bindType, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ttl, err := g.Redis().TTL(ctx, cacheKey)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("获取缓存过期时间失败")
|
||||
}
|
||||
if err := g.Redis().SetEX(ctx, cacheKey, cache, ttl); err != nil {
|
||||
return nil, ecode.Fail.Sub("更新缓存失败")
|
||||
}
|
||||
}
|
||||
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user