From dd05510d27a5f3c89bfc2defb1398575d78b9d06 Mon Sep 17 00:00:00 2001 From: keven Date: Sun, 19 Oct 2025 14:39:46 +0800 Subject: [PATCH] feat(backend): implement About and Config endpoints, enhance GetStat with queue data and file size metrics --- backend/internal/controllers/about.go | 25 +++++++++ backend/internal/controllers/config.go | 4 ++ backend/internal/controllers/stat.go | 73 ++++++++++---------------- backend/main.go | 2 + 4 files changed, 60 insertions(+), 44 deletions(-) diff --git a/backend/internal/controllers/about.go b/backend/internal/controllers/about.go index c8c54c5..a4ae534 100644 --- a/backend/internal/controllers/about.go +++ b/backend/internal/controllers/about.go @@ -1,12 +1,33 @@ package controllers import ( + "backend/internal/models" "backend/internal/utils" + "encoding/json" "github.com/labstack/echo/v4" + "github.com/samber/lo" ) func GetAbout(c echo.Context) error { + maxStorageSize, err := utils.GetFileSize(utils.GetEnv("upload.maximum")) + if err != nil { + return utils.HTTPErrorHandler(c, err) + } + + fileInfoMap, err := models.GetRedisFileInfoAll() + if err != nil { + return utils.HTTPErrorHandler(c, err) + } + + currentFileSize := lo.Reduce(lo.Values(fileInfoMap), func(agg int64, item string, _ int) int64 { + var fileInfo models.RedisFileInfo + err := json.Unmarshal([]byte(item), &fileInfo) + if err != nil { + return agg + } + return agg + fileInfo.FileSize + }, 0) return utils.HTTPSuccessHandler(c, map[string]any{ "bg_url": utils.GetEnv("about.bg_url"), @@ -15,5 +36,9 @@ func GetAbout(c echo.Context) error { "name": utils.GetEnv("about.name"), "url": utils.GetEnv("about.url"), "avatar": utils.GetEnv("about.avatar"), + "file": map[string]any{ + "maximun": maxStorageSize, + "current": currentFileSize, + }, }) } diff --git a/backend/internal/controllers/config.go b/backend/internal/controllers/config.go index a8ff51e..97cc1cf 100644 --- a/backend/internal/controllers/config.go +++ b/backend/internal/controllers/config.go @@ -2,8 +2,10 @@ package controllers import ( "backend/internal/utils" + "time" "github.com/labstack/echo/v4" + "github.com/spf13/cast" ) func GetConfig(c echo.Context) error { @@ -13,5 +15,7 @@ func GetConfig(c echo.Context) error { "site_url": utils.GetEnv("site.url"), "site_icon": utils.GetEnvWithDefault("site.icon", "/logo.png"), "site_bg_url": utils.GetEnvWithDefault("site.bg_url", "https://img.fudaoyuan.icu/api/1/random/?scale_min=1.5&webp=true&md=false&format=302"), + "version": utils.GetEnvWithDefault("VERSION", "dev"), + "build_time": cast.ToInt(utils.GetEnvWithDefault("BUILD_TIME", cast.ToString(time.Now().Unix()))), }) } diff --git a/backend/internal/controllers/stat.go b/backend/internal/controllers/stat.go index 50d53df..733a149 100644 --- a/backend/internal/controllers/stat.go +++ b/backend/internal/controllers/stat.go @@ -6,10 +6,13 @@ import ( "encoding/json" "time" - "github.com/hibiken/asynq" "github.com/labstack/echo/v4" - "github.com/samber/lo" - "github.com/spf13/cast" +) + +const ( + DateLayout = "2006-01-02" + DaysToAnalyze = 30 + QueueHistoryDays = 30 ) type FileChartData struct { @@ -18,11 +21,20 @@ type FileChartData struct { Date string `json:"date"` } +type QueueChartData struct { + Processed int `json:"processed"` + Failed int `json:"failed"` +} + func GetStat(c echo.Context) error { fileInfoMap, err := models.GetRedisFileInfoAll() if err != nil { return utils.HTTPErrorHandler(c, err) } + + now := time.Now() + cutoffTime := now.Add(-DaysToAnalyze * 24 * time.Hour) + fileChartData := make(map[string]FileChartData) for _, value := range fileInfoMap { var fileInfo models.RedisFileInfo @@ -33,8 +45,10 @@ func GetStat(c echo.Context) error { if fileInfo.FileType != models.FileTypeUpload { continue } - if time.Unix(fileInfo.CreatedAt, 0).After(time.Now().Add(-30 * 24 * time.Hour)) { - dateKey := time.Unix(fileInfo.CreatedAt, 0).Format("2006-01-02") + + createdAt := time.Unix(fileInfo.CreatedAt, 0) + if createdAt.After(cutoffTime) { + dateKey := createdAt.Format(DateLayout) if data, ok := fileChartData[dateKey]; ok { fileChartData[dateKey] = FileChartData{ FileSize: data.FileSize + fileInfo.FileSize, @@ -48,55 +62,26 @@ func GetStat(c echo.Context) error { } } } - storageChartData := lo.Times(30, func(i int) FileChartData { - dateKey := time.Now().AddDate(0, 0, -i).Format("2006-01-02") - if data, ok := fileChartData[dateKey]; ok { - return FileChartData{ - FileSize: data.FileSize, - FileNum: data.FileNum, - Date: dateKey, - } - } - return FileChartData{ - FileSize: 0, - FileNum: 0, - Date: dateKey, - } - }) queueInspector := utils.GetQueueInspector() - queues, err := queueInspector.History("default", 30) + queues, err := queueInspector.History("default", QueueHistoryDays) if err != nil { return utils.HTTPErrorHandler(c, err) } - maxStorageSize, err := utils.GetFileSize(utils.GetEnv("upload.maximum")) - if err != nil { - return utils.HTTPErrorHandler(c, err) - } - - queueData := lo.Map(queues, func(item *asynq.DailyStats, _ int) map[string]any { - return map[string]any{ - "date": item.Date.Format("2006-01-02"), - "processed": item.Processed, - "failed": item.Failed, + queuesChartData := make(map[string]QueueChartData) + for _, item := range queues { + dateKey := item.Date.Format(DateLayout) + queuesChartData[dateKey] = QueueChartData{ + Processed: item.Processed, + Failed: item.Failed, } - }) + } return utils.HTTPSuccessHandler(c, map[string]any{ - "version": utils.GetEnvWithDefault("VERSION", "dev"), - "build_time": cast.ToInt(utils.GetEnvWithDefault("BUILD_TIME", cast.ToString(time.Now().Unix()))), - "max_limit": map[string]any{ - "file_size": maxStorageSize, - }, - "admin": map[string]any{ - "name": utils.GetEnv("ADMIN_NAME"), - "email": utils.GetEnv("ADMIN_EMAIL"), - "url": utils.GetEnv("ADMIN_URL"), - }, "chart": map[string]any{ - "storage": storageChartData, - "queue": queueData, + "storage": fileChartData, + "queue": queuesChartData, }, }) } diff --git a/backend/main.go b/backend/main.go index 652fda8..d57dfba 100644 --- a/backend/main.go +++ b/backend/main.go @@ -41,5 +41,7 @@ func main() { e.GET("/image/compress/:id", controllers.GetCompressImage) e.GET("/stat", controllers.GetStat) + e.GET("/config", controllers.GetConfig) + e.GET("/about", controllers.GetAbout) e.Logger.Fatal(e.Start(fmt.Sprintf(":%s", utils.GetEnvWithDefault("api.port", "5001")))) }