config.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. package conf
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "path"
  7. "reflect"
  8. "strings"
  9. "github.com/zeromicro/go-zero/core/jsonx"
  10. "github.com/zeromicro/go-zero/core/mapping"
  11. "github.com/zeromicro/go-zero/internal/encoding"
  12. )
  13. var (
  14. loaders = map[string]func([]byte, any) error{
  15. ".json": LoadFromJsonBytes,
  16. ".toml": LoadFromTomlBytes,
  17. ".yaml": LoadFromYamlBytes,
  18. ".yml": LoadFromYamlBytes,
  19. }
  20. emptyFieldInfo fieldInfo
  21. )
  22. type fieldInfo struct {
  23. children map[string]fieldInfo
  24. mapField *fieldInfo
  25. }
  26. // Load loads config into v from file, .json, .yaml and .yml are acceptable.
  27. func Load(file string, v any, opts ...Option) error {
  28. content, err := os.ReadFile(file)
  29. if err != nil {
  30. return err
  31. }
  32. loader, ok := loaders[strings.ToLower(path.Ext(file))]
  33. if !ok {
  34. return fmt.Errorf("unrecognized file type: %s", file)
  35. }
  36. var opt options
  37. for _, o := range opts {
  38. o(&opt)
  39. }
  40. if opt.env {
  41. return loader([]byte(os.ExpandEnv(string(content))), v)
  42. }
  43. return loader(content, v)
  44. }
  45. // LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable.
  46. // Deprecated: use Load instead.
  47. func LoadConfig(file string, v any, opts ...Option) error {
  48. return Load(file, v, opts...)
  49. }
  50. // LoadFromJsonBytes loads config into v from content json bytes.
  51. func LoadFromJsonBytes(content []byte, v any) error {
  52. var m map[string]any
  53. if err := jsonx.Unmarshal(content, &m); err != nil {
  54. return err
  55. }
  56. finfo, err := buildFieldsInfo(reflect.TypeOf(v))
  57. if err != nil {
  58. return err
  59. }
  60. lowerCaseKeyMap := toLowerCaseKeyMap(m, finfo)
  61. return mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toLowerCase))
  62. }
  63. // LoadConfigFromJsonBytes loads config into v from content json bytes.
  64. // Deprecated: use LoadFromJsonBytes instead.
  65. func LoadConfigFromJsonBytes(content []byte, v any) error {
  66. return LoadFromJsonBytes(content, v)
  67. }
  68. // LoadFromTomlBytes loads config into v from content toml bytes.
  69. func LoadFromTomlBytes(content []byte, v any) error {
  70. b, err := encoding.TomlToJson(content)
  71. if err != nil {
  72. return err
  73. }
  74. return LoadFromJsonBytes(b, v)
  75. }
  76. // LoadFromYamlBytes loads config into v from content yaml bytes.
  77. func LoadFromYamlBytes(content []byte, v any) error {
  78. b, err := encoding.YamlToJson(content)
  79. if err != nil {
  80. return err
  81. }
  82. return LoadFromJsonBytes(b, v)
  83. }
  84. // LoadConfigFromYamlBytes loads config into v from content yaml bytes.
  85. // Deprecated: use LoadFromYamlBytes instead.
  86. func LoadConfigFromYamlBytes(content []byte, v any) error {
  87. return LoadFromYamlBytes(content, v)
  88. }
  89. // MustLoad loads config into v from path, exits on error.
  90. func MustLoad(path string, v any, opts ...Option) {
  91. if err := Load(path, v, opts...); err != nil {
  92. log.Fatalf("error: config file %s, %s", path, err.Error())
  93. }
  94. }
  95. func addOrMergeFields(info fieldInfo, key string, child fieldInfo) error {
  96. if prev, ok := info.children[key]; ok {
  97. if len(child.children) == 0 && child.mapField == nil {
  98. return newDupKeyError(key)
  99. }
  100. // merge fields
  101. for k, v := range child.children {
  102. if _, ok = prev.children[k]; ok {
  103. return newDupKeyError(k)
  104. }
  105. prev.children[k] = v
  106. }
  107. prev.mapField = child.mapField
  108. } else {
  109. info.children[key] = child
  110. }
  111. return nil
  112. }
  113. func buildFieldsInfo(tp reflect.Type) (fieldInfo, error) {
  114. tp = mapping.Deref(tp)
  115. switch tp.Kind() {
  116. case reflect.Struct:
  117. return buildStructFieldsInfo(tp)
  118. case reflect.Array, reflect.Slice:
  119. return buildFieldsInfo(mapping.Deref(tp.Elem()))
  120. default:
  121. return emptyFieldInfo, nil
  122. }
  123. }
  124. func buildStructFieldsInfo(tp reflect.Type) (fieldInfo, error) {
  125. info := fieldInfo{
  126. children: make(map[string]fieldInfo),
  127. }
  128. for i := 0; i < tp.NumField(); i++ {
  129. field := tp.Field(i)
  130. name := field.Name
  131. lowerCaseName := toLowerCase(name)
  132. ft := mapping.Deref(field.Type)
  133. // flatten anonymous fields
  134. if field.Anonymous {
  135. switch ft.Kind() {
  136. case reflect.Struct:
  137. fields, err := buildFieldsInfo(ft)
  138. if err != nil {
  139. return emptyFieldInfo, err
  140. }
  141. for k, v := range fields.children {
  142. if err = addOrMergeFields(info, k, v); err != nil {
  143. return emptyFieldInfo, err
  144. }
  145. }
  146. info.mapField = fields.mapField
  147. case reflect.Map:
  148. elemField, err := buildFieldsInfo(mapping.Deref(ft.Elem()))
  149. if err != nil {
  150. return emptyFieldInfo, err
  151. }
  152. if _, ok := info.children[lowerCaseName]; ok {
  153. return emptyFieldInfo, newDupKeyError(lowerCaseName)
  154. }
  155. info.children[lowerCaseName] = fieldInfo{
  156. mapField: &elemField,
  157. }
  158. default:
  159. if _, ok := info.children[lowerCaseName]; ok {
  160. return emptyFieldInfo, newDupKeyError(lowerCaseName)
  161. }
  162. info.children[lowerCaseName] = fieldInfo{
  163. children: make(map[string]fieldInfo),
  164. }
  165. }
  166. continue
  167. }
  168. var finfo fieldInfo
  169. var err error
  170. switch ft.Kind() {
  171. case reflect.Struct:
  172. finfo, err = buildFieldsInfo(ft)
  173. if err != nil {
  174. return emptyFieldInfo, err
  175. }
  176. case reflect.Array, reflect.Slice:
  177. finfo, err = buildFieldsInfo(ft.Elem())
  178. if err != nil {
  179. return emptyFieldInfo, err
  180. }
  181. case reflect.Map:
  182. elemInfo, err := buildFieldsInfo(mapping.Deref(ft.Elem()))
  183. if err != nil {
  184. return emptyFieldInfo, err
  185. }
  186. finfo.mapField = &elemInfo
  187. default:
  188. finfo, err = buildFieldsInfo(ft)
  189. if err != nil {
  190. return emptyFieldInfo, err
  191. }
  192. }
  193. if err := addOrMergeFields(info, lowerCaseName, finfo); err != nil {
  194. return emptyFieldInfo, err
  195. }
  196. }
  197. return info, nil
  198. }
  199. func toLowerCase(s string) string {
  200. return strings.ToLower(s)
  201. }
  202. func toLowerCaseInterface(v any, info fieldInfo) any {
  203. switch vv := v.(type) {
  204. case map[string]any:
  205. return toLowerCaseKeyMap(vv, info)
  206. case []any:
  207. var arr []any
  208. for _, vvv := range vv {
  209. arr = append(arr, toLowerCaseInterface(vvv, info))
  210. }
  211. return arr
  212. default:
  213. return v
  214. }
  215. }
  216. func toLowerCaseKeyMap(m map[string]any, info fieldInfo) map[string]any {
  217. res := make(map[string]any)
  218. for k, v := range m {
  219. ti, ok := info.children[k]
  220. if ok {
  221. res[k] = toLowerCaseInterface(v, ti)
  222. continue
  223. }
  224. lk := toLowerCase(k)
  225. if ti, ok = info.children[lk]; ok {
  226. res[lk] = toLowerCaseInterface(v, ti)
  227. } else if info.mapField != nil {
  228. res[k] = toLowerCaseInterface(v, *info.mapField)
  229. } else {
  230. res[k] = v
  231. }
  232. }
  233. return res
  234. }
  235. type dupKeyError struct {
  236. key string
  237. }
  238. func newDupKeyError(key string) dupKeyError {
  239. return dupKeyError{key: key}
  240. }
  241. func (e dupKeyError) Error() string {
  242. return fmt.Sprintf("duplicated key %s", e.key)
  243. }