package app import ( "verification-platform-backend/internal/database" "verification-platform-backend/internal/model" "verification-platform-backend/internal/service" "verification-platform-backend/pkg/response" "github.com/gin-gonic/gin" ) func SetupInfoRoutes(r *gin.RouterGroup) { r.GET("/info", handleAppGetInfo) r.GET("/check-update", handleAppCheckUpdate) r.GET("/announcements", handleAppGetAnnouncements) } func handleAppGetInfo(c *gin.Context) { appKey := c.Param("appKey") var app model.Application if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } if service.GetApplicationDisabledStatus(app.ID) { response.Error(c, 403, "该应用已被禁用") return } response.Success(c, gin.H{ "id": app.ID, "name": app.Name, "description": app.Description, "icon_url": app.IconURL, "status": app.Status, "billing_type": app.BillingType, "login_policy": app.LoginPolicy, "max_devices": app.MaxDevices, "multi_open_mode": app.MultiOpenMode, "max_instances": app.MaxInstances, "enable_trial": app.EnableTrial, "trial_balance": app.TrialBalance, "heartbeat_interval": app.HeartbeatInterval, "heartbeat_timeout": app.HeartbeatTimeout, }) } func handleAppCheckUpdate(c *gin.Context) { appKey := c.Param("appKey") clientVersion := c.Query("version") var app model.Application if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } if service.GetApplicationDisabledStatus(app.ID) { response.Error(c, 403, "该应用已被禁用") return } // 查询该应用的所有版本,按ID降序(创建顺序) var allVersions []model.Version if err := database.DB.Where("application_id = ? AND status = ?", app.ID, "active"). Order("id DESC"). Preload("Files"). Find(&allVersions).Error; err != nil { response.Error(c, 500, "获取版本列表失败") return } // 没有任何版本 if len(allVersions) == 0 { response.Success(c, gin.H{ "has_update": false, "current_version": clientVersion, "latest_version": "", "download_url": "", "update_notes": "", "update_strategy": "", "update_method": "", "files": []interface{}{}, }) return } // 客户端必须提供版本号 if clientVersion == "" { response.Error(c, 400, "请提供客户端版本号") return } // 找到客户端当前版本对应的版本记录 var clientVersionRecord *model.Version for i := range allVersions { if allVersions[i].Version == clientVersion { clientVersionRecord = &allVersions[i] break } } // 客户端版本不存在于服务器版本列表中,返回错误 if clientVersionRecord == nil { response.Error(c, 404, "客户端版本不存在") return } // 判断客户端版本状态:检查是否有更高ID的强制更新版本 isSuperseded := false for i := range allVersions { v := &allVersions[i] // 存在ID更高(创建时间更晚)的强制更新版本 if v.ID > clientVersionRecord.ID && v.UpdateStrategy == "forced" { isSuperseded = true break } } // 如果被取代(有强制更新),必须更新 // 找到最新的强制更新版本 var latestVersion *model.Version var updateStrategy string if isSuperseded { // 找到ID最高的强制更新版本 for i := range allVersions { v := &allVersions[i] if v.ID > clientVersionRecord.ID && v.UpdateStrategy == "forced" { if latestVersion == nil || v.ID > latestVersion.ID { latestVersion = v } } } updateStrategy = "forced" } else { // 没有强制更新,检查是否有更高ID的版本(普通更新) // 最新版本就是ID最高的版本(已经是按ID降序排列,第一个就是最新) latestVersion = &allVersions[0] // 只有当最新版本ID大于客户端版本ID时才需要更新 if latestVersion.ID > clientVersionRecord.ID { updateStrategy = latestVersion.UpdateStrategy // optional 或 forced } else { // 已经是最新版本 response.Success(c, gin.H{ "has_update": false, "current_version": clientVersion, "latest_version": clientVersionRecord.Version, "download_url": "", "update_notes": "", "update_strategy": "", "update_method": "", "files": []interface{}{}, }) return } } // 构建文件列表 files := make([]map[string]interface{}, len(latestVersion.Files)) for i, f := range latestVersion.Files { files[i] = map[string]interface{}{ "file_path": f.FilePath, "file_name": f.FileName, "file_size": f.FileSize, "file_hash": f.FileHash, "file_type": f.FileType, "is_required": f.IsRequired, } } // 构建返回结果 result := map[string]interface{}{ "has_update": true, "current_version": clientVersion, "latest_version": latestVersion.Version, "download_url": latestVersion.FilePath, "file_size": latestVersion.FileSize, "file_hash": latestVersion.FileHash, "entry_file": latestVersion.EntryFile, "update_notes": latestVersion.Description, "update_strategy": updateStrategy, "update_type": latestVersion.UpdateType, "update_method": latestVersion.UpdateMethod, "changelog": latestVersion.Changelog, "files": files, } // 检查是否有适合客户端版本的增量更新 // 查找以客户端版本为基础版本的 patch 更新 var patchVersion model.Version err := database.DB.Where("application_id = ? AND update_type = ? AND base_version_id = ? AND status = ?", app.ID, "patch", clientVersionRecord.ID, "active"). Order("id DESC"). Preload("Files"). First(&patchVersion).Error if err == nil { // 找到了增量更新 result["is_patch"] = true result["base_version"] = clientVersion result["patch_url"] = patchVersion.FilePath result["patch_size"] = patchVersion.FileSize result["patch_hash"] = patchVersion.FileHash } response.Success(c, result) } func handleAppGetAnnouncements(c *gin.Context) { appKey := c.Param("appKey") var app model.Application if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } if service.GetApplicationDisabledStatus(app.ID) { response.Error(c, 403, "该应用已被禁用") return } var announcements []model.Announcement if err := database.DB.Where("application_id = ? AND status = ?", app.ID, "active").Order("is_top DESC, created_at DESC").Find(&announcements).Error; err != nil { response.Error(c, 500, "获取公告失败") return } result := make([]gin.H, len(announcements)) for i, a := range announcements { result[i] = gin.H{ "id": a.ID, "title": a.Title, "content": a.Content, "type": a.Type, "is_top": a.IsTop, "created_at": a.CreatedAt, } } response.Success(c, result) }