feat(cron): 添加角色配装信息刷新任务并优化神器数据同步功能
- 新增每5天执行一次的角色配装信息刷新任务 - 重构神器数据同步功能,优化数据处理和保存逻辑- 添加神器图片URL获取和上传逻辑 - 更新相关测试用例
This commit is contained in:
@@ -31,7 +31,7 @@ var (
|
|||||||
|
|
||||||
// 启动定时任务
|
// 启动定时任务
|
||||||
if err := service.Cron().StartAllJobs(ctx); err != nil {
|
if err := service.Cron().StartAllJobs(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "Failed to start cron jobs:", err)
|
util.Error(ctx, "Failed to start cron jobs:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ func setupGracefulShutdown(ctx context.Context) {
|
|||||||
|
|
||||||
// 停止定时任务
|
// 停止定时任务
|
||||||
if err := service.Cron().StopAllJobs(ctx); err != nil {
|
if err := service.Cron().StopAllJobs(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "Failed to stop cron jobs:", err)
|
util.Error(ctx, "Failed to stop cron jobs:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 退出程序
|
// 退出程序
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"epic/internal/service"
|
"epic/internal/service"
|
||||||
"epic/internal/util"
|
"epic/internal/util"
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
"github.com/gogf/gf/v2/errors/gerror"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
"github.com/gogf/gf/v2/os/gcron"
|
"github.com/gogf/gf/v2/os/gcron"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -37,7 +36,7 @@ func init() {
|
|||||||
|
|
||||||
// StartAllJobs 启动所有定时任务
|
// StartAllJobs 启动所有定时任务
|
||||||
func (l *Logic) StartAllJobs(ctx context.Context) error {
|
func (l *Logic) StartAllJobs(ctx context.Context) error {
|
||||||
g.Log().Info(ctx, "Starting all cron jobs...")
|
util.Info(ctx, "Starting all cron jobs...")
|
||||||
|
|
||||||
// 启动定时任务调度器
|
// 启动定时任务调度器
|
||||||
l.cron.Start()
|
l.cron.Start()
|
||||||
@@ -47,13 +46,13 @@ func (l *Logic) StartAllJobs(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "All cron jobs started successfully")
|
util.Info(ctx, "All cron jobs started successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopAllJobs 停止所有定时任务
|
// StopAllJobs 停止所有定时任务
|
||||||
func (l *Logic) StopAllJobs(ctx context.Context) error {
|
func (l *Logic) StopAllJobs(ctx context.Context) error {
|
||||||
g.Log().Info(ctx, "Stopping all cron jobs...")
|
util.Info(ctx, "Stopping all cron jobs...")
|
||||||
|
|
||||||
l.jobsMux.Lock()
|
l.jobsMux.Lock()
|
||||||
defer l.jobsMux.Unlock()
|
defer l.jobsMux.Unlock()
|
||||||
@@ -62,13 +61,13 @@ func (l *Logic) StopAllJobs(ctx context.Context) error {
|
|||||||
for name, entry := range l.jobs {
|
for name, entry := range l.jobs {
|
||||||
l.cron.Remove(entry.Name)
|
l.cron.Remove(entry.Name)
|
||||||
delete(l.jobs, name)
|
delete(l.jobs, name)
|
||||||
g.Log().Infof(ctx, "Stopped job: %s", name)
|
util.Infof(ctx, "Stopped job: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止调度器
|
// 停止调度器
|
||||||
l.cron.Stop()
|
l.cron.Stop()
|
||||||
|
|
||||||
g.Log().Info(ctx, "All cron jobs stopped successfully")
|
util.Info(ctx, "All cron jobs stopped successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +84,11 @@ func (l *Logic) AddJob(ctx context.Context, name, cron string, job func()) error
|
|||||||
// 添加任务到调度器
|
// 添加任务到调度器
|
||||||
entry, err := l.cron.Add(ctx, cron, func(ctx context.Context) {
|
entry, err := l.cron.Add(ctx, cron, func(ctx context.Context) {
|
||||||
startTime := gtime.Now()
|
startTime := gtime.Now()
|
||||||
g.Log().Infof(ctx, "Starting job: %s at %s", name, startTime.String())
|
util.Infof(ctx, "Starting job: %s at %s", name, startTime.String())
|
||||||
job()
|
job()
|
||||||
endTime := gtime.Now()
|
endTime := gtime.Now()
|
||||||
duration := endTime.Sub(startTime)
|
duration := endTime.Sub(startTime)
|
||||||
g.Log().Infof(ctx, "Completed job: %s, duration: %v", name, duration)
|
util.Infof(ctx, "Completed job: %s, duration: %v", name, duration)
|
||||||
}, name)
|
}, name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -98,7 +97,7 @@ func (l *Logic) AddJob(ctx context.Context, name, cron string, job func()) error
|
|||||||
|
|
||||||
// 保存任务引用
|
// 保存任务引用
|
||||||
l.jobs[name] = entry
|
l.jobs[name] = entry
|
||||||
g.Log().Infof(ctx, "Added job: %s with cron: %s", name, cron)
|
util.Infof(ctx, "Added job: %s with cron: %s", name, cron)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -117,7 +116,7 @@ func (l *Logic) RemoveJob(ctx context.Context, name string) error {
|
|||||||
l.cron.Remove(entry.Name)
|
l.cron.Remove(entry.Name)
|
||||||
delete(l.jobs, name)
|
delete(l.jobs, name)
|
||||||
|
|
||||||
g.Log().Infof(ctx, "Removed job: %s", name)
|
util.Infof(ctx, "Removed job: %s", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,11 +182,11 @@ func (l *Logic) registerDefaultJobs(ctx context.Context) error {
|
|||||||
|
|
||||||
// 每天凌晨2点同步i18n远程翻译数据
|
// 每天凌晨2点同步i18n远程翻译数据
|
||||||
if err := l.AddJob(ctx, "i18n_remote_sync", "0 0 2 * * *", func() {
|
if err := l.AddJob(ctx, "i18n_remote_sync", "0 0 2 * * *", func() {
|
||||||
g.Log().Info(ctx, "开始同步i18n远程翻译数据...")
|
util.Info(ctx, "开始同步i18n远程翻译数据...")
|
||||||
if err := i18n.GetI18nLogic().SyncI18nFromRemote(ctx); err != nil {
|
if err := i18n.GetI18nLogic().SyncI18nFromRemote(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "i18n远程翻译数据同步失败:", err)
|
util.Error(ctx, "i18n远程翻译数据同步失败:", err)
|
||||||
} else {
|
} else {
|
||||||
g.Log().Info(ctx, "i18n远程翻译数据同步完成")
|
util.Info(ctx, "i18n远程翻译数据同步完成")
|
||||||
}
|
}
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -198,44 +197,44 @@ func (l *Logic) registerDefaultJobs(ctx context.Context) error {
|
|||||||
|
|
||||||
// syncDataFromThirdParty 从第三方网站同步数据
|
// syncDataFromThirdParty 从第三方网站同步数据
|
||||||
func (l *Logic) syncDataFromThirdParty(ctx context.Context) {
|
func (l *Logic) syncDataFromThirdParty(ctx context.Context) {
|
||||||
g.Log().Info(ctx, "Starting data sync from third party...")
|
util.Info(ctx, "Starting data sync from third party...")
|
||||||
|
|
||||||
// 使用第三方数据同步器
|
// 使用第三方数据同步器
|
||||||
if err := l.sync.SyncAllData(ctx); err != nil {
|
if err := l.sync.SyncAllData(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "Data sync failed:", err)
|
util.Error(ctx, "Data sync failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "Data sync completed")
|
util.Info(ctx, "Data sync completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步英雄数据
|
// 同步英雄数据
|
||||||
func (l *Logic) syncHeroData(ctx context.Context) {
|
func (l *Logic) syncHeroData(ctx context.Context) {
|
||||||
g.Log().Info(ctx, "Starting hero data sync...")
|
util.Info(ctx, "Starting hero data sync...")
|
||||||
|
|
||||||
if err := l.sync.SyncHeroData(ctx); err != nil {
|
if err := l.sync.SyncHeroData(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "Hero data sync failed:", err)
|
util.Error(ctx, "Hero data sync failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "Hero data sync completed")
|
util.Info(ctx, "Hero data sync completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步神器数据
|
// 同步神器数据
|
||||||
func (l *Logic) syncArtifactData(ctx context.Context) {
|
func (l *Logic) syncArtifactData(ctx context.Context) {
|
||||||
g.Log().Info(ctx, "Starting artifact data sync...")
|
util.Info(ctx, "Starting artifact data sync...")
|
||||||
|
|
||||||
if err := l.sync.SyncArtifactData(ctx); err != nil {
|
if err := l.sync.SyncArtifactData(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "Artifact data sync failed:", err)
|
util.Error(ctx, "Artifact data sync failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "Artifact data sync completed")
|
util.Info(ctx, "Artifact data sync completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// healthCheck 健康检查
|
// healthCheck 健康检查
|
||||||
func (l *Logic) healthCheck(ctx context.Context) {
|
func (l *Logic) healthCheck(ctx context.Context) {
|
||||||
g.Log().Debug(ctx, "Performing health check...")
|
util.Debug(ctx, "Performing health check...")
|
||||||
|
|
||||||
// TODO: 实现健康检查逻辑
|
// TODO: 实现健康检查逻辑
|
||||||
// 1. 检查数据库连接
|
// 1. 检查数据库连接
|
||||||
@@ -243,30 +242,30 @@ func (l *Logic) healthCheck(ctx context.Context) {
|
|||||||
// 3. 检查第三方API可用性
|
// 3. 检查第三方API可用性
|
||||||
// 4. 记录系统状态
|
// 4. 记录系统状态
|
||||||
|
|
||||||
g.Log().Debug(ctx, "Health check completed")
|
util.Debug(ctx, "Health check completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// refreshCache 刷新缓存
|
// refreshCache 刷新缓存
|
||||||
func (l *Logic) refreshCache(ctx context.Context) {
|
func (l *Logic) refreshCache(ctx context.Context) {
|
||||||
g.Log().Info(ctx, "Starting cache refresh...")
|
util.Info(ctx, "Starting cache refresh...")
|
||||||
|
|
||||||
// TODO: 实现缓存刷新逻辑
|
// TODO: 实现缓存刷新逻辑
|
||||||
// 1. 刷新英雄数据缓存
|
// 1. 刷新英雄数据缓存
|
||||||
// 2. 刷新神器数据缓存
|
// 2. 刷新神器数据缓存
|
||||||
// 3. 刷新其他业务缓存
|
// 3. 刷新其他业务缓存
|
||||||
|
|
||||||
g.Log().Info(ctx, "Cache refresh completed")
|
util.Info(ctx, "Cache refresh completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新OSS图片预签名URL缓存的定时任务
|
// 刷新OSS图片预签名URL缓存的定时任务
|
||||||
func (l *Logic) refreshOssPresignUrlCacheJob(ctx context.Context) {
|
func (l *Logic) refreshOssPresignUrlCacheJob(ctx context.Context) {
|
||||||
g.Log().Info(ctx, "Starting OSS presigned URL cache refresh...")
|
util.Info(ctx, "Starting OSS presigned URL cache refresh...")
|
||||||
|
|
||||||
// 1. 从数据库读取所有英雄图片地址
|
// 1. 从数据库读取所有英雄图片地址
|
||||||
var dbHeroes []*entity.EpicHeroInfo
|
var dbHeroes []*entity.EpicHeroInfo
|
||||||
err := dao.EpicHeroInfo.Ctx(ctx).Scan(&dbHeroes)
|
err := dao.EpicHeroInfo.Ctx(ctx).Scan(&dbHeroes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "Failed to query hero info for OSS presign refresh:", err)
|
util.Error(ctx, "Failed to query hero info for OSS presign refresh:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,18 +291,18 @@ func (l *Logic) refreshOssPresignUrlCacheJob(ctx context.Context) {
|
|||||||
expire := 1 * time.Hour // 预签名URL有效期
|
expire := 1 * time.Hour // 预签名URL有效期
|
||||||
err = util.RefreshOssPresignedUrlCache(ctx, keys, expire)
|
err = util.RefreshOssPresignedUrlCache(ctx, keys, expire)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "OSS presigned URL cache refresh failed:", err)
|
util.Error(ctx, "OSS presigned URL cache refresh failed:", err)
|
||||||
} else {
|
} else {
|
||||||
g.Log().Info(ctx, "OSS presigned URL cache refresh completed")
|
util.Info(ctx, "OSS presigned URL cache refresh completed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增:定时刷新角色配装信息
|
// 新增:定时刷新角色配装信息
|
||||||
func (l *Logic) refreshHeroSetContent(ctx context.Context) {
|
func (l *Logic) refreshHeroSetContent(ctx context.Context) {
|
||||||
g.Log().Info(ctx, "Starting hero set content refresh...")
|
util.Info(ctx, "Starting hero set content refresh...")
|
||||||
if err := l.sync.RefreshAllHeroSetContent(ctx); err != nil {
|
if err := l.sync.RefreshAllHeroSetContent(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "Hero set content refresh failed:", err)
|
util.Error(ctx, "Hero set content refresh failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.Log().Info(ctx, "Hero set content refresh completed")
|
util.Info(ctx, "Hero set content refresh completed")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,43 +32,43 @@ func NewThirdPartyDataSync() *ThirdPartyDataSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *ThirdPartyDataSync) SyncHeroData(ctx context.Context) error {
|
func (t *ThirdPartyDataSync) SyncHeroData(ctx context.Context) error {
|
||||||
g.Log().Info(ctx, "开始同步英雄数据...")
|
util.Info(ctx, "开始同步英雄数据...")
|
||||||
|
|
||||||
// 示例:从第三方API获取英雄数据
|
// 示例:从第三方API获取英雄数据
|
||||||
heroData, err := t.fetchHeroDataFromAPI(ctx)
|
heroData, err := t.fetchHeroDataFromAPI(ctx)
|
||||||
if err != nil || heroData == nil {
|
if err != nil || heroData == nil {
|
||||||
g.Log().Error(ctx, "获取英雄数据失败:", err)
|
util.Error(ctx, "获取英雄数据失败:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理并保存数据
|
// 处理并保存数据
|
||||||
if err := t.processAndSaveHeroData(ctx, heroData); err != nil {
|
if err := t.processAndSaveHeroData(ctx, heroData); err != nil {
|
||||||
g.Log().Error(ctx, "处理英雄数据失败:", err)
|
util.Error(ctx, "处理英雄数据失败:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "英雄数据同步完成")
|
util.Info(ctx, "英雄数据同步完成")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步神器数据
|
// 同步神器数据
|
||||||
func (t *ThirdPartyDataSync) SyncArtifactData(ctx context.Context) error {
|
func (t *ThirdPartyDataSync) SyncArtifactData(ctx context.Context) error {
|
||||||
g.Log().Info(ctx, "开始同步神器数据...")
|
util.Info(ctx, "开始同步神器数据...")
|
||||||
|
|
||||||
//从第三方API获取神器数据
|
//从第三方API获取神器数据
|
||||||
artifactData, err := t.fetchArtifactDataFromAPI(ctx)
|
artifactData, err := t.fetchArtifactDataFromAPI(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "获取神器数据失败:", err)
|
util.Error(ctx, "获取神器数据失败:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理并保存数据
|
// 处理并保存数据
|
||||||
if err := t.processAndSaveArtifactData(ctx, artifactData); err != nil {
|
if err := t.processAndSaveArtifactData(ctx, artifactData); err != nil {
|
||||||
g.Log().Error(ctx, "处理神器数据失败:", err)
|
util.Error(ctx, "处理神器数据失败:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "神器数据同步完成")
|
util.Info(ctx, "神器数据同步完成")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,11 +169,16 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
|||||||
return fmt.Errorf("解析英雄数据到DTO失败: %v", err)
|
return fmt.Errorf("解析英雄数据到DTO失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Log().Info(ctx, "解析到", len(heroes), "个英雄数据")
|
util.Info(ctx, "解析到", len(heroes), "个英雄数据")
|
||||||
|
|
||||||
// 一次性查出所有数据库英雄,构建map
|
// 一次性查出所有数据库英雄,构建map
|
||||||
var dbHeroes []*entity.EpicHeroInfo
|
var dbHeroes []*entity.EpicHeroInfo
|
||||||
err := dao.EpicHeroInfo.Ctx(ctx).Scan(&dbHeroes)
|
err := dao.EpicHeroInfo.Ctx(ctx).
|
||||||
|
Fields(
|
||||||
|
dao.EpicHeroInfo.Columns().HeroCode,
|
||||||
|
dao.EpicHeroInfo.Columns().RawJson,
|
||||||
|
).
|
||||||
|
Scan(&dbHeroes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("查询数据库英雄失败: %v", err)
|
return fmt.Errorf("查询数据库英雄失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -194,7 +199,7 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
|||||||
// 只更新 rawJson 字段
|
// 只更新 rawJson 字段
|
||||||
rawJsonBytes, err := json.Marshal(hero)
|
rawJsonBytes, err := json.Marshal(hero)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "序列化英雄数据失败:", err)
|
util.Error(ctx, "序列化英雄数据失败:", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rawJson := string(rawJsonBytes)
|
rawJson := string(rawJsonBytes)
|
||||||
@@ -206,7 +211,7 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
|||||||
}).
|
}).
|
||||||
Update()
|
Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "更新英雄rawJson失败:", err)
|
util.Error(ctx, "更新英雄rawJson失败:", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.Log().Debug(ctx, "更新英雄rawJson:", hero.Code)
|
g.Log().Debug(ctx, "更新英雄rawJson:", hero.Code)
|
||||||
@@ -225,7 +230,7 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
|||||||
ossObjectKey := fmt.Sprintf("epic/hero/images/%s.png", hero.Code)
|
ossObjectKey := fmt.Sprintf("epic/hero/images/%s.png", hero.Code)
|
||||||
ossUrl, err := util.DownloadAndUploadToOSS(ctx, hero.Assets.Icon, ossObjectKey)
|
ossUrl, err := util.DownloadAndUploadToOSS(ctx, hero.Assets.Icon, ossObjectKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "上传英雄图片到OSS失败:", err)
|
util.Error(ctx, "上传英雄图片到OSS失败:", err)
|
||||||
return err // 直接返回,后续数据库不会插入
|
return err // 直接返回,后续数据库不会插入
|
||||||
}
|
}
|
||||||
fmt.Println(ossUrl)
|
fmt.Println(ossUrl)
|
||||||
@@ -262,7 +267,7 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
|||||||
|
|
||||||
_, err = dao.EpicHeroInfo.Ctx(ctx).Data(newHero).Insert()
|
_, err = dao.EpicHeroInfo.Ctx(ctx).Data(newHero).Insert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "插入新英雄失败:", err)
|
util.Error(ctx, "插入新英雄失败:", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.Log().Debug(ctx, "插入新英雄:", hero.Code)
|
g.Log().Debug(ctx, "插入新英雄:", hero.Code)
|
||||||
@@ -272,7 +277,7 @@ func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []
|
|||||||
key := ossObjectKey
|
key := ossObjectKey
|
||||||
err := util.RefreshOssPresignedUrlCache(ctx, []string{key}, 24*time.Hour)
|
err := util.RefreshOssPresignedUrlCache(ctx, []string{key}, 24*time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "刷新新英雄图片预签名URL失败:", key, err)
|
util.Error(ctx, "刷新新英雄图片预签名URL失败:", key, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +302,7 @@ func (t *ThirdPartyDataSync) processAndSaveArtifactData(ctx context.Context, dat
|
|||||||
if err := json.Unmarshal([]byte(data), &artifactMap); err != nil {
|
if err := json.Unmarshal([]byte(data), &artifactMap); err != nil {
|
||||||
return fmt.Errorf("解析神器数据失败: %v", err)
|
return fmt.Errorf("解析神器数据失败: %v", err)
|
||||||
}
|
}
|
||||||
g.Log().Info(ctx, "解析到", len(artifactMap), "个神器数据")
|
util.Info(ctx, "解析到", len(artifactMap), "个神器数据")
|
||||||
|
|
||||||
// 2. 查询数据库所有神器,构建map
|
// 2. 查询数据库所有神器,构建map
|
||||||
var dbArtifacts []*entity.EpicArtifactInfo
|
var dbArtifacts []*entity.EpicArtifactInfo
|
||||||
@@ -355,10 +360,10 @@ func (t *ThirdPartyDataSync) processAndSaveArtifactData(ctx context.Context, dat
|
|||||||
dao.EpicArtifactInfo.Columns().Deleted: artifact.Deleted,
|
dao.EpicArtifactInfo.Columns().Deleted: artifact.Deleted,
|
||||||
}).Update()
|
}).Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "更新神器失败:", art.Name, err)
|
util.Error(ctx, "更新神器失败:", art.Name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.Log().Info(ctx, "更新神器:", art.Name)
|
util.Info(ctx, "更新神器:", art.Name)
|
||||||
} else {
|
} else {
|
||||||
artifact.Creator = "sync"
|
artifact.Creator = "sync"
|
||||||
_, err := dao.EpicArtifactInfo.Ctx(ctx).Data(g.Map{
|
_, err := dao.EpicArtifactInfo.Ctx(ctx).Data(g.Map{
|
||||||
@@ -378,10 +383,10 @@ func (t *ThirdPartyDataSync) processAndSaveArtifactData(ctx context.Context, dat
|
|||||||
dao.EpicArtifactInfo.Columns().Deleted: artifact.Deleted,
|
dao.EpicArtifactInfo.Columns().Deleted: artifact.Deleted,
|
||||||
}).Insert()
|
}).Insert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "插入神器失败:", art.Name, err)
|
util.Error(ctx, "插入神器失败:", art.Name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.Log().Info(ctx, "插入神器:", art.Name)
|
util.Info(ctx, "插入神器:", art.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -392,6 +397,10 @@ func (t *ThirdPartyDataSync) saveHeroData(ctx context.Context, hero *dto.ThirdPa
|
|||||||
// 查询是否存在
|
// 查询是否存在
|
||||||
var dbHero *entity.EpicHeroInfo
|
var dbHero *entity.EpicHeroInfo
|
||||||
err := dao.EpicHeroInfo.Ctx(ctx).
|
err := dao.EpicHeroInfo.Ctx(ctx).
|
||||||
|
Fields(
|
||||||
|
dao.EpicHeroInfo.Columns().HeroCode,
|
||||||
|
dao.EpicHeroInfo.Columns().RawJson,
|
||||||
|
).
|
||||||
Where(dao.EpicHeroInfo.Columns().HeroCode, hero.Code).
|
Where(dao.EpicHeroInfo.Columns().HeroCode, hero.Code).
|
||||||
Scan(&dbHero)
|
Scan(&dbHero)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -481,23 +490,23 @@ func (t *ThirdPartyDataSync) saveArtifactData(ctx context.Context, artifact *dto
|
|||||||
|
|
||||||
// SyncAllData 同步所有数据
|
// SyncAllData 同步所有数据
|
||||||
func (t *ThirdPartyDataSync) SyncAllData(ctx context.Context) error {
|
func (t *ThirdPartyDataSync) SyncAllData(ctx context.Context) error {
|
||||||
g.Log().Info(ctx, "开始同步所有第三方数据...")
|
util.Info(ctx, "开始同步所有第三方数据...")
|
||||||
|
|
||||||
// 同步英雄数据
|
// 同步英雄数据
|
||||||
if err := t.SyncHeroData(ctx); err != nil {
|
if err := t.SyncHeroData(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "英雄数据同步失败:", err)
|
util.Error(ctx, "英雄数据同步失败:", err)
|
||||||
// 继续同步其他数据
|
// 继续同步其他数据
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步神器数据
|
// 同步神器数据
|
||||||
if err := t.SyncArtifactData(ctx); err != nil {
|
if err := t.SyncArtifactData(ctx); err != nil {
|
||||||
g.Log().Error(ctx, "神器数据同步失败:", err)
|
util.Error(ctx, "神器数据同步失败:", err)
|
||||||
// 继续同步其他数据
|
// 继续同步其他数据
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可以继续添加其他数据类型的同步
|
// 可以继续添加其他数据类型的同步
|
||||||
|
|
||||||
g.Log().Info(ctx, "所有第三方数据同步完成")
|
util.Info(ctx, "所有第三方数据同步完成")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,14 +528,14 @@ func (t *ThirdPartyDataSync) RefreshHeroSetContentByHeroInfo(ctx context.Context
|
|||||||
g.Log().Infof(ctx, "已更新: %s", heroName)
|
g.Log().Infof(ctx, "已更新: %s", heroName)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
g.Log().Error(ctx, "配装数据无效(长度<=200): %s", heroName)
|
util.Error(ctx, "配装数据无效(长度<=200): %s", heroName)
|
||||||
return fmt.Errorf("配装数据无效(长度<=200)")
|
return fmt.Errorf("配装数据无效(长度<=200)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新所有角色配装字段
|
// 刷新所有角色配装字段
|
||||||
func (t *ThirdPartyDataSync) RefreshAllHeroSetContent(ctx context.Context) error {
|
func (t *ThirdPartyDataSync) RefreshAllHeroSetContent(ctx context.Context) error {
|
||||||
g.Log().Info(ctx, "开始批量刷新所有角色配装字段...")
|
util.Info(ctx, "开始批量刷新所有角色配装字段...")
|
||||||
|
|
||||||
// 1. 查询所有角色,按set_update_time正序排列,为空的在最前面
|
// 1. 查询所有角色,按set_update_time正序排列,为空的在最前面
|
||||||
var heroList []*entity.EpicHeroInfo
|
var heroList []*entity.EpicHeroInfo
|
||||||
@@ -534,7 +543,7 @@ func (t *ThirdPartyDataSync) RefreshAllHeroSetContent(ctx context.Context) error
|
|||||||
OrderAsc("set_update_time").
|
OrderAsc("set_update_time").
|
||||||
Scan(&heroList)
|
Scan(&heroList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log().Error(ctx, "查询epic_hero_info失败:", err)
|
util.Error(ctx, "查询epic_hero_info失败:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,12 +587,12 @@ func getArtifactImageUrl(ctx context.Context, artCode string, dbArt *entity.Epic
|
|||||||
// 从Redis获取神器爬虫数据
|
// 从Redis获取神器爬虫数据
|
||||||
redisVal, err := util.RedisCache.Get(ctx, "epic7:artifacts")
|
redisVal, err := util.RedisCache.Get(ctx, "epic7:artifacts")
|
||||||
if err != nil || redisVal == nil {
|
if err != nil || redisVal == nil {
|
||||||
g.Log().Error(ctx, "获取Redis神器数据失败:", err)
|
util.Error(ctx, "获取Redis神器数据失败:", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
var artifactArr []map[string]interface{}
|
var artifactArr []map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(redisVal.String()), &artifactArr); err != nil {
|
if err := json.Unmarshal([]byte(redisVal.String()), &artifactArr); err != nil {
|
||||||
g.Log().Error(ctx, "解析Redis神器数据失败:", err)
|
util.Error(ctx, "解析Redis神器数据失败:", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
g.Log().Debug(ctx, "Redis中共有", len(artifactArr), "个神器数据")
|
g.Log().Debug(ctx, "Redis中共有", len(artifactArr), "个神器数据")
|
||||||
@@ -690,7 +699,7 @@ func getArtifactImageUrl(ctx context.Context, artCode string, dbArt *entity.Epic
|
|||||||
if bestMatch != nil {
|
if bestMatch != nil {
|
||||||
archSrc, ok := bestMatch["arch_src"].(string)
|
archSrc, ok := bestMatch["arch_src"].(string)
|
||||||
if !ok || archSrc == "" {
|
if !ok || archSrc == "" {
|
||||||
g.Log().Error(ctx, "匹配成功但arch_src为空:", bestMatchName)
|
util.Error(ctx, "匹配成功但arch_src为空:", bestMatchName)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
g.Log().Debug(ctx, "开始下载并上传图片:", bestMatchName, "图片路径:", archSrc)
|
g.Log().Debug(ctx, "开始下载并上传图片:", bestMatchName, "图片路径:", archSrc)
|
||||||
@@ -701,7 +710,7 @@ func getArtifactImageUrl(ctx context.Context, artCode string, dbArt *entity.Epic
|
|||||||
ossObjectKey := fmt.Sprintf("epic/artifact/images/%s.png", artCode)
|
ossObjectKey := fmt.Sprintf("epic/artifact/images/%s.png", artCode)
|
||||||
ossUrl, err := util.DownloadAndUploadToOSS(ctx, imgUrl, ossObjectKey)
|
ossUrl, err := util.DownloadAndUploadToOSS(ctx, imgUrl, ossObjectKey)
|
||||||
if err != nil || ossUrl == "" {
|
if err != nil || ossUrl == "" {
|
||||||
g.Log().Error(ctx, "下载上传图片失败:", bestMatchName, "错误:", err)
|
util.Error(ctx, "下载上传图片失败:", bestMatchName, "错误:", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
prefix := consts.S3Endpoint + "/" + consts.S3Bucket
|
prefix := consts.S3Endpoint + "/" + consts.S3Bucket
|
||||||
@@ -753,7 +762,12 @@ func FixHeroAndArtifactNameToChinese(ctx context.Context) error {
|
|||||||
|
|
||||||
// 2. 修复英雄表
|
// 2. 修复英雄表
|
||||||
var heroes []*entity.EpicHeroInfo
|
var heroes []*entity.EpicHeroInfo
|
||||||
err = dao.EpicHeroInfo.Ctx(ctx).Scan(&heroes)
|
err = dao.EpicHeroInfo.Ctx(ctx).
|
||||||
|
Fields(
|
||||||
|
dao.EpicHeroInfo.Columns().HeroCode,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroName,
|
||||||
|
).
|
||||||
|
Scan(&heroes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("查询epic_hero_info失败: %v", err)
|
return fmt.Errorf("查询epic_hero_info失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,19 @@ func (l *Logic) GetHeroByCode(ctx context.Context, code string) (*entity.EpicHer
|
|||||||
// 2. 缓存未命中,查数据库
|
// 2. 缓存未命中,查数据库
|
||||||
var hero *entity.EpicHeroInfo
|
var hero *entity.EpicHeroInfo
|
||||||
err := dao.EpicHeroInfo.Ctx(ctx).
|
err := dao.EpicHeroInfo.Ctx(ctx).
|
||||||
|
Fields(
|
||||||
|
dao.EpicHeroInfo.Columns().Id,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroName,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroCode,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroAttrLv60,
|
||||||
|
dao.EpicHeroInfo.Columns().NickName,
|
||||||
|
dao.EpicHeroInfo.Columns().Rarity,
|
||||||
|
dao.EpicHeroInfo.Columns().Role,
|
||||||
|
dao.EpicHeroInfo.Columns().Zodiac,
|
||||||
|
dao.EpicHeroInfo.Columns().HeadImgUrl,
|
||||||
|
dao.EpicHeroInfo.Columns().Attribute,
|
||||||
|
dao.EpicHeroInfo.Columns().Remark,
|
||||||
|
).
|
||||||
Where(dao.EpicHeroInfo.Columns().HeroCode, code).
|
Where(dao.EpicHeroInfo.Columns().HeroCode, code).
|
||||||
Scan(&hero)
|
Scan(&hero)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -58,7 +71,19 @@ func (l *Logic) GetHeroList(ctx context.Context) ([]*v1.EpicHeroVO, error) {
|
|||||||
|
|
||||||
// 2. 缓存未命中,查数据库
|
// 2. 缓存未命中,查数据库
|
||||||
err := dao.EpicHeroInfo.Ctx(ctx).
|
err := dao.EpicHeroInfo.Ctx(ctx).
|
||||||
OrderDesc(dao.EpicHeroInfo.Columns().CreateTime). // 按创建时间倒序
|
Fields(
|
||||||
|
dao.EpicHeroInfo.Columns().Id,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroName,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroCode,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroAttrLv60,
|
||||||
|
dao.EpicHeroInfo.Columns().NickName,
|
||||||
|
dao.EpicHeroInfo.Columns().Rarity,
|
||||||
|
dao.EpicHeroInfo.Columns().Role,
|
||||||
|
dao.EpicHeroInfo.Columns().Zodiac,
|
||||||
|
dao.EpicHeroInfo.Columns().HeadImgUrl,
|
||||||
|
dao.EpicHeroInfo.Columns().Attribute,
|
||||||
|
dao.EpicHeroInfo.Columns().Remark,
|
||||||
|
).OrderDesc(dao.EpicHeroInfo.Columns().CreateTime).
|
||||||
Scan(&doList)
|
Scan(&doList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -102,6 +127,19 @@ func (l *Logic) GetHeroDetailByCode(ctx context.Context, code string) (*v1.HeroD
|
|||||||
)
|
)
|
||||||
|
|
||||||
err = dao.EpicHeroInfo.Ctx(ctx).
|
err = dao.EpicHeroInfo.Ctx(ctx).
|
||||||
|
Fields(
|
||||||
|
dao.EpicHeroInfo.Columns().Id,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroName,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroCode,
|
||||||
|
dao.EpicHeroInfo.Columns().HeroAttrLv60,
|
||||||
|
dao.EpicHeroInfo.Columns().NickName,
|
||||||
|
dao.EpicHeroInfo.Columns().Rarity,
|
||||||
|
dao.EpicHeroInfo.Columns().Role,
|
||||||
|
dao.EpicHeroInfo.Columns().Zodiac,
|
||||||
|
dao.EpicHeroInfo.Columns().HeadImgUrl,
|
||||||
|
dao.EpicHeroInfo.Columns().Attribute,
|
||||||
|
dao.EpicHeroInfo.Columns().Remark,
|
||||||
|
).
|
||||||
Where(dao.EpicHeroInfo.Columns().HeroCode, code).
|
Where(dao.EpicHeroInfo.Columns().HeroCode, code).
|
||||||
Scan(&epicHeroInfo)
|
Scan(&epicHeroInfo)
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,37 @@ func Info(ctx context.Context, args ...interface{}) {
|
|||||||
g.Log().Info(ctx, args...)
|
g.Log().Info(ctx, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Infof 全局Info格式化日志
|
||||||
|
func Infof(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
g.Log().Infof(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debug 全局Debug日志
|
// Debug 全局Debug日志
|
||||||
func Debug(ctx context.Context, args ...interface{}) {
|
func Debug(ctx context.Context, args ...interface{}) {
|
||||||
g.Log().Debug(ctx, args...)
|
g.Log().Debug(ctx, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debugf 全局Debug格式化日志
|
||||||
|
func Debugf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
g.Log().Debugf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Error 全局Error日志
|
// Error 全局Error日志
|
||||||
func Error(ctx context.Context, args ...interface{}) {
|
func Error(ctx context.Context, args ...interface{}) {
|
||||||
g.Log().Error(ctx, args...)
|
g.Log().Error(ctx, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errorf 全局Error格式化日志
|
||||||
|
func Errorf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
g.Log().Errorf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn 全局Warn日志
|
||||||
|
func Warn(ctx context.Context, args ...interface{}) {
|
||||||
|
g.Log().Warning(ctx, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf 全局Warn格式化日志
|
||||||
|
func Warnf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
g.Log().Warningf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ logger:
|
|||||||
database:
|
database:
|
||||||
default:
|
default:
|
||||||
link: "mysql:root:hu123456@tcp(193.112.151.199:3306)/wow"
|
link: "mysql:root:hu123456@tcp(193.112.151.199:3306)/wow"
|
||||||
debug: true
|
debug: false
|
||||||
|
|
||||||
# https://goframe.org/docs/core/gredis-config-file
|
# https://goframe.org/docs/core/gredis-config-file
|
||||||
redis:
|
redis:
|
||||||
|
|||||||
Reference in New Issue
Block a user