Files
mengyaping/mengyaping-backend/storage/app_config.go
2026-05-16 19:03:32 +08:00

162 lines
3.9 KiB
Go

package storage
import (
"encoding/json"
"fmt"
"log"
"time"
"mengyaping-backend/config"
)
const (
kvKeyServer = "cfg_server"
kvKeyMonitor = "cfg_monitor"
kvKeyDataPath = "cfg_data_path"
kvKeyDatabase = "cfg_database"
)
type monitorKVPayload struct {
IntervalMinutes int `json:"interval_minutes"`
TimeoutSeconds int `json:"timeout_seconds"`
RetryCount int `json:"retry_count"`
HistoryDays int `json:"history_days"`
}
func (s *Storage) getKVRaw(key string) string {
var row MonitorKV
s.db.Where("cfg_key = ?", key).Limit(1).Find(&row)
if row.CfgKey == "" {
return ""
}
return row.CfgValue
}
func (s *Storage) setKVRaw(key, val string) error {
var row MonitorKV
s.db.Where("cfg_key = ?", key).Limit(1).Find(&row)
if row.CfgKey == "" {
return s.db.Create(&MonitorKV{CfgKey: key, CfgValue: val}).Error
}
row.CfgValue = val
return s.db.Save(&row).Error
}
// loadAndSyncAppConfig 从 monitor_kv 覆盖内存配置,再写回全量(补全缺省键、统一格式)
func (s *Storage) loadAndSyncAppConfig() {
cfg := config.GetConfig()
if v := s.getKVRaw(kvKeyServer); v != "" {
var sc config.ServerConfig
if err := json.Unmarshal([]byte(v), &sc); err != nil {
log.Printf("解析 %s: %v", kvKeyServer, err)
} else {
if sc.Port != "" {
cfg.Server.Port = sc.Port
}
if sc.Host != "" {
cfg.Server.Host = sc.Host
}
}
}
if v := s.getKVRaw(kvKeyMonitor); v != "" {
var m monitorKVPayload
if err := json.Unmarshal([]byte(v), &m); err != nil {
log.Printf("解析 %s: %v", kvKeyMonitor, err)
} else {
if m.IntervalMinutes > 0 {
snapped := config.SnapMonitorIntervalMinutes(m.IntervalMinutes)
cfg.Monitor.Interval = time.Duration(snapped) * time.Minute
}
if m.TimeoutSeconds > 0 {
cfg.Monitor.Timeout = time.Duration(m.TimeoutSeconds) * time.Second
}
if m.RetryCount > 0 {
cfg.Monitor.RetryCount = m.RetryCount
}
if m.HistoryDays > 0 {
cfg.Monitor.HistoryDays = m.HistoryDays
}
}
}
if v := s.getKVRaw(kvKeyDataPath); v != "" {
cfg.DataPath = v
}
if v := s.getKVRaw(kvKeyDatabase); v != "" {
var dc config.DatabaseConfig
if err := json.Unmarshal([]byte(v), &dc); err != nil {
log.Printf("解析 %s: %v", kvKeyDatabase, err)
} else {
if dc.Host != "" {
cfg.Database.Host = dc.Host
}
if dc.Port != "" {
cfg.Database.Port = dc.Port
}
if dc.User != "" {
cfg.Database.User = dc.User
}
if dc.Password != "" {
cfg.Database.Password = dc.Password
}
if dc.Database != "" {
cfg.Database.Database = dc.Database
}
}
}
if err := s.PersistAppConfig(); err != nil {
log.Printf("同步应用配置到 monitor_kv: %v", err)
}
}
// PersistAppConfig 将当前内存中的 server/monitor/data_path/database 写入 monitor_kv
func (s *Storage) PersistAppConfig() error {
cfg := config.GetConfig()
b, err := json.Marshal(cfg.Server)
if err != nil {
return err
}
if err := s.setKVRaw(kvKeyServer, string(b)); err != nil {
return err
}
m := monitorKVPayload{
IntervalMinutes: config.SnapMonitorIntervalMinutes(int(cfg.Monitor.Interval / time.Minute)),
TimeoutSeconds: int(cfg.Monitor.Timeout.Seconds()),
RetryCount: cfg.Monitor.RetryCount,
HistoryDays: cfg.Monitor.HistoryDays,
}
b, err = json.Marshal(m)
if err != nil {
return err
}
if err := s.setKVRaw(kvKeyMonitor, string(b)); err != nil {
return err
}
if err := s.setKVRaw(kvKeyDataPath, cfg.DataPath); err != nil {
return err
}
b, err = json.Marshal(cfg.Database)
if err != nil {
return err
}
return s.setKVRaw(kvKeyDatabase, string(b))
}
// SetMonitorIntervalMinutes 更新检测周期并写入 monitor_kv
func (s *Storage) SetMonitorIntervalMinutes(minutes int) error {
if !config.IsAllowedMonitorInterval(minutes) {
return fmt.Errorf("interval_minutes 必须是预设值之一: %v", config.AllowedMonitorIntervalMinutes)
}
cfg := config.GetConfig()
cfg.Monitor.Interval = time.Duration(minutes) * time.Minute
return s.PersistAppConfig()
}