224 lines
5.9 KiB
Go
224 lines
5.9 KiB
Go
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),
|
|
})
|
|
}
|