feat: 新增启动参数设置页面,区分 desktop 可编辑与 server 只读
This commit is contained in:
223
backend/internal/handler/settings_handler.go
Normal file
223
backend/internal/handler/settings_handler.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"nex/backend/internal/config"
|
||||
appErrors "nex/backend/pkg/errors"
|
||||
)
|
||||
|
||||
type SettingsHandler struct {
|
||||
runtimeCfg *config.Config
|
||||
mode string
|
||||
editable bool
|
||||
configPath string
|
||||
}
|
||||
|
||||
func NewSettingsHandler(runtimeCfg *config.Config, mode string, editable bool, configPath string) *SettingsHandler {
|
||||
return &SettingsHandler{
|
||||
runtimeCfg: runtimeCfg,
|
||||
mode: mode,
|
||||
editable: editable,
|
||||
configPath: configPath,
|
||||
}
|
||||
}
|
||||
|
||||
type serverConfigDTO struct {
|
||||
Port int `json:"port"`
|
||||
ReadTimeout string `json:"read_timeout"`
|
||||
WriteTimeout string `json:"write_timeout"`
|
||||
}
|
||||
|
||||
type databaseConfigDTO struct {
|
||||
Driver string `json:"driver"`
|
||||
Path string `json:"path"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
DBName string `json:"dbname"`
|
||||
MaxIdleConns int `json:"max_idle_conns"`
|
||||
MaxOpenConns int `json:"max_open_conns"`
|
||||
ConnMaxLifetime string `json:"conn_max_lifetime"`
|
||||
}
|
||||
|
||||
type logConfigDTO struct {
|
||||
Level string `json:"level"`
|
||||
Path string `json:"path"`
|
||||
MaxSize int `json:"max_size"`
|
||||
MaxBackups int `json:"max_backups"`
|
||||
MaxAge int `json:"max_age"`
|
||||
Compress bool `json:"compress"`
|
||||
}
|
||||
|
||||
type startupSettingsDTO struct {
|
||||
Server serverConfigDTO `json:"server"`
|
||||
Database databaseConfigDTO `json:"database"`
|
||||
Log logConfigDTO `json:"log"`
|
||||
}
|
||||
|
||||
type startupSettingsResponse struct {
|
||||
Mode string `json:"mode"`
|
||||
Editable bool `json:"editable"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
RestartRequired bool `json:"restart_required"`
|
||||
Config startupSettingsDTO `json:"config"`
|
||||
}
|
||||
|
||||
func configToDTO(cfg *config.Config) startupSettingsDTO {
|
||||
return startupSettingsDTO{
|
||||
Server: serverConfigDTO{
|
||||
Port: cfg.Server.Port,
|
||||
ReadTimeout: cfg.Server.ReadTimeout.String(),
|
||||
WriteTimeout: cfg.Server.WriteTimeout.String(),
|
||||
},
|
||||
Database: databaseConfigDTO{
|
||||
Driver: cfg.Database.Driver,
|
||||
Path: cfg.Database.Path,
|
||||
Host: cfg.Database.Host,
|
||||
Port: cfg.Database.Port,
|
||||
User: cfg.Database.User,
|
||||
Password: cfg.Database.Password,
|
||||
DBName: cfg.Database.DBName,
|
||||
MaxIdleConns: cfg.Database.MaxIdleConns,
|
||||
MaxOpenConns: cfg.Database.MaxOpenConns,
|
||||
ConnMaxLifetime: cfg.Database.ConnMaxLifetime.String(),
|
||||
},
|
||||
Log: logConfigDTO{
|
||||
Level: cfg.Log.Level,
|
||||
Path: cfg.Log.Path,
|
||||
MaxSize: cfg.Log.MaxSize,
|
||||
MaxBackups: cfg.Log.MaxBackups,
|
||||
MaxAge: cfg.Log.MaxAge,
|
||||
Compress: cfg.Log.Compress,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dtoToConfig(dto startupSettingsDTO) (*config.Config, error) {
|
||||
readTimeout, err := time.ParseDuration(dto.Server.ReadTimeout)
|
||||
if err != nil {
|
||||
return nil, appErrors.WithMessage(appErrors.ErrInvalidRequest, "read_timeout 格式错误,例如 30s")
|
||||
}
|
||||
writeTimeout, err := time.ParseDuration(dto.Server.WriteTimeout)
|
||||
if err != nil {
|
||||
return nil, appErrors.WithMessage(appErrors.ErrInvalidRequest, "write_timeout 格式错误,例如 30s")
|
||||
}
|
||||
connMaxLifetime, err := time.ParseDuration(dto.Database.ConnMaxLifetime)
|
||||
if err != nil {
|
||||
return nil, appErrors.WithMessage(appErrors.ErrInvalidRequest, "conn_max_lifetime 格式错误,例如 1h")
|
||||
}
|
||||
|
||||
return &config.Config{
|
||||
Server: config.ServerConfig{
|
||||
Port: dto.Server.Port,
|
||||
ReadTimeout: readTimeout,
|
||||
WriteTimeout: writeTimeout,
|
||||
},
|
||||
Database: config.DatabaseConfig{
|
||||
Driver: dto.Database.Driver,
|
||||
Path: dto.Database.Path,
|
||||
Host: dto.Database.Host,
|
||||
Port: dto.Database.Port,
|
||||
User: dto.Database.User,
|
||||
Password: dto.Database.Password,
|
||||
DBName: dto.Database.DBName,
|
||||
MaxIdleConns: dto.Database.MaxIdleConns,
|
||||
MaxOpenConns: dto.Database.MaxOpenConns,
|
||||
ConnMaxLifetime: connMaxLifetime,
|
||||
},
|
||||
Log: config.LogConfig{
|
||||
Level: dto.Log.Level,
|
||||
Path: dto.Log.Path,
|
||||
MaxSize: dto.Log.MaxSize,
|
||||
MaxBackups: dto.Log.MaxBackups,
|
||||
MaxAge: dto.Log.MaxAge,
|
||||
Compress: dto.Log.Compress,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) GetStartupSettings(c *gin.Context) {
|
||||
var cfg *config.Config
|
||||
var configPath string
|
||||
|
||||
if h.mode == "desktop" {
|
||||
desktopCfg, err := config.LoadDesktopConfigAtPath(h.configPath)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
cfg = desktopCfg
|
||||
configPath = h.configPath
|
||||
} else {
|
||||
cfg = h.runtimeCfg
|
||||
configPath = h.configPath
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, startupSettingsResponse{
|
||||
Mode: h.mode,
|
||||
Editable: h.editable,
|
||||
ConfigPath: configPath,
|
||||
RestartRequired: h.editable,
|
||||
Config: configToDTO(cfg),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) SaveStartupSettings(c *gin.Context) {
|
||||
if !h.editable {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "server 模式下不允许保存启动参数",
|
||||
"code": "forbidden",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Config startupSettingsDTO `json:"config"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "无效的请求格式",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := dtoToConfig(req.Config)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := cfg.Validate(); err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := config.SaveConfigToPath(cfg, h.configPath); err != nil {
|
||||
if errors.Is(err, appErrors.ErrInvalidRequest) {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeError(c, appErrors.Wrap(appErrors.ErrInternal, err))
|
||||
return
|
||||
}
|
||||
|
||||
savedCfg, err := config.LoadDesktopConfigAtPath(h.configPath)
|
||||
if err != nil {
|
||||
writeError(c, appErrors.Wrap(appErrors.ErrInternal, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, startupSettingsResponse{
|
||||
Mode: h.mode,
|
||||
Editable: h.editable,
|
||||
ConfigPath: h.configPath,
|
||||
RestartRequired: true,
|
||||
Config: configToDTO(savedCfg),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user