config.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package conf
  2. import (
  3. "dario.cat/mergo"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "git.ikuban.com/server/yaml"
  8. "github.com/elliotchance/orderedmap/v3"
  9. "github.com/go-kratos/kratos/v2/config"
  10. "google.golang.org/protobuf/encoding/protojson"
  11. "google.golang.org/protobuf/proto"
  12. )
  13. func InitConfig(sources []Source) (*Bootstrap, error) {
  14. configSources := make([]config.Source, 0)
  15. sourceMap := orderedmap.NewOrderedMap[string, any]() // 有序map控制优先级
  16. bc := &Bootstrap{}
  17. for _, source := range sources {
  18. if !source.Validate() {
  19. continue
  20. }
  21. s, err := source.NewSource()
  22. if err != nil {
  23. return nil, fmt.Errorf("%v, new source error: %v", source.String(), err)
  24. }
  25. kvs, err := s.Load()
  26. if err != nil {
  27. return nil, fmt.Errorf("%v, source load error: %v", source.String(), err)
  28. }
  29. for _, v := range kvs {
  30. sourceMap.Set(v.Key, map[string]any{})
  31. }
  32. configSources = append(configSources, s)
  33. }
  34. if sourceMap.Len() == 0 {
  35. return nil, errors.New("config source is empty")
  36. }
  37. c := config.New(
  38. config.WithSource(configSources...),
  39. config.WithDecoder(func(kv *config.KeyValue, v map[string]interface{}) error {
  40. ok := sourceMap.Has(kv.Key)
  41. if !ok {
  42. return errors.New("unknown config key")
  43. }
  44. next := map[string]any{}
  45. err := yaml.Unmarshal(kv.Value, next)
  46. if err != nil {
  47. return err
  48. }
  49. sourceMap.Set(kv.Key, convertMap(next))
  50. merged := make(map[string]any)
  51. for c := range sourceMap.Values() {
  52. err = mergo.Merge(&merged, c, mergo.WithOverride)
  53. if err != nil {
  54. return err
  55. }
  56. }
  57. b, err := marshalJSON(merged)
  58. if err != nil {
  59. return err
  60. }
  61. err = unmarshalJSON(b, bc)
  62. if err != nil {
  63. return err
  64. }
  65. return nil
  66. }),
  67. )
  68. if err := c.Load(); err != nil {
  69. return nil, err
  70. }
  71. return bc, nil
  72. }
  73. func marshalJSON(v interface{}) ([]byte, error) {
  74. if m, ok := v.(proto.Message); ok {
  75. return protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(m)
  76. }
  77. return json.Marshal(v)
  78. }
  79. func unmarshalJSON(data []byte, v interface{}) error {
  80. if m, ok := v.(proto.Message); ok {
  81. return protojson.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(data, m)
  82. }
  83. return json.Unmarshal(data, v)
  84. }
  85. func convertMap(src interface{}) interface{} {
  86. switch m := src.(type) {
  87. case map[string]interface{}:
  88. dst := make(map[string]interface{}, len(m))
  89. for k, v := range m {
  90. dst[k] = convertMap(v)
  91. }
  92. return dst
  93. case map[interface{}]interface{}:
  94. dst := make(map[string]interface{}, len(m))
  95. for k, v := range m {
  96. dst[fmt.Sprint(k)] = convertMap(v)
  97. }
  98. return dst
  99. case []interface{}:
  100. dst := make([]interface{}, len(m))
  101. for k, v := range m {
  102. dst[k] = convertMap(v)
  103. }
  104. return dst
  105. case []byte:
  106. // there will be no binary data in the config data
  107. return string(m)
  108. default:
  109. return src
  110. }
  111. }