2025-01-20 10:10:08 +08:00
|
|
|
package svc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2025-01-21 10:38:27 +08:00
|
|
|
"gitea.youtukeji.com.cn/xiabin/youtu_server/game_open_api/internal/config"
|
2025-01-24 18:36:46 +08:00
|
|
|
"gitea.youtukeji.com.cn/xiabin/youtu_server/game_open_api/internal/logic/rankings"
|
2025-01-21 10:38:27 +08:00
|
|
|
"gitea.youtukeji.com.cn/xiabin/youtu_server/game_open_api/model"
|
2025-01-21 16:48:55 +08:00
|
|
|
helper "gitea.youtukeji.com.cn/youtu/openapi-helper"
|
2025-01-24 10:00:03 +08:00
|
|
|
"github.com/golang-jwt/jwt/v4"
|
2025-01-24 18:36:46 +08:00
|
|
|
"github.com/redis/go-redis/v9"
|
2025-01-21 16:48:55 +08:00
|
|
|
redisCache "github.com/silenceper/wechat/v2/cache"
|
2025-01-20 10:10:08 +08:00
|
|
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
2025-01-23 18:39:48 +08:00
|
|
|
"go.uber.org/zap"
|
|
|
|
"go.uber.org/zap/zapcore"
|
|
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
2025-01-24 10:00:03 +08:00
|
|
|
"math/rand"
|
|
|
|
"time"
|
2025-01-20 10:10:08 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type ServiceContext struct {
|
2025-01-24 18:36:46 +08:00
|
|
|
Config config.Config
|
|
|
|
AppUser model.AppUserModel
|
|
|
|
GameScore model.GameScoreModel
|
|
|
|
AppAccount model.AppAccountModel
|
|
|
|
DouyinCli *helper.DouYinOpenApiClient
|
|
|
|
WechatCli *helper.WechatApi
|
|
|
|
ZapLogger *zap.Logger
|
|
|
|
RedisRanking *rankings.Ranking
|
2025-01-20 10:10:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewServiceContext(c config.Config) *ServiceContext {
|
2025-01-21 16:48:55 +08:00
|
|
|
svc := &ServiceContext{
|
2025-01-20 10:10:08 +08:00
|
|
|
Config: c,
|
|
|
|
AppUser: model.NewAppUserModel(sqlx.NewMysql(c.DB.DataSource), c.Cache),
|
|
|
|
GameScore: model.NewGameScoreModel(sqlx.NewMysql(c.DB.DataSource), c.Cache),
|
|
|
|
AppAccount: model.NewAppAccountModel(sqlx.NewMysql(c.DB.DataSource), c.Cache),
|
|
|
|
}
|
2025-01-21 16:48:55 +08:00
|
|
|
|
2025-01-24 18:36:46 +08:00
|
|
|
//初始化redis client
|
|
|
|
redisClient := redis.NewClient(&redis.Options{
|
|
|
|
Addr: c.DWCache.Host,
|
|
|
|
Password: c.DWCache.Password, // 没有密码,默认值
|
|
|
|
})
|
|
|
|
|
|
|
|
//初始化排行榜对象
|
|
|
|
svc.RedisRanking = rankings.NewRanking(redisClient)
|
|
|
|
|
2025-01-21 16:48:55 +08:00
|
|
|
dwCache := redisCache.NewRedis(context.Background(), &redisCache.RedisOpts{Host: c.DWCache.Host, IdleTimeout: c.DWCache.IdleTimeout})
|
|
|
|
|
|
|
|
svc.DouyinCli = helper.NewDouYinOpenApiClient()
|
|
|
|
svc.WechatCli = helper.NewWechatOpenApiClient()
|
2025-01-24 18:36:46 +08:00
|
|
|
|
|
|
|
//查询小程序配置(抖音&微信)
|
2025-01-21 16:48:55 +08:00
|
|
|
result, err := svc.AppAccount.FindAll(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2025-01-24 18:36:46 +08:00
|
|
|
//小程序配置
|
2025-01-21 16:48:55 +08:00
|
|
|
for _, v := range *result {
|
|
|
|
if v.Type == 0 {
|
|
|
|
svc.DouyinCli.NewAndStoreDouYinOpenApi(v.AppID, v.Secret, v.EcpmValue.V, v.EcpmView.V, dwCache)
|
|
|
|
} else {
|
|
|
|
svc.WechatCli.NewAndStoreWechatOpenApi(v.AppID, v.Secret, dwCache)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-24 18:36:46 +08:00
|
|
|
//获取所有排行榜
|
|
|
|
rankList, err := svc.GameScore.FindAllRankList(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//添加排行榜数据
|
|
|
|
for s, scores := range rankList {
|
2025-01-25 11:15:43 +08:00
|
|
|
data := make([]redis.Z, 0, len(scores))
|
2025-01-24 18:36:46 +08:00
|
|
|
for _, score := range scores {
|
|
|
|
data = append(data, redis.Z{
|
|
|
|
Score: float64(score.Score),
|
|
|
|
Member: score.AppUserId,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
svc.RedisRanking.SetList(context.Background(), s, data...)
|
|
|
|
}
|
|
|
|
|
2025-01-23 18:39:48 +08:00
|
|
|
//初始化一个zap日志对象用于写入ecpm日志
|
|
|
|
svc.ZapLogger = zap.New(zapcore.NewCore(
|
|
|
|
zapcore.NewJSONEncoder(zapcore.EncoderConfig{
|
|
|
|
TimeKey: "ts",
|
|
|
|
LevelKey: "level",
|
|
|
|
NameKey: "logger",
|
|
|
|
CallerKey: "caller",
|
|
|
|
FunctionKey: zapcore.OmitKey,
|
|
|
|
MessageKey: "msg",
|
|
|
|
StacktraceKey: "stacktrace",
|
|
|
|
LineEnding: zapcore.DefaultLineEnding,
|
|
|
|
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
|
|
|
EncodeTime: zapcore.EpochTimeEncoder,
|
|
|
|
EncodeDuration: zapcore.SecondsDurationEncoder,
|
|
|
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
|
|
|
}),
|
|
|
|
zapcore.NewMultiWriteSyncer(zapcore.AddSync(&lumberjack.Logger{
|
|
|
|
Filename: c.EcpmLogPath, // Log file path 日志文件的路径
|
|
|
|
MaxSize: 1024, // Maximum size unit for each log file: M 每个日志最大大小
|
|
|
|
MaxBackups: 30, // The maximum number of backups that can be saved for log files 可以保存的日志文件数量
|
|
|
|
MaxAge: 7, // Maximum number of days the file can be saved 日志文件保存的最大天数
|
|
|
|
Compress: true, // Compression or not 是否对日志文件进行压缩
|
|
|
|
})),
|
|
|
|
zapcore.InfoLevel,
|
|
|
|
))
|
|
|
|
|
2025-01-21 16:48:55 +08:00
|
|
|
return svc
|
2025-01-20 10:10:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type AccessToken struct {
|
|
|
|
AppId uint64 `json:"appId"`
|
|
|
|
UserId uint64 `json:"userId"`
|
|
|
|
AppIdStr string `json:"appIdStr"`
|
|
|
|
OpenId string `json:"openId"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func UnmarshalAccessToken(d any) (ac AccessToken, err error) {
|
|
|
|
m, ok := d.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
err = errors.New("invalid access token")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
appId, _ := m["appId"].(json.Number).Int64()
|
|
|
|
ac.AppId = uint64(appId)
|
|
|
|
userId, _ := m["userId"].(json.Number).Int64()
|
|
|
|
ac.UserId = uint64(userId)
|
|
|
|
ac.AppIdStr = m["appIdStr"].(string)
|
|
|
|
ac.OpenId = m["openId"].(string)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetCtxToken(ctx context.Context) (ac AccessToken, err error) {
|
|
|
|
return UnmarshalAccessToken(ctx.Value("payload"))
|
|
|
|
}
|
2025-01-24 10:00:03 +08:00
|
|
|
|
|
|
|
// GenerateAccessToken 生成 JWT 认证的 token
|
|
|
|
// 会从ServiceContext中获取配置信息
|
|
|
|
func (svc *ServiceContext) GenerateAccessToken(at *AccessToken) (token string, err error) {
|
|
|
|
claims := make(jwt.MapClaims)
|
|
|
|
claims["exp"] = time.Now().Unix() + svc.Config.Auth.AccessExpire
|
|
|
|
claims["iat"] = svc.Config.Auth.AccessExpire
|
|
|
|
claims["payload"] = at
|
|
|
|
|
|
|
|
t := jwt.New(jwt.SigningMethodHS256)
|
|
|
|
t.Claims = claims
|
|
|
|
token, err = t.SignedString([]byte(svc.Config.Auth.AccessSecret))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var DefaultUsername = []string{
|
|
|
|
"甜蜜糖果",
|
|
|
|
"糖果爱好者",
|
|
|
|
"软糖粉丝",
|
|
|
|
"巧克力糖果控",
|
|
|
|
"棒棒糖迷",
|
|
|
|
"小熊软糖达人",
|
|
|
|
"硬糖狂人",
|
|
|
|
"焦糖糖果控",
|
|
|
|
"水果糖行家",
|
|
|
|
"棉花糖达人",
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRandomUsername 随机获取一个糖果相关的用户名
|
|
|
|
func GetRandomUsername() string {
|
|
|
|
// 初始化随机数种子
|
|
|
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
|
// 生成一个 0 到列表长度减 1 之间的随机索引
|
|
|
|
randomIndex := r.Intn(len(DefaultUsername))
|
|
|
|
// 根据随机索引返回对应的用户名
|
|
|
|
return DefaultUsername[randomIndex]
|
|
|
|
}
|