Files
gemini-banlancer/internal/settings/manager.go
2025-11-20 12:24:05 +08:00

108 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Filename: internal/settings/manager.go
package settings
import (
"encoding/json"
"fmt"
"gemini-balancer/internal/models"
"gemini-balancer/internal/pkg/reflectutil"
"reflect"
"time"
)
// ========= 便利的读取器 (Convenience Accessors) =========
func (sm *SettingsManager) IsIPBanEnabled() bool {
return sm.GetSettings().EnableIPBanning
}
func (sm *SettingsManager) GetMaxLoginAttempts() int {
return sm.GetSettings().MaxLoginAttempts
}
func (sm *SettingsManager) GetIPBanDuration() time.Duration {
minutes := sm.GetSettings().IPBanDurationMinutes
return time.Duration(minutes) * time.Minute
}
// GetSettingsCopy 返回当前系统设置的一个值副本,确保线程安全。
func (sm *SettingsManager) GetSettingsCopy() models.SystemSettings {
// 从 syncer 获取当前的设置指针
currentSettingsPtr := sm.GetSettings()
if currentSettingsPtr == nil {
// 在 syncer 初始化完成前,返回一个安全的默认值
return *defaultSystemSettings()
}
// 返回指针指向的值Go会自动创建一个副本
return *currentSettingsPtr
}
// ========= 辅助与调试函数 (Helpers & Debugging) =========
// [ DisplaySettings 现在接收一个参数,以便在加载后立即打印
func (sm *SettingsManager) DisplaySettings(settings *models.SystemSettings) {
if settings == nil {
sm.logger.Warn("Cannot display settings, current settings object is nil.")
return
}
sm.logger.Info("")
sm.logger.Info("========= Runtime System Settings (from SettingsManager) =========")
sm.logger.Infof(" - Request Timeout: %d seconds", settings.RequestTimeoutSeconds)
sm.logger.Infof(" - Connect Timeout: %d seconds", settings.ConnectTimeoutSeconds)
sm.logger.Infof(" - Max Retries: %d", settings.MaxRetries)
sm.logger.Infof(" - Blacklist Threshold: %d", settings.BlacklistThreshold)
sm.logger.Info("==================================================================")
sm.logger.Info("")
}
// defaultSystemSettings
func defaultSystemSettings() *models.SystemSettings {
settings := &models.SystemSettings{}
settings.CustomHeaders = make(map[string]string)
v := reflect.ValueOf(settings).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldValue := v.Field(i)
// 我们只对“简单组织”动刀
kind := fieldValue.Kind()
if kind == reflect.Int || kind == reflect.Int64 || kind == reflect.String || kind == reflect.Bool {
defaultValue := field.Tag.Get("default")
if defaultValue != "" {
if err := reflectutil.SetFieldFromString(fieldValue, defaultValue); err != nil {
panic(fmt.Sprintf("FATAL: Invalid default tag for primitive field %s ('%s'): %v", field.Name, defaultValue, err))
}
}
}
}
return settings
}
// parseAndSetField “扫描”数据库字符串并将其“开箱”到正确的Go类型中
func parseAndSetField(fieldValue reflect.Value, dbValue string) error {
if !fieldValue.CanSet() {
return fmt.Errorf("field is not settable")
}
// 如果数据库值为空我们不进行任何操作以保留defaultSystemSettings设置的默认值
if dbValue == "" {
return nil
}
kind := fieldValue.Kind()
switch kind {
case reflect.Slice, reflect.Map:
// 如果是 slice 或 map我们就用“开箱器 (json.Unmarshal)”
// fieldValue.Addr().Interface() 获取到的是指向该字段的指针正是Unmarshal所需要的
return json.Unmarshal([]byte(dbValue), fieldValue.Addr().Interface())
default:
// 对于所有原始类型,我们信任并复用现有的 reflectutil 工具
return reflectutil.SetFieldFromString(fieldValue, dbValue)
}
}
// Stop 优雅地停止SettingsManager的后台syncer。
func (sm *SettingsManager) Stop() {
if sm.syncer != nil {
sm.logger.Info("Stopping SettingsManager's syncer...")
sm.syncer.Stop()
}
}