feat: 配置分离
This commit is contained in:
@@ -3,7 +3,6 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -70,18 +69,23 @@ func (m *Manager) ReloadConfig() error {
|
||||
|
||||
config := &Config{
|
||||
Server: types.ServerConfig{
|
||||
Port: parseInteger(os.Getenv("PORT"), 3000),
|
||||
Host: getEnvOrDefault("HOST", "0.0.0.0"),
|
||||
ReadTimeout: parseInteger(os.Getenv("SERVER_READ_TIMEOUT"), 120),
|
||||
WriteTimeout: parseInteger(os.Getenv("SERVER_WRITE_TIMEOUT"), 1800),
|
||||
IdleTimeout: parseInteger(os.Getenv("SERVER_IDLE_TIMEOUT"), 120),
|
||||
GracefulShutdownTimeout: parseInteger(os.Getenv("SERVER_GRACEFUL_SHUTDOWN_TIMEOUT"), 60),
|
||||
Port: parseInteger(os.Getenv("PORT"), 3000),
|
||||
Host: getEnvOrDefault("HOST", "0.0.0.0"),
|
||||
// Server timeout configs now come from system settings, not environment
|
||||
// Using defaults here, will be overridden by system settings
|
||||
ReadTimeout: 120,
|
||||
WriteTimeout: 1800,
|
||||
IdleTimeout: 120,
|
||||
GracefulShutdownTimeout: 60,
|
||||
},
|
||||
OpenAI: types.OpenAIConfig{
|
||||
BaseURLs: parseArray(os.Getenv("OPENAI_BASE_URL"), []string{"https://api.openai.com"}),
|
||||
RequestTimeout: parseInteger(os.Getenv("REQUEST_TIMEOUT"), DefaultConstants.DefaultTimeout),
|
||||
ResponseTimeout: parseInteger(os.Getenv("RESPONSE_TIMEOUT"), 30),
|
||||
IdleConnTimeout: parseInteger(os.Getenv("IDLE_CONN_TIMEOUT"), 120),
|
||||
// OPENAI_BASE_URL is removed from environment config
|
||||
// Base URLs will be configured per group
|
||||
BaseURLs: []string{}, // Will be set per group
|
||||
// Timeout configs now come from system settings
|
||||
RequestTimeout: 30,
|
||||
ResponseTimeout: 30,
|
||||
IdleConnTimeout: 120,
|
||||
},
|
||||
Auth: types.AuthConfig{
|
||||
Key: os.Getenv("AUTH_KEY"),
|
||||
@@ -113,29 +117,28 @@ func (m *Manager) ReloadConfig() error {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Info("Configuration reloaded successfully")
|
||||
m.DisplayConfig()
|
||||
logrus.Info("Environment configuration reloaded successfully")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetServerConfig returns server configuration
|
||||
func (m *Manager) GetServerConfig() types.ServerConfig {
|
||||
return m.config.Server
|
||||
}
|
||||
// func (m *Manager) GetServerConfig() types.ServerConfig {
|
||||
// return m.config.Server
|
||||
// }
|
||||
|
||||
// GetOpenAIConfig returns OpenAI configuration
|
||||
func (m *Manager) GetOpenAIConfig() types.OpenAIConfig {
|
||||
config := m.config.OpenAI
|
||||
if len(config.BaseURLs) > 1 {
|
||||
// Use atomic counter for thread-safe round-robin
|
||||
index := atomic.AddUint64(&m.roundRobinCounter, 1) - 1
|
||||
config.BaseURL = config.BaseURLs[index%uint64(len(config.BaseURLs))]
|
||||
} else if len(config.BaseURLs) == 1 {
|
||||
config.BaseURL = config.BaseURLs[0]
|
||||
}
|
||||
return config
|
||||
}
|
||||
// func (m *Manager) GetOpenAIConfig() types.OpenAIConfig {
|
||||
// config := m.config.OpenAI
|
||||
// if len(config.BaseURLs) > 1 {
|
||||
// // Use atomic counter for thread-safe round-robin
|
||||
// index := atomic.AddUint64(&m.roundRobinCounter, 1) - 1
|
||||
// config.BaseURL = config.BaseURLs[index%uint64(len(config.BaseURLs))]
|
||||
// } else if len(config.BaseURLs) == 1 {
|
||||
// config.BaseURL = config.BaseURLs[0]
|
||||
// }
|
||||
// return config
|
||||
// }
|
||||
|
||||
// GetAuthConfig returns authentication configuration
|
||||
func (m *Manager) GetAuthConfig() types.AuthConfig {
|
||||
@@ -157,6 +160,51 @@ func (m *Manager) GetLogConfig() types.LogConfig {
|
||||
return m.config.Log
|
||||
}
|
||||
|
||||
// GetEffectiveServerConfig returns server configuration merged with system settings
|
||||
func (m *Manager) GetEffectiveServerConfig() types.ServerConfig {
|
||||
config := m.config.Server
|
||||
|
||||
// Merge with system settings
|
||||
settingsManager := GetSystemSettingsManager()
|
||||
systemSettings := settingsManager.GetSettings()
|
||||
|
||||
config.ReadTimeout = systemSettings.ServerReadTimeout
|
||||
config.WriteTimeout = systemSettings.ServerWriteTimeout
|
||||
config.IdleTimeout = systemSettings.ServerIdleTimeout
|
||||
config.GracefulShutdownTimeout = systemSettings.ServerGracefulShutdownTimeout
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// GetEffectiveOpenAIConfig returns OpenAI configuration merged with system settings and group config
|
||||
func (m *Manager) GetEffectiveOpenAIConfig(groupConfig map[string]any) types.OpenAIConfig {
|
||||
config := m.config.OpenAI
|
||||
|
||||
// Merge with system settings
|
||||
settingsManager := GetSystemSettingsManager()
|
||||
effectiveSettings := settingsManager.GetEffectiveConfig(groupConfig)
|
||||
|
||||
config.RequestTimeout = effectiveSettings.RequestTimeout
|
||||
config.ResponseTimeout = effectiveSettings.ResponseTimeout
|
||||
config.IdleConnTimeout = effectiveSettings.IdleConnTimeout
|
||||
|
||||
// Apply round-robin for multiple URLs if configured
|
||||
if len(config.BaseURLs) > 1 {
|
||||
index := atomic.AddUint64(&m.roundRobinCounter, 1) - 1
|
||||
config.BaseURL = config.BaseURLs[index%uint64(len(config.BaseURLs))]
|
||||
} else if len(config.BaseURLs) == 1 {
|
||||
config.BaseURL = config.BaseURLs[0]
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// GetEffectiveLogConfig returns log configuration (now uses environment config only)
|
||||
// func (m *Manager) GetEffectiveLogConfig() types.LogConfig {
|
||||
// // Log configuration is now managed via environment variables only
|
||||
// return m.config.Log
|
||||
// }
|
||||
|
||||
// Validate validates the configuration
|
||||
func (m *Manager) Validate() error {
|
||||
var validationErrors []string
|
||||
@@ -166,22 +214,6 @@ func (m *Manager) Validate() error {
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("port must be between %d-%d", DefaultConstants.MinPort, DefaultConstants.MaxPort))
|
||||
}
|
||||
|
||||
// Validate timeout
|
||||
if m.config.OpenAI.RequestTimeout < DefaultConstants.MinTimeout {
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("request timeout cannot be less than %ds", DefaultConstants.MinTimeout))
|
||||
}
|
||||
|
||||
// Validate upstream URL format
|
||||
if len(m.config.OpenAI.BaseURLs) == 0 {
|
||||
validationErrors = append(validationErrors, "at least one upstream API URL is required")
|
||||
}
|
||||
for _, baseURL := range m.config.OpenAI.BaseURLs {
|
||||
if _, err := url.Parse(baseURL); err != nil {
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("invalid upstream API URL format: %s", baseURL))
|
||||
}
|
||||
}
|
||||
|
||||
// Validate performance configuration
|
||||
if m.config.Performance.MaxConcurrentRequests < 1 {
|
||||
validationErrors = append(validationErrors, "max concurrent requests cannot be less than 1")
|
||||
}
|
||||
@@ -199,34 +231,37 @@ func (m *Manager) Validate() error {
|
||||
|
||||
// DisplayConfig displays current configuration information
|
||||
func (m *Manager) DisplayConfig() {
|
||||
serverConfig := m.GetEffectiveServerConfig()
|
||||
// openaiConfig := m.GetOpenAIConfig()
|
||||
authConfig := m.GetAuthConfig()
|
||||
corsConfig := m.GetCORSConfig()
|
||||
perfConfig := m.GetPerformanceConfig()
|
||||
logConfig := m.GetLogConfig()
|
||||
|
||||
logrus.Info("Current Configuration:")
|
||||
logrus.Infof(" Server: %s:%d", m.config.Server.Host, m.config.Server.Port)
|
||||
logrus.Infof(" Upstream URLs: %s", strings.Join(m.config.OpenAI.BaseURLs, ", "))
|
||||
logrus.Infof(" Request timeout: %ds", m.config.OpenAI.RequestTimeout)
|
||||
logrus.Infof(" Response timeout: %ds", m.config.OpenAI.ResponseTimeout)
|
||||
logrus.Infof(" Idle connection timeout: %ds", m.config.OpenAI.IdleConnTimeout)
|
||||
logrus.Infof(" Server: %s:%d", serverConfig.Host, serverConfig.Port)
|
||||
|
||||
authStatus := "disabled"
|
||||
if m.config.Auth.Enabled {
|
||||
if authConfig.Enabled {
|
||||
authStatus = "enabled"
|
||||
}
|
||||
logrus.Infof(" Authentication: %s", authStatus)
|
||||
|
||||
corsStatus := "disabled"
|
||||
if m.config.CORS.Enabled {
|
||||
if corsConfig.Enabled {
|
||||
corsStatus = "enabled"
|
||||
}
|
||||
logrus.Infof(" CORS: %s", corsStatus)
|
||||
logrus.Infof(" Max concurrent requests: %d", m.config.Performance.MaxConcurrentRequests)
|
||||
logrus.Infof(" Max concurrent requests: %d", perfConfig.MaxConcurrentRequests)
|
||||
|
||||
gzipStatus := "disabled"
|
||||
if m.config.Performance.EnableGzip {
|
||||
if perfConfig.EnableGzip {
|
||||
gzipStatus = "enabled"
|
||||
}
|
||||
logrus.Infof(" Gzip compression: %s", gzipStatus)
|
||||
|
||||
requestLogStatus := "enabled"
|
||||
if !m.config.Log.EnableRequest {
|
||||
if !logConfig.EnableRequest {
|
||||
requestLogStatus = "disabled"
|
||||
}
|
||||
logrus.Infof(" Request logging: %s", requestLogStatus)
|
||||
|
362
internal/config/system_settings.go
Normal file
362
internal/config/system_settings.go
Normal file
@@ -0,0 +1,362 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gpt-load/internal/db"
|
||||
"gpt-load/internal/models"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// SystemSettings 定义所有系统配置项
|
||||
// 使用结构体标签作为唯一事实来源
|
||||
type SystemSettings struct {
|
||||
// 负载均衡和重试配置
|
||||
BlacklistThreshold int `json:"blacklist_threshold" default:"1" desc:"Error count before blacklisting a key" validate:"min=0"`
|
||||
MaxRetries int `json:"max_retries" default:"3" desc:"Maximum retry attempts with different keys" validate:"min=0"`
|
||||
|
||||
// 服务器超时配置 (秒)
|
||||
ServerReadTimeout int `json:"server_read_timeout" default:"120" desc:"HTTP server read timeout in seconds" validate:"min=1"`
|
||||
ServerWriteTimeout int `json:"server_write_timeout" default:"1800" desc:"HTTP server write timeout in seconds" validate:"min=1"`
|
||||
ServerIdleTimeout int `json:"server_idle_timeout" default:"120" desc:"HTTP server idle timeout in seconds" validate:"min=1"`
|
||||
ServerGracefulShutdownTimeout int `json:"server_graceful_shutdown_timeout" default:"60" desc:"Graceful shutdown timeout in seconds" validate:"min=1"`
|
||||
|
||||
// 请求超时配置 (秒)
|
||||
RequestTimeout int `json:"request_timeout" default:"30" desc:"Request timeout in seconds" validate:"min=1"`
|
||||
ResponseTimeout int `json:"response_timeout" default:"30" desc:"Response timeout in seconds (TLS handshake & response header)" validate:"min=1"`
|
||||
IdleConnTimeout int `json:"idle_conn_timeout" default:"120" desc:"Idle connection timeout in seconds" validate:"min=1"`
|
||||
|
||||
// 性能配置
|
||||
// MaxConcurrentRequests int `json:"max_concurrent_requests" default:"100" desc:"Maximum number of concurrent requests" validate:"min=1"`
|
||||
|
||||
// 请求日志配置(数据库日志)
|
||||
RequestLogRetentionDays int `json:"request_log_retention_days" default:"30" desc:"Number of days to retain request logs in database" 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
|
||||
}
|
||||
|
||||
descTag := field.Tag.Get("desc")
|
||||
defaultTag := field.Tag.Get("default")
|
||||
validateTag := field.Tag.Get("validate")
|
||||
|
||||
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,
|
||||
Value: fieldValue.Interface(),
|
||||
Type: field.Type.String(),
|
||||
DefaultValue: defaultTag,
|
||||
Description: descTag,
|
||||
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 map[string]any) 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() {
|
||||
if intVal, err := interfaceToInt(val); err == nil {
|
||||
fieldValue.SetInt(int64(intVal))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(" Performance: max_concurrent=%d", sm.settings.MaxConcurrentRequests)
|
||||
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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user