diff --git a/internal/http/handlers/image.go b/internal/http/handlers/image.go index 5828c8d..846e934 100644 --- a/internal/http/handlers/image.go +++ b/internal/http/handlers/image.go @@ -48,11 +48,16 @@ type ImageMetaResp struct { // @Param format query string false "格式 (jpg)" default(jpg) // @Produce image/jpeg // @Success 200 {file} binary +// @Success 202 {object} map[string]string "按需抓取任务已启动" // @Failure 404 {object} map[string]string "图片未找到,响应体包含具体原因" // @Router /image/today [get] func GetToday(c *gin.Context) { mkt := c.Query("mkt") img, err := image.GetTodayImage(mkt) + if err == image.ErrFetchStarted { + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("On-demand fetch started for region [%s]. Please try again later.", mkt)}) + return + } if err != nil { sendImageNotFound(c, mkt) return @@ -67,11 +72,16 @@ func GetToday(c *gin.Context) { // @Param mkt query string false "地区编码 (如 zh-CN, en-US)" // @Produce json // @Success 200 {object} ImageMetaResp +// @Success 202 {object} map[string]string "按需抓取任务已启动" // @Failure 404 {object} map[string]string "图片未找到,响应体包含具体原因" // @Router /image/today/meta [get] func GetTodayMeta(c *gin.Context) { mkt := c.Query("mkt") img, err := image.GetTodayImage(mkt) + if err == image.ErrFetchStarted { + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("On-demand fetch started for region [%s]. Please try again later.", mkt)}) + return + } if err != nil { sendImageNotFound(c, mkt) return @@ -89,11 +99,16 @@ func GetTodayMeta(c *gin.Context) { // @Param format query string false "格式" default(jpg) // @Produce image/jpeg // @Success 200 {file} binary +// @Success 202 {object} map[string]string "按需抓取任务已启动" // @Failure 404 {object} map[string]string "图片未找到,响应体包含具体原因" // @Router /image/random [get] func GetRandom(c *gin.Context) { mkt := c.Query("mkt") img, err := image.GetRandomImage(mkt) + if err == image.ErrFetchStarted { + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("On-demand fetch started for region [%s]. Please try again later.", mkt)}) + return + } if err != nil { sendImageNotFound(c, mkt) return @@ -108,11 +123,16 @@ func GetRandom(c *gin.Context) { // @Param mkt query string false "地区编码 (如 zh-CN, en-US)" // @Produce json // @Success 200 {object} ImageMetaResp +// @Success 202 {object} map[string]string "按需抓取任务已启动" // @Failure 404 {object} map[string]string "图片未找到,响应体包含具体原因" // @Router /image/random/meta [get] func GetRandomMeta(c *gin.Context) { mkt := c.Query("mkt") img, err := image.GetRandomImage(mkt) + if err == image.ErrFetchStarted { + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("On-demand fetch started for region [%s]. Please try again later.", mkt)}) + return + } if err != nil { sendImageNotFound(c, mkt) return @@ -131,12 +151,17 @@ func GetRandomMeta(c *gin.Context) { // @Param format query string false "格式" default(jpg) // @Produce image/jpeg // @Success 200 {file} binary +// @Success 202 {object} map[string]string "按需抓取任务已启动" // @Failure 404 {object} map[string]string "图片未找到,响应体包含具体原因" // @Router /image/date/{date} [get] func GetByDate(c *gin.Context) { date := c.Param("date") mkt := c.Query("mkt") img, err := image.GetImageByDate(date, mkt) + if err == image.ErrFetchStarted { + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("On-demand fetch started for region [%s]. Please try again later.", mkt)}) + return + } if err != nil { sendImageNotFound(c, mkt) return @@ -152,12 +177,17 @@ func GetByDate(c *gin.Context) { // @Param mkt query string false "地区编码 (如 zh-CN, en-US)" // @Produce json // @Success 200 {object} ImageMetaResp +// @Success 202 {object} map[string]string "按需抓取任务已启动" // @Failure 404 {object} map[string]string "图片未找到,响应体包含具体原因" // @Router /image/date/{date}/meta [get] func GetByDateMeta(c *gin.Context) { date := c.Param("date") mkt := c.Query("mkt") img, err := image.GetImageByDate(date, mkt) + if err == image.ErrFetchStarted { + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("On-demand fetch started for region [%s]. Please try again later.", mkt)}) + return + } if err != nil { sendImageNotFound(c, mkt) return diff --git a/internal/service/image/image_service.go b/internal/service/image/image_service.go index 426ca29..7e67778 100644 --- a/internal/service/image/image_service.go +++ b/internal/service/image/image_service.go @@ -2,6 +2,7 @@ package image import ( "context" + "errors" "fmt" "time" @@ -15,6 +16,8 @@ import ( "go.uber.org/zap" ) +var ErrFetchStarted = errors.New("on-demand fetch started") + func CleanupOldImages(ctx context.Context) error { days := config.GetConfig().Retention.Days if days <= 0 { @@ -60,14 +63,13 @@ func GetTodayImage(mkt string) (*model.Image, error) { } err := tx.Preload("Variants").First(&img).Error if err != nil && mkt != "" && config.GetConfig().API.EnableOnDemandFetch && util.IsValidRegion(mkt) { - // 如果没找到,尝试按需抓取该地区 - util.Logger.Info("Image not found in DB, attempting on-demand fetch", zap.String("mkt", mkt)) + // 如果没找到,尝试异步按需抓取该地区 + util.Logger.Info("Image not found in DB, starting asynchronous on-demand fetch", zap.String("mkt", mkt)) f := fetcher.NewFetcher() - _ = f.FetchRegion(context.Background(), mkt) - - // 抓取后重新查询 - tx = repo.DB.Where("date = ?", today).Where("mkt = ?", mkt) - err = tx.Preload("Variants").First(&img).Error + go func() { + _ = f.FetchRegion(context.Background(), mkt) + }() + return nil, ErrFetchStarted } if err != nil { @@ -118,14 +120,13 @@ func GetRandomImage(mkt string) (*model.Image, error) { } tx.Count(&count) if count == 0 && mkt != "" && config.GetConfig().API.EnableOnDemandFetch && util.IsValidRegion(mkt) { - // 如果没找到,尝试按需抓取该地区 - util.Logger.Info("No images found in DB for region, attempting on-demand fetch", zap.String("mkt", mkt)) + // 如果没找到,尝试异步按需抓取该地区 + util.Logger.Info("No images found in DB for region, starting asynchronous on-demand fetch", zap.String("mkt", mkt)) f := fetcher.NewFetcher() - _ = f.FetchRegion(context.Background(), mkt) - - // 抓取后重新计数 - tx = repo.DB.Model(&model.Image{}).Where("mkt = ?", mkt) - tx.Count(&count) + go func() { + _ = f.FetchRegion(context.Background(), mkt) + }() + return nil, ErrFetchStarted } if count == 0 { @@ -167,14 +168,13 @@ func GetImageByDate(date string, mkt string) (*model.Image, error) { } err := tx.Preload("Variants").First(&img).Error if err != nil && mkt != "" && config.GetConfig().API.EnableOnDemandFetch && util.IsValidRegion(mkt) { - // 如果没找到,尝试按需抓取该地区 - util.Logger.Info("Image not found in DB for date, attempting on-demand fetch", zap.String("mkt", mkt), zap.String("date", date)) + // 如果没找到,尝试异步按需抓取该地区 + util.Logger.Info("Image not found in DB for date, starting asynchronous on-demand fetch", zap.String("mkt", mkt), zap.String("date", date)) f := fetcher.NewFetcher() - _ = f.FetchRegion(context.Background(), mkt) - - // 抓取后重新查询 - tx = repo.DB.Where("date = ?", date).Where("mkt = ?", mkt) - err = tx.Preload("Variants").First(&img).Error + go func() { + _ = f.FetchRegion(context.Background(), mkt) + }() + return nil, ErrFetchStarted } // 兜底逻辑 diff --git a/internal/util/regions.go b/internal/util/regions.go index 9ae9a74..a89d618 100644 --- a/internal/util/regions.go +++ b/internal/util/regions.go @@ -32,6 +32,4 @@ var AllRegions = []Region{ {Value: "ko-KR", Label: "韩国"}, {Value: "en-IN", Label: "印度"}, {Value: "ru-RU", Label: "俄罗斯"}, - {Value: "zh-HK", Label: "中国香港"}, - {Value: "zh-TW", Label: "中国台湾"}, }