config.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. package config
  2. import (
  3. "encoding/json"
  4. "reflect"
  5. "strconv"
  6. "strings"
  7. "sync"
  8. "github.com/QuantumNous/new-api/common"
  9. )
  10. // ConfigManager 统一管理所有配置
  11. type ConfigManager struct {
  12. configs map[string]interface{}
  13. mutex sync.RWMutex
  14. }
  15. var GlobalConfig = NewConfigManager()
  16. func NewConfigManager() *ConfigManager {
  17. return &ConfigManager{
  18. configs: make(map[string]interface{}),
  19. }
  20. }
  21. // Register 注册一个配置模块
  22. func (cm *ConfigManager) Register(name string, config interface{}) {
  23. cm.mutex.Lock()
  24. defer cm.mutex.Unlock()
  25. cm.configs[name] = config
  26. }
  27. // Get 获取指定配置模块
  28. func (cm *ConfigManager) Get(name string) interface{} {
  29. cm.mutex.RLock()
  30. defer cm.mutex.RUnlock()
  31. return cm.configs[name]
  32. }
  33. // LoadFromDB 从数据库加载配置
  34. func (cm *ConfigManager) LoadFromDB(options map[string]string) error {
  35. cm.mutex.Lock()
  36. defer cm.mutex.Unlock()
  37. for name, config := range cm.configs {
  38. prefix := name + "."
  39. configMap := make(map[string]string)
  40. // 收集属于此配置的所有选项
  41. for key, value := range options {
  42. if strings.HasPrefix(key, prefix) {
  43. configKey := strings.TrimPrefix(key, prefix)
  44. configMap[configKey] = value
  45. }
  46. }
  47. // 如果找到配置项,则更新配置
  48. if len(configMap) > 0 {
  49. if err := updateConfigFromMap(config, configMap); err != nil {
  50. common.SysError("failed to update config " + name + ": " + err.Error())
  51. continue
  52. }
  53. }
  54. }
  55. return nil
  56. }
  57. // SaveToDB 将配置保存到数据库
  58. func (cm *ConfigManager) SaveToDB(updateFunc func(key, value string) error) error {
  59. cm.mutex.RLock()
  60. defer cm.mutex.RUnlock()
  61. for name, config := range cm.configs {
  62. configMap, err := configToMap(config)
  63. if err != nil {
  64. return err
  65. }
  66. for key, value := range configMap {
  67. dbKey := name + "." + key
  68. if err := updateFunc(dbKey, value); err != nil {
  69. return err
  70. }
  71. }
  72. }
  73. return nil
  74. }
  75. // 辅助函数:将配置对象转换为map
  76. func configToMap(config interface{}) (map[string]string, error) {
  77. result := make(map[string]string)
  78. val := reflect.ValueOf(config)
  79. if val.Kind() == reflect.Ptr {
  80. val = val.Elem()
  81. }
  82. if val.Kind() != reflect.Struct {
  83. return nil, nil
  84. }
  85. typ := val.Type()
  86. for i := 0; i < val.NumField(); i++ {
  87. field := val.Field(i)
  88. fieldType := typ.Field(i)
  89. // 跳过未导出字段
  90. if !fieldType.IsExported() {
  91. continue
  92. }
  93. // 获取json标签作为键名
  94. key := fieldType.Tag.Get("json")
  95. if key == "" || key == "-" {
  96. key = fieldType.Name
  97. }
  98. // 处理不同类型的字段
  99. var strValue string
  100. switch field.Kind() {
  101. case reflect.String:
  102. strValue = field.String()
  103. case reflect.Bool:
  104. strValue = strconv.FormatBool(field.Bool())
  105. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  106. strValue = strconv.FormatInt(field.Int(), 10)
  107. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  108. strValue = strconv.FormatUint(field.Uint(), 10)
  109. case reflect.Float32, reflect.Float64:
  110. strValue = strconv.FormatFloat(field.Float(), 'f', -1, 64)
  111. case reflect.Ptr:
  112. // 处理指针类型:如果非 nil,序列化指向的值
  113. if !field.IsNil() {
  114. bytes, err := json.Marshal(field.Interface())
  115. if err != nil {
  116. return nil, err
  117. }
  118. strValue = string(bytes)
  119. } else {
  120. // nil 指针序列化为 "null"
  121. strValue = "null"
  122. }
  123. case reflect.Map, reflect.Slice, reflect.Struct:
  124. // 复杂类型使用JSON序列化
  125. bytes, err := json.Marshal(field.Interface())
  126. if err != nil {
  127. return nil, err
  128. }
  129. strValue = string(bytes)
  130. default:
  131. // 跳过不支持的类型
  132. continue
  133. }
  134. result[key] = strValue
  135. }
  136. return result, nil
  137. }
  138. // 辅助函数:从map更新配置对象
  139. func updateConfigFromMap(config interface{}, configMap map[string]string) error {
  140. val := reflect.ValueOf(config)
  141. if val.Kind() != reflect.Ptr {
  142. return nil
  143. }
  144. val = val.Elem()
  145. if val.Kind() != reflect.Struct {
  146. return nil
  147. }
  148. typ := val.Type()
  149. for i := 0; i < val.NumField(); i++ {
  150. field := val.Field(i)
  151. fieldType := typ.Field(i)
  152. // 跳过未导出字段
  153. if !fieldType.IsExported() {
  154. continue
  155. }
  156. // 获取json标签作为键名
  157. key := fieldType.Tag.Get("json")
  158. if key == "" || key == "-" {
  159. key = fieldType.Name
  160. }
  161. // 检查map中是否有对应的值
  162. strValue, ok := configMap[key]
  163. if !ok {
  164. continue
  165. }
  166. // 根据字段类型设置值
  167. if !field.CanSet() {
  168. continue
  169. }
  170. switch field.Kind() {
  171. case reflect.String:
  172. field.SetString(strValue)
  173. case reflect.Bool:
  174. boolValue, err := strconv.ParseBool(strValue)
  175. if err != nil {
  176. continue
  177. }
  178. field.SetBool(boolValue)
  179. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  180. intValue, err := strconv.ParseInt(strValue, 10, 64)
  181. if err != nil {
  182. continue
  183. }
  184. field.SetInt(intValue)
  185. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  186. uintValue, err := strconv.ParseUint(strValue, 10, 64)
  187. if err != nil {
  188. continue
  189. }
  190. field.SetUint(uintValue)
  191. case reflect.Float32, reflect.Float64:
  192. floatValue, err := strconv.ParseFloat(strValue, 64)
  193. if err != nil {
  194. continue
  195. }
  196. field.SetFloat(floatValue)
  197. case reflect.Ptr:
  198. // 处理指针类型
  199. if strValue == "null" {
  200. field.Set(reflect.Zero(field.Type()))
  201. } else {
  202. // 如果指针是 nil,需要先初始化
  203. if field.IsNil() {
  204. field.Set(reflect.New(field.Type().Elem()))
  205. }
  206. // 反序列化到指针指向的值
  207. err := json.Unmarshal([]byte(strValue), field.Interface())
  208. if err != nil {
  209. continue
  210. }
  211. }
  212. case reflect.Map, reflect.Slice, reflect.Struct:
  213. // 复杂类型使用JSON反序列化
  214. err := json.Unmarshal([]byte(strValue), field.Addr().Interface())
  215. if err != nil {
  216. continue
  217. }
  218. }
  219. }
  220. return nil
  221. }
  222. // ConfigToMap 将配置对象转换为map(导出函数)
  223. func ConfigToMap(config interface{}) (map[string]string, error) {
  224. return configToMap(config)
  225. }
  226. // UpdateConfigFromMap 从map更新配置对象(导出函数)
  227. func UpdateConfigFromMap(config interface{}, configMap map[string]string) error {
  228. return updateConfigFromMap(config, configMap)
  229. }
  230. // ExportAllConfigs 导出所有已注册的配置为扁平结构
  231. func (cm *ConfigManager) ExportAllConfigs() map[string]string {
  232. cm.mutex.RLock()
  233. defer cm.mutex.RUnlock()
  234. result := make(map[string]string)
  235. for name, cfg := range cm.configs {
  236. configMap, err := ConfigToMap(cfg)
  237. if err != nil {
  238. continue
  239. }
  240. // 使用 "模块名.配置项" 的格式添加到结果中
  241. for key, value := range configMap {
  242. result[name+"."+key] = value
  243. }
  244. }
  245. return result
  246. }