config.go 6.9 KB

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