|
|
@@ -0,0 +1,259 @@
|
|
|
+package config
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "one-api/common"
|
|
|
+ "reflect"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "sync"
|
|
|
+)
|
|
|
+
|
|
|
+// ConfigManager 统一管理所有配置
|
|
|
+type ConfigManager struct {
|
|
|
+ configs map[string]interface{}
|
|
|
+ mutex sync.RWMutex
|
|
|
+}
|
|
|
+
|
|
|
+var GlobalConfig = NewConfigManager()
|
|
|
+
|
|
|
+func NewConfigManager() *ConfigManager {
|
|
|
+ return &ConfigManager{
|
|
|
+ configs: make(map[string]interface{}),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Register 注册一个配置模块
|
|
|
+func (cm *ConfigManager) Register(name string, config interface{}) {
|
|
|
+ cm.mutex.Lock()
|
|
|
+ defer cm.mutex.Unlock()
|
|
|
+ cm.configs[name] = config
|
|
|
+}
|
|
|
+
|
|
|
+// Get 获取指定配置模块
|
|
|
+func (cm *ConfigManager) Get(name string) interface{} {
|
|
|
+ cm.mutex.RLock()
|
|
|
+ defer cm.mutex.RUnlock()
|
|
|
+ return cm.configs[name]
|
|
|
+}
|
|
|
+
|
|
|
+// LoadFromDB 从数据库加载配置
|
|
|
+func (cm *ConfigManager) LoadFromDB(options map[string]string) error {
|
|
|
+ cm.mutex.Lock()
|
|
|
+ defer cm.mutex.Unlock()
|
|
|
+
|
|
|
+ for name, config := range cm.configs {
|
|
|
+ prefix := name + "."
|
|
|
+ configMap := make(map[string]string)
|
|
|
+
|
|
|
+ // 收集属于此配置的所有选项
|
|
|
+ for key, value := range options {
|
|
|
+ if strings.HasPrefix(key, prefix) {
|
|
|
+ configKey := strings.TrimPrefix(key, prefix)
|
|
|
+ configMap[configKey] = value
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果找到配置项,则更新配置
|
|
|
+ if len(configMap) > 0 {
|
|
|
+ if err := updateConfigFromMap(config, configMap); err != nil {
|
|
|
+ common.SysError("failed to update config " + name + ": " + err.Error())
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// SaveToDB 将配置保存到数据库
|
|
|
+func (cm *ConfigManager) SaveToDB(updateFunc func(key, value string) error) error {
|
|
|
+ cm.mutex.RLock()
|
|
|
+ defer cm.mutex.RUnlock()
|
|
|
+
|
|
|
+ for name, config := range cm.configs {
|
|
|
+ configMap, err := configToMap(config)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ for key, value := range configMap {
|
|
|
+ dbKey := name + "." + key
|
|
|
+ if err := updateFunc(dbKey, value); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// 辅助函数:将配置对象转换为map
|
|
|
+func configToMap(config interface{}) (map[string]string, error) {
|
|
|
+ result := make(map[string]string)
|
|
|
+
|
|
|
+ val := reflect.ValueOf(config)
|
|
|
+ if val.Kind() == reflect.Ptr {
|
|
|
+ val = val.Elem()
|
|
|
+ }
|
|
|
+
|
|
|
+ if val.Kind() != reflect.Struct {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ typ := val.Type()
|
|
|
+ for i := 0; i < val.NumField(); i++ {
|
|
|
+ field := val.Field(i)
|
|
|
+ fieldType := typ.Field(i)
|
|
|
+
|
|
|
+ // 跳过未导出字段
|
|
|
+ if !fieldType.IsExported() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取json标签作为键名
|
|
|
+ key := fieldType.Tag.Get("json")
|
|
|
+ if key == "" || key == "-" {
|
|
|
+ key = fieldType.Name
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理不同类型的字段
|
|
|
+ var strValue string
|
|
|
+ switch field.Kind() {
|
|
|
+ case reflect.String:
|
|
|
+ strValue = field.String()
|
|
|
+ case reflect.Bool:
|
|
|
+ strValue = strconv.FormatBool(field.Bool())
|
|
|
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
+ strValue = strconv.FormatInt(field.Int(), 10)
|
|
|
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
+ strValue = strconv.FormatUint(field.Uint(), 10)
|
|
|
+ case reflect.Float32, reflect.Float64:
|
|
|
+ strValue = strconv.FormatFloat(field.Float(), 'f', -1, 64)
|
|
|
+ case reflect.Map, reflect.Slice, reflect.Struct:
|
|
|
+ // 复杂类型使用JSON序列化
|
|
|
+ bytes, err := json.Marshal(field.Interface())
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ strValue = string(bytes)
|
|
|
+ default:
|
|
|
+ // 跳过不支持的类型
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ result[key] = strValue
|
|
|
+ }
|
|
|
+
|
|
|
+ return result, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 辅助函数:从map更新配置对象
|
|
|
+func updateConfigFromMap(config interface{}, configMap map[string]string) error {
|
|
|
+ val := reflect.ValueOf(config)
|
|
|
+ if val.Kind() != reflect.Ptr {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ val = val.Elem()
|
|
|
+
|
|
|
+ if val.Kind() != reflect.Struct {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ typ := val.Type()
|
|
|
+ for i := 0; i < val.NumField(); i++ {
|
|
|
+ field := val.Field(i)
|
|
|
+ fieldType := typ.Field(i)
|
|
|
+
|
|
|
+ // 跳过未导出字段
|
|
|
+ if !fieldType.IsExported() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取json标签作为键名
|
|
|
+ key := fieldType.Tag.Get("json")
|
|
|
+ if key == "" || key == "-" {
|
|
|
+ key = fieldType.Name
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查map中是否有对应的值
|
|
|
+ strValue, ok := configMap[key]
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据字段类型设置值
|
|
|
+ if !field.CanSet() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ switch field.Kind() {
|
|
|
+ case reflect.String:
|
|
|
+ field.SetString(strValue)
|
|
|
+ case reflect.Bool:
|
|
|
+ boolValue, err := strconv.ParseBool(strValue)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ field.SetBool(boolValue)
|
|
|
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
+ intValue, err := strconv.ParseInt(strValue, 10, 64)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ field.SetInt(intValue)
|
|
|
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
+ uintValue, err := strconv.ParseUint(strValue, 10, 64)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ field.SetUint(uintValue)
|
|
|
+ case reflect.Float32, reflect.Float64:
|
|
|
+ floatValue, err := strconv.ParseFloat(strValue, 64)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ field.SetFloat(floatValue)
|
|
|
+ case reflect.Map, reflect.Slice, reflect.Struct:
|
|
|
+ // 复杂类型使用JSON反序列化
|
|
|
+ err := json.Unmarshal([]byte(strValue), field.Addr().Interface())
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ConfigToMap 将配置对象转换为map(导出函数)
|
|
|
+func ConfigToMap(config interface{}) (map[string]string, error) {
|
|
|
+ return configToMap(config)
|
|
|
+}
|
|
|
+
|
|
|
+// UpdateConfigFromMap 从map更新配置对象(导出函数)
|
|
|
+func UpdateConfigFromMap(config interface{}, configMap map[string]string) error {
|
|
|
+ return updateConfigFromMap(config, configMap)
|
|
|
+}
|
|
|
+
|
|
|
+// ExportAllConfigs 导出所有已注册的配置为扁平结构
|
|
|
+func (cm *ConfigManager) ExportAllConfigs() map[string]string {
|
|
|
+ cm.mutex.RLock()
|
|
|
+ defer cm.mutex.RUnlock()
|
|
|
+
|
|
|
+ result := make(map[string]string)
|
|
|
+
|
|
|
+ for name, cfg := range cm.configs {
|
|
|
+ configMap, err := ConfigToMap(cfg)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用 "模块名.配置项" 的格式添加到结果中
|
|
|
+ for key, value := range configMap {
|
|
|
+ result[name+"."+key] = value
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result
|
|
|
+}
|