package server import ( "runtime" "syscall" "time" "kra/internal/biz" "kra/internal/conf" "kra/internal/service" "kra/internal/worker" "github.com/gin-gonic/gin" "github.com/shirou/gopsutil/v4/cpu" "github.com/shirou/gopsutil/v4/mem" "google.golang.org/protobuf/proto" ) func registerSystemConfigRoutes(group *gin.RouterGroup, config *conf.AdminBackend, systemService *service.SystemService, settings *service.SettingsService, scheduler *worker.TaskScheduler) { security := group.Group("/securityConfig") security.GET("/getSecurityConfig", func(c *gin.Context) { value, err := settings.Security(c.Request.Context()) if err != nil { fail(c, "获取安全配置失败") return } writeResult(c, codeSuccess, value, "获取成功") }) security.POST("/setSecurityConfig", func(c *gin.Context) { var value biz.SecurityConfig if c.ShouldBindJSON(&value) != nil { fail(c, "参数错误") return } result, err := settings.SaveSecurity(c.Request.Context(), &value) if err != nil { fail(c, err.Error()) return } writeResult(c, codeSuccess, result, "设置成功") }) system := group.Group("/system") system.POST("/getSystemConfig", func(c *gin.Context) { admin := gin.H{"routerPrefix": ""} email := gin.H{} if config != nil { admin["routerPrefix"] = config.RouterPrefix if config.Jwt != nil { admin["jwt"] = gin.H{"signingKey": "******", "expiresTime": config.Jwt.ExpiresTime.AsDuration().String(), "bufferTime": config.Jwt.BufferTime.AsDuration().String(), "issuer": config.Jwt.Issuer} } if config.Captcha != nil { admin["captcha"] = gin.H{"keyLong": config.Captcha.KeyLong, "imgWidth": config.Captcha.ImgWidth, "imgHeight": config.Captcha.ImgHeight, "storeExpiration": config.Captcha.StoreExpiration.AsDuration().String()} } if config.Local != nil { admin["local"] = gin.H{"storePath": config.Local.StorePath, "pathPrefix": config.Local.PathPrefix} } if config.Media != nil { admin["media"] = gin.H{"sessionTtl": config.Media.SessionTtl} } if config.Email != nil { email = gin.H{"to": config.Email.To, "from": config.Email.From, "host": config.Email.Host, "secret": "******", "nickname": config.Email.Nickname, "port": config.Email.Port, "is-ssl": config.Email.IsSsl, "is-loginauth": config.Email.IsLoginAuth} } if config.Storage != nil { storage := proto.Clone(config.Storage).(*conf.AdminBackend_Storage) maskStorageSecrets(storage) admin["storage"] = storage } } writeResult(c, codeSuccess, gin.H{"config": gin.H{"admin": admin, "email": email}}, "获取成功") }) system.POST("/setSystemConfig", func(c *gin.Context) { var req struct { Config struct { Admin struct { RouterPrefix string `json:"routerPrefix"` JWT struct { SigningKey string `json:"signingKey"` Issuer string `json:"issuer"` } `json:"jwt"` Local struct { StorePath string `json:"storePath"` PathPrefix string `json:"pathPrefix"` } `json:"local"` Media struct { SessionTTL int32 `json:"sessionTtl"` } `json:"media"` Storage *conf.AdminBackend_Storage `json:"storage"` } `json:"admin"` Email *struct { To string `json:"to"` From string `json:"from"` Host string `json:"host"` Secret string `json:"secret"` Nickname string `json:"nickname"` Port int32 `json:"port"` IsSSL bool `json:"is-ssl"` IsLoginAuth bool `json:"is-loginauth"` } `json:"email"` } `json:"config"` } if c.ShouldBindJSON(&req) != nil { fail(c, "参数错误") return } if config != nil { next := proto.Clone(config).(*conf.AdminBackend) next.RouterPrefix = req.Config.Admin.RouterPrefix if next.Jwt != nil { if req.Config.Admin.JWT.SigningKey != "" && req.Config.Admin.JWT.SigningKey != "******" { next.Jwt.SigningKey = req.Config.Admin.JWT.SigningKey } if req.Config.Admin.JWT.Issuer != "" { next.Jwt.Issuer = req.Config.Admin.JWT.Issuer } } if next.Local != nil { if req.Config.Admin.Local.StorePath != "" { next.Local.StorePath = req.Config.Admin.Local.StorePath } if req.Config.Admin.Local.PathPrefix != "" { next.Local.PathPrefix = req.Config.Admin.Local.PathPrefix } } if next.Media != nil && req.Config.Admin.Media.SessionTTL > 0 { next.Media.SessionTtl = req.Config.Admin.Media.SessionTTL } if req.Config.Admin.Storage != nil { preserveStorageSecrets(req.Config.Admin.Storage, next.Storage) next.Storage = req.Config.Admin.Storage } if next.Email != nil && req.Config.Email != nil { next.Email.To = req.Config.Email.To next.Email.From = req.Config.Email.From next.Email.Host = req.Config.Email.Host next.Email.Nickname = req.Config.Email.Nickname next.Email.Port = req.Config.Email.Port next.Email.IsSsl = req.Config.Email.IsSSL next.Email.IsLoginAuth = req.Config.Email.IsLoginAuth if req.Config.Email.Secret != "" && req.Config.Email.Secret != "******" { next.Email.Secret = req.Config.Email.Secret } } if err := systemService.PersistAdminConfig(c.Request.Context(), next); err != nil { fail(c, "配置保存失败: "+err.Error()) return } } writeResult(c, codeSuccess, gin.H{}, "设置成功") }) system.POST("/reloadSystem", func(c *gin.Context) { if err := systemService.ReloadConfig(c.Request.Context()); err != nil { fail(c, "重载系统失败:"+err.Error()) return } if err := scheduler.Reload(c.Request.Context()); err != nil { fail(c, "系统配置已重载,但定时任务重载失败:"+err.Error()) return } writeResult(c, codeSuccess, gin.H{}, "重载系统成功") }) system.POST("/getServerInfo", func(c *gin.Context) { cpuPercent, _ := cpu.Percent(200*time.Millisecond, false) memory, _ := mem.VirtualMemory() disk := []gin.H{} var stat syscall.Statfs_t if syscall.Statfs(".", &stat) == nil { total := uint64(stat.Blocks) * uint64(stat.Bsize) free := uint64(stat.Bavail) * uint64(stat.Bsize) used := total - free percent := 0 if total > 0 { percent = int(used * 100 / total) } disk = append(disk, gin.H{"mountPoint": ".", "usedMb": used / 1024 / 1024, "usedGb": used / 1024 / 1024 / 1024, "totalMb": total / 1024 / 1024, "totalGb": total / 1024 / 1024 / 1024, "usedPercent": percent}) } usedMB, totalMB, memoryPercent := uint64(0), uint64(0), float64(0) if memory != nil { usedMB, totalMB, memoryPercent = memory.Used/1024/1024, memory.Total/1024/1024, memory.UsedPercent } server := gin.H{"os": gin.H{"goos": runtime.GOOS, "numCpu": runtime.NumCPU(), "compiler": runtime.Compiler, "goVersion": runtime.Version(), "numGoroutine": runtime.NumGoroutine()}, "cpu": gin.H{"cpus": cpuPercent, "cores": runtime.NumCPU()}, "ram": gin.H{"usedMb": usedMB, "totalMb": totalMB, "usedPercent": memoryPercent}, "disk": disk} writeResult(c, codeSuccess, gin.H{"server": server}, "获取成功") }) } func objectStores(storage *conf.AdminBackend_Storage) []*conf.AdminBackend_ObjectStore { if storage == nil { return nil } return []*conf.AdminBackend_ObjectStore{storage.AliyunOss, storage.HuaweiObs, storage.TencentCos, storage.AwsS3, storage.CloudflareR2, storage.Minio} } func maskStorageSecrets(storage *conf.AdminBackend_Storage) { if storage.Qiniu != nil { storage.Qiniu.SecretKey = "******" } for _, item := range objectStores(storage) { if item != nil { item.SecretKey = "******" } } } func preserveStorageSecrets(next, current *conf.AdminBackend_Storage) { if next == nil || current == nil { return } if next.Qiniu != nil && current.Qiniu != nil && (next.Qiniu.SecretKey == "" || next.Qiniu.SecretKey == "******") { next.Qiniu.SecretKey = current.Qiniu.SecretKey } nextItems, currentItems := objectStores(next), objectStores(current) for i := range nextItems { if nextItems[i] != nil && currentItems[i] != nil && (nextItems[i].SecretKey == "" || nextItems[i].SecretKey == "******") { nextItems[i].SecretKey = currentItems[i].SecretKey } } }