load.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package config
  2. import (
  3. "errors"
  4. "fmt"
  5. "dario.cat/mergo"
  6. "git.ikuban.com/server/yaml"
  7. "github.com/bytedance/sonic"
  8. "github.com/elliotchance/orderedmap/v3"
  9. "github.com/go-kratos/kratos/v2/config"
  10. )
  11. func Load(sources []Source, bc any) error {
  12. configSources := make([]config.Source, 0)
  13. sourceMap := orderedmap.NewOrderedMap[string, any]() // 有序map控制优先级
  14. for _, source := range sources {
  15. if !source.Validate() {
  16. continue
  17. }
  18. s, err := source.NewSource()
  19. if err != nil {
  20. return fmt.Errorf("%v, new source error: %v", source.String(), err)
  21. }
  22. kvs, err := s.Load()
  23. if err != nil {
  24. return fmt.Errorf("%v, source load error: %v", source.String(), err)
  25. }
  26. for _, v := range kvs {
  27. sourceMap.Set(v.Key, map[string]any{})
  28. }
  29. configSources = append(configSources, s)
  30. }
  31. if sourceMap.Len() == 0 {
  32. return errors.New("config source is empty")
  33. }
  34. c := config.New(
  35. config.WithSource(configSources...),
  36. config.WithDecoder(func(kv *config.KeyValue, v map[string]interface{}) error {
  37. ok := sourceMap.Has(kv.Key)
  38. if !ok {
  39. return fmt.Errorf("unknown config key,key:%s", kv.Key)
  40. }
  41. if kv.Format == "" {
  42. // 处理环境变量配置(Format 为空)
  43. // 环境变量的值已经是简单的字符串,不需要额外解析
  44. // 将环境变量值直接设置到 sourceMap 中对应键的位置
  45. // 这里需要将简单的键值对转换为嵌套结构
  46. envMap := buildNestedMap(kv.Key, string(kv.Value))
  47. sourceMap.Set(kv.Key, envMap)
  48. } else if kv.Format == Yaml.String() {
  49. next := map[string]any{}
  50. err := yaml.Unmarshal(kv.Value, next)
  51. if err != nil {
  52. return err
  53. }
  54. sourceMap.Set(kv.Key, convertMap(next))
  55. } else if kv.Format == Json.String() {
  56. next := map[string]any{}
  57. err := sonic.Unmarshal(kv.Value, &next)
  58. if err != nil {
  59. return err
  60. }
  61. sourceMap.Set(kv.Key, convertMap(next))
  62. }
  63. // 在每个配置源处理完成后,立即合并并解析到目标结构体
  64. // 这样确保配置热更新也能正常工作
  65. merged := make(map[string]any)
  66. for c := range sourceMap.Values() {
  67. err := mergo.Merge(&merged, c, mergo.WithOverride)
  68. if err != nil {
  69. return err
  70. }
  71. }
  72. // 将合并后的配置序列化为 YAML 再解析到目标结构体
  73. b, err := yaml.Marshal(merged)
  74. if err != nil {
  75. return err
  76. }
  77. err = yaml.Unmarshal(b, bc)
  78. if err != nil {
  79. return err
  80. }
  81. // 执行默认配置函数
  82. if defaultCfg != nil {
  83. defaultCfg(bc)
  84. }
  85. return nil
  86. }),
  87. )
  88. if err := c.Load(); err != nil {
  89. return err
  90. }
  91. return nil
  92. }
  93. type DefaultCfg func(bc any)
  94. var defaultCfg DefaultCfg
  95. func SetDefaultCfg(f DefaultCfg) {
  96. defaultCfg = f
  97. }
  98. func convertMap(src interface{}) interface{} {
  99. switch m := src.(type) {
  100. case map[string]interface{}:
  101. dst := make(map[string]interface{}, len(m))
  102. for k, v := range m {
  103. dst[k] = convertMap(v)
  104. }
  105. return dst
  106. case map[interface{}]interface{}:
  107. dst := make(map[interface{}]interface{}, len(m))
  108. for k, v := range m {
  109. dst[k] = convertMap(v)
  110. }
  111. return dst
  112. case []interface{}:
  113. dst := make([]interface{}, len(m))
  114. for k, v := range m {
  115. dst[k] = convertMap(v)
  116. }
  117. return dst
  118. case []byte:
  119. // there will be no binary data in the config data
  120. return string(m)
  121. default:
  122. return src
  123. }
  124. }