396 lines
12 KiB
Go
396 lines
12 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"gpt-load/internal/db"
|
|
"gpt-load/internal/models"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"gorm.io/datatypes"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
// SystemSettings 定义所有系统配置项
|
|
// 使用结构体标签作为唯一事实来源
|
|
type SystemSettings struct {
|
|
// 负载均衡和重试配置
|
|
BlacklistThreshold int `json:"blacklist_threshold" default:"1" name:"黑名单阈值" category:"失败重试" desc:"一个 Key 连续失败多少次后进入黑名单" validate:"min=0"`
|
|
MaxRetries int `json:"max_retries" default:"3" name:"最大重试次数" category:"失败重试" desc:"单个请求使用不同 Key 的最大重试次数" validate:"min=0"`
|
|
|
|
// 服务器超时配置 (秒)
|
|
ServerReadTimeout int `json:"server_read_timeout" default:"120" name:"读取超时" category:"服务器配置" desc:"HTTP 服务器读取超时时间(秒)" validate:"min=1"`
|
|
ServerWriteTimeout int `json:"server_write_timeout" default:"1800" name:"写入超时" category:"服务器配置" desc:"HTTP 服务器写入超时时间(秒)" validate:"min=1"`
|
|
ServerIdleTimeout int `json:"server_idle_timeout" default:"120" name:"空闲超时" category:"服务器配置" desc:"HTTP 服务器空闲超时时间(秒)" validate:"min=1"`
|
|
ServerGracefulShutdownTimeout int `json:"server_graceful_shutdown_timeout" default:"60" name:"优雅关闭超时" category:"服务器配置" desc:"服务优雅关闭的等待超时时间(秒)" validate:"min=1"`
|
|
|
|
// 请求超时配置 (秒)
|
|
RequestTimeout int `json:"request_timeout" default:"30" name:"请求超时" category:"请求配置" desc:"请求处理的总体超时时间(秒)" validate:"min=1"`
|
|
ResponseTimeout int `json:"response_timeout" default:"30" name:"响应超时" category:"请求配置" desc:"TLS 握手和响应头的超时时间(秒)" validate:"min=1"`
|
|
IdleConnTimeout int `json:"idle_conn_timeout" default:"120" name:"空闲连接超时" category:"请求配置" desc:"空闲连接的超时时间(秒)" validate:"min=1"`
|
|
|
|
// 请求日志配置(数据库日志)
|
|
RequestLogRetentionDays int `json:"request_log_retention_days" default:"30" name:"日志保留天数" category:"日志配置" desc:"请求日志在数据库中的保留天数" validate:"min=1"`
|
|
}
|
|
|
|
// GenerateSettingsMetadata 使用反射从 SystemSettings 结构体动态生成元数据
|
|
func GenerateSettingsMetadata(s *SystemSettings) []models.SystemSettingInfo {
|
|
var settingsInfo []models.SystemSettingInfo
|
|
v := reflect.ValueOf(s).Elem()
|
|
t := v.Type()
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
fieldValue := v.Field(i)
|
|
|
|
jsonTag := field.Tag.Get("json")
|
|
if jsonTag == "" {
|
|
continue
|
|
}
|
|
|
|
nameTag := field.Tag.Get("name")
|
|
descTag := field.Tag.Get("desc")
|
|
defaultTag := field.Tag.Get("default")
|
|
validateTag := field.Tag.Get("validate")
|
|
categoryTag := field.Tag.Get("category")
|
|
|
|
var minValue *int
|
|
if strings.HasPrefix(validateTag, "min=") {
|
|
valStr := strings.TrimPrefix(validateTag, "min=")
|
|
if val, err := strconv.Atoi(valStr); err == nil {
|
|
minValue = &val
|
|
}
|
|
}
|
|
|
|
info := models.SystemSettingInfo{
|
|
Key: jsonTag,
|
|
Name: nameTag,
|
|
Value: fieldValue.Interface(),
|
|
Type: field.Type.String(),
|
|
DefaultValue: defaultTag,
|
|
Description: descTag,
|
|
Category: categoryTag,
|
|
MinValue: minValue,
|
|
}
|
|
settingsInfo = append(settingsInfo, info)
|
|
}
|
|
return settingsInfo
|
|
}
|
|
|
|
// DefaultSystemSettings 返回默认的系统配置
|
|
func DefaultSystemSettings() SystemSettings {
|
|
s := SystemSettings{}
|
|
v := reflect.ValueOf(&s).Elem()
|
|
t := v.Type()
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
defaultTag := field.Tag.Get("default")
|
|
if defaultTag == "" {
|
|
continue
|
|
}
|
|
|
|
fieldValue := v.Field(i)
|
|
if fieldValue.CanSet() {
|
|
switch fieldValue.Kind() {
|
|
case reflect.Int:
|
|
if val, err := strconv.ParseInt(defaultTag, 10, 64); err == nil {
|
|
fieldValue.SetInt(val)
|
|
}
|
|
// Add cases for other types like string, bool if needed
|
|
}
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
// SystemSettingsManager 管理系统配置
|
|
type SystemSettingsManager struct {
|
|
settings SystemSettings
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
var globalSystemSettings *SystemSettingsManager
|
|
var once sync.Once
|
|
|
|
// GetSystemSettingsManager 获取全局系统配置管理器单例
|
|
func GetSystemSettingsManager() *SystemSettingsManager {
|
|
once.Do(func() {
|
|
globalSystemSettings = &SystemSettingsManager{}
|
|
})
|
|
return globalSystemSettings
|
|
}
|
|
|
|
// InitializeSystemSettings 初始化系统配置到数据库
|
|
func (sm *SystemSettingsManager) InitializeSystemSettings() error {
|
|
if db.DB == nil {
|
|
return fmt.Errorf("database not initialized")
|
|
}
|
|
|
|
defaultSettings := DefaultSystemSettings()
|
|
metadata := GenerateSettingsMetadata(&defaultSettings)
|
|
|
|
for _, meta := range metadata {
|
|
var existing models.SystemSetting
|
|
err := db.DB.Where("setting_key = ?", meta.Key).First(&existing).Error
|
|
if err != nil { // Not found
|
|
setting := models.SystemSetting{
|
|
SettingKey: meta.Key,
|
|
SettingValue: fmt.Sprintf("%v", meta.DefaultValue),
|
|
Description: meta.Description,
|
|
}
|
|
if err := db.DB.Create(&setting).Error; err != nil {
|
|
logrus.Errorf("Failed to initialize setting %s: %v", setting.SettingKey, err)
|
|
return err
|
|
}
|
|
logrus.Infof("Initialized system setting: %s = %s", setting.SettingKey, setting.SettingValue)
|
|
}
|
|
}
|
|
|
|
// 加载配置到内存
|
|
return sm.LoadFromDatabase()
|
|
}
|
|
|
|
// LoadFromDatabase 从数据库加载系统配置到内存
|
|
func (sm *SystemSettingsManager) LoadFromDatabase() error {
|
|
if db.DB == nil {
|
|
return fmt.Errorf("database not initialized")
|
|
}
|
|
|
|
var settings []models.SystemSetting
|
|
if err := db.DB.Find(&settings).Error; err != nil {
|
|
return fmt.Errorf("failed to load system settings: %w", err)
|
|
}
|
|
|
|
settingsMap := make(map[string]string)
|
|
for _, setting := range settings {
|
|
settingsMap[setting.SettingKey] = setting.SettingValue
|
|
}
|
|
|
|
sm.mu.Lock()
|
|
defer sm.mu.Unlock()
|
|
|
|
// 使用默认值,然后用数据库中的值覆盖
|
|
sm.settings = DefaultSystemSettings()
|
|
sm.mapToStruct(settingsMap, &sm.settings)
|
|
|
|
logrus.Info("System settings loaded from database")
|
|
return nil
|
|
}
|
|
|
|
// GetSettings 获取当前系统配置
|
|
func (sm *SystemSettingsManager) GetSettings() SystemSettings {
|
|
sm.mu.RLock()
|
|
defer sm.mu.RUnlock()
|
|
return sm.settings
|
|
}
|
|
|
|
// UpdateSettings 更新系统配置
|
|
func (sm *SystemSettingsManager) UpdateSettings(settingsMap map[string]string) error {
|
|
if db.DB == nil {
|
|
return fmt.Errorf("database not initialized")
|
|
}
|
|
|
|
// 验证配置项
|
|
if err := sm.ValidateSettings(settingsMap); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 更新数据库
|
|
var settingsToUpdate []models.SystemSetting
|
|
for key, value := range settingsMap {
|
|
settingsToUpdate = append(settingsToUpdate, models.SystemSetting{
|
|
SettingKey: key,
|
|
SettingValue: value,
|
|
})
|
|
}
|
|
|
|
if len(settingsToUpdate) > 0 {
|
|
if err := db.DB.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "setting_key"}},
|
|
DoUpdates: clause.AssignmentColumns([]string{"setting_value", "updated_at"}),
|
|
}).Create(&settingsToUpdate).Error; err != nil {
|
|
return fmt.Errorf("failed to update system settings: %w", err)
|
|
}
|
|
}
|
|
|
|
// 重新加载配置到内存
|
|
return sm.LoadFromDatabase()
|
|
}
|
|
|
|
// GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖)
|
|
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) SystemSettings {
|
|
sm.mu.RLock()
|
|
defer sm.mu.RUnlock()
|
|
|
|
// 从系统配置开始
|
|
effectiveConfig := sm.settings
|
|
v := reflect.ValueOf(&effectiveConfig).Elem()
|
|
t := v.Type()
|
|
|
|
// 创建一个从 json 标签到字段名的映射
|
|
jsonToField := make(map[string]string)
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
|
|
if jsonTag != "" {
|
|
jsonToField[jsonTag] = field.Name
|
|
}
|
|
}
|
|
|
|
// 应用分组配置覆盖
|
|
for key, val := range groupConfig {
|
|
if fieldName, ok := jsonToField[key]; ok {
|
|
fieldValue := v.FieldByName(fieldName)
|
|
if fieldValue.IsValid() && fieldValue.CanSet() {
|
|
switch fieldValue.Kind() {
|
|
case reflect.Int:
|
|
if intVal, err := interfaceToInt(val); err == nil {
|
|
fieldValue.SetInt(int64(intVal))
|
|
}
|
|
case reflect.String:
|
|
if strVal, ok := interfaceToString(val); ok {
|
|
fieldValue.SetString(strVal)
|
|
}
|
|
case reflect.Bool:
|
|
if boolVal, ok := interfaceToBool(val); ok {
|
|
fieldValue.SetBool(boolVal)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return effectiveConfig
|
|
}
|
|
|
|
// ValidateSettings 验证系统配置的有效性
|
|
func (sm *SystemSettingsManager) ValidateSettings(settingsMap map[string]string) error {
|
|
tempSettings := DefaultSystemSettings()
|
|
v := reflect.ValueOf(&tempSettings).Elem()
|
|
t := v.Type()
|
|
jsonToField := make(map[string]reflect.StructField)
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
jsonTag := field.Tag.Get("json")
|
|
if jsonTag != "" {
|
|
jsonToField[jsonTag] = field
|
|
}
|
|
}
|
|
|
|
for key, value := range settingsMap {
|
|
field, ok := jsonToField[key]
|
|
if !ok {
|
|
return fmt.Errorf("invalid setting key: %s", key)
|
|
}
|
|
|
|
validateTag := field.Tag.Get("validate")
|
|
if validateTag == "" {
|
|
continue
|
|
}
|
|
|
|
switch field.Type.Kind() {
|
|
case reflect.Int:
|
|
intVal, err := strconv.Atoi(value)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid integer value for %s: %s", key, value)
|
|
}
|
|
if strings.HasPrefix(validateTag, "min=") {
|
|
minValStr := strings.TrimPrefix(validateTag, "min=")
|
|
minVal, _ := strconv.Atoi(minValStr)
|
|
if intVal < minVal {
|
|
return fmt.Errorf("value for %s (%d) is below minimum value (%d)", key, intVal, minVal)
|
|
}
|
|
}
|
|
default:
|
|
return fmt.Errorf("unsupported type for setting key validation: %s", key)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DisplayCurrentSettings 显示当前系统配置信息
|
|
func (sm *SystemSettingsManager) DisplayCurrentSettings() {
|
|
sm.mu.RLock()
|
|
defer sm.mu.RUnlock()
|
|
|
|
logrus.Info("Current System Settings:")
|
|
logrus.Infof(" Blacklist threshold: %d", sm.settings.BlacklistThreshold)
|
|
logrus.Infof(" Max retries: %d", sm.settings.MaxRetries)
|
|
logrus.Infof(" Server timeouts: read=%ds, write=%ds, idle=%ds, shutdown=%ds",
|
|
sm.settings.ServerReadTimeout, sm.settings.ServerWriteTimeout,
|
|
sm.settings.ServerIdleTimeout, sm.settings.ServerGracefulShutdownTimeout)
|
|
logrus.Infof(" Request timeouts: request=%ds, response=%ds, idle_conn=%ds",
|
|
sm.settings.RequestTimeout, sm.settings.ResponseTimeout, sm.settings.IdleConnTimeout)
|
|
logrus.Infof(" Request log retention: %d days", sm.settings.RequestLogRetentionDays)
|
|
}
|
|
|
|
// 辅助方法
|
|
|
|
func (sm *SystemSettingsManager) mapToStruct(m map[string]string, s *SystemSettings) {
|
|
v := reflect.ValueOf(s).Elem()
|
|
t := v.Type()
|
|
|
|
// 创建一个从 json 标签到字段名的映射
|
|
jsonToField := make(map[string]string)
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
|
|
if jsonTag != "" {
|
|
jsonToField[jsonTag] = field.Name
|
|
}
|
|
}
|
|
|
|
for key, valStr := range m {
|
|
if fieldName, ok := jsonToField[key]; ok {
|
|
fieldValue := v.FieldByName(fieldName)
|
|
if fieldValue.IsValid() && fieldValue.CanSet() {
|
|
// 假设所有字段都是 int 类型
|
|
if intVal, err := strconv.Atoi(valStr); err == nil {
|
|
fieldValue.SetInt(int64(intVal))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 工具函数
|
|
|
|
func interfaceToInt(val interface{}) (int, error) {
|
|
switch v := val.(type) {
|
|
case int:
|
|
return v, nil
|
|
case float64:
|
|
return int(v), nil
|
|
case string:
|
|
return strconv.Atoi(v)
|
|
default:
|
|
return 0, fmt.Errorf("cannot convert to int: %v", val)
|
|
}
|
|
}
|
|
|
|
func interfaceToString(val interface{}) (string, bool) {
|
|
s, ok := val.(string)
|
|
return s, ok
|
|
}
|
|
|
|
func interfaceToBool(val interface{}) (bool, bool) {
|
|
switch v := val.(type) {
|
|
case bool:
|
|
return v, true
|
|
case string:
|
|
lowerV := strings.ToLower(v)
|
|
if lowerV == "true" || lowerV == "1" || lowerV == "on" {
|
|
return true, true
|
|
}
|
|
if lowerV == "false" || lowerV == "0" || lowerV == "off" {
|
|
return false, true
|
|
}
|
|
}
|
|
return false, false
|
|
}
|