config.go 7.3 KB

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