config.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package config
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "os"
  8. "reflect"
  9. "regexp"
  10. "strings"
  11. "time"
  12. "github.com/quic-go/quic-go"
  13. "gopkg.in/yaml.v3"
  14. "m7s.live/engine/v4/log"
  15. )
  16. type Config struct {
  17. Ptr reflect.Value //指向配置结构体值,优先级:动态修改值>环境变量>配置文件>defaultYaml>全局配置>默认值
  18. Modify any //动态修改的值
  19. Env any //环境变量中的值
  20. File any //配置文件中的值
  21. Global *Config //全局配置中的值,指针类型
  22. Default any //默认值
  23. Enum []struct {
  24. Label string `json:"label"`
  25. Value any `json:"value"`
  26. }
  27. name string // 小写
  28. propsMap map[string]*Config
  29. props []*Config
  30. tag reflect.StructTag
  31. }
  32. var durationType = reflect.TypeOf(time.Duration(0))
  33. var regexpType = reflect.TypeOf(Regexp{})
  34. type Plugin interface {
  35. // 可能的入参类型:FirstConfig 第一次初始化配置,Config 后续配置更新,SE系列(StateEvent)流状态变化事件
  36. OnEvent(any)
  37. }
  38. type TCPPlugin interface {
  39. Plugin
  40. ServeTCP(net.Conn)
  41. }
  42. type HTTPPlugin interface {
  43. Plugin
  44. http.Handler
  45. }
  46. type QuicPlugin interface {
  47. Plugin
  48. ServeQuic(quic.Connection)
  49. }
  50. func (config *Config) Range(f func(key string, value Config)) {
  51. if m, ok := config.GetValue().(map[string]Config); ok {
  52. for k, v := range m {
  53. f(k, v)
  54. }
  55. }
  56. }
  57. func (config *Config) IsMap() bool {
  58. _, ok := config.GetValue().(map[string]Config)
  59. return ok
  60. }
  61. func (config *Config) Get(key string) (v *Config) {
  62. if config.propsMap == nil {
  63. config.propsMap = make(map[string]*Config)
  64. }
  65. if v, ok := config.propsMap[key]; ok {
  66. return v
  67. } else {
  68. v = &Config{
  69. name: key,
  70. }
  71. config.propsMap[key] = v
  72. config.props = append(config.props, v)
  73. return v
  74. }
  75. }
  76. func (config Config) Has(key string) (ok bool) {
  77. if config.propsMap == nil {
  78. return false
  79. }
  80. _, ok = config.propsMap[strings.ToLower(key)]
  81. return ok
  82. }
  83. func (config *Config) MarshalJSON() ([]byte, error) {
  84. if config.propsMap == nil {
  85. return json.Marshal(config.GetValue())
  86. }
  87. return json.Marshal(config.propsMap)
  88. }
  89. func (config *Config) GetValue() any{
  90. return config.Ptr.Interface()
  91. }
  92. // Parse 第一步读取配置结构体的默认值
  93. func (config *Config) Parse(s any, prefix ...string) {
  94. var t reflect.Type
  95. var v reflect.Value
  96. if vv, ok := s.(reflect.Value); ok {
  97. t, v = vv.Type(), vv
  98. } else {
  99. t, v = reflect.TypeOf(s), reflect.ValueOf(s)
  100. }
  101. if t.Kind() == reflect.Pointer {
  102. t, v = t.Elem(), v.Elem()
  103. }
  104. config.Ptr = v
  105. config.Default = v.Interface()
  106. if len(prefix) > 0 { // 读取环境变量
  107. envKey := strings.Join(prefix, "_")
  108. if envValue := os.Getenv(envKey); envValue != "" {
  109. envv := config.assign(strings.ToLower(prefix[0]), envValue)
  110. config.Env = envv.Interface()
  111. config.Ptr.Set(envv)
  112. }
  113. }
  114. if t.Kind() == reflect.Struct && t != regexpType {
  115. for i, j := 0, t.NumField(); i < j; i++ {
  116. ft, fv := t.Field(i), v.Field(i)
  117. if !ft.IsExported() {
  118. continue
  119. }
  120. name := strings.ToLower(ft.Name)
  121. if tag := ft.Tag.Get("yaml"); tag != "" {
  122. if tag == "-" {
  123. continue
  124. }
  125. name, _, _ = strings.Cut(tag, ",")
  126. }
  127. prop := config.Get(name)
  128. prop.Parse(fv, append(prefix, strings.ToUpper(ft.Name))...)
  129. prop.tag = ft.Tag
  130. for _, kv := range strings.Split(ft.Tag.Get("enum"), ",") {
  131. kvs := strings.Split(kv, ":")
  132. if len(kvs) != 2 {
  133. continue
  134. }
  135. var tmp struct {
  136. Value any
  137. }
  138. yaml.Unmarshal([]byte(fmt.Sprintf("value: %s", strings.TrimSpace(kvs[0]))), &tmp)
  139. prop.Enum = append(prop.Enum, struct {
  140. Label string `json:"label"`
  141. Value any `json:"value"`
  142. }{
  143. Label: strings.TrimSpace(kvs[1]),
  144. Value: tmp.Value,
  145. })
  146. }
  147. }
  148. }
  149. }
  150. // ParseDefaultYaml 第二步读取全局配置
  151. func (config *Config) ParseGlobal(g *Config) {
  152. config.Global = g
  153. if config.propsMap != nil {
  154. for k, v := range config.propsMap {
  155. v.ParseGlobal(g.Get(k))
  156. }
  157. } else {
  158. config.Ptr.Set(g.Ptr)
  159. }
  160. }
  161. // ParseDefaultYaml 第三步读取内嵌默认配置
  162. func (config *Config) ParseDefaultYaml(defaultYaml map[string]any) {
  163. if defaultYaml == nil {
  164. return
  165. }
  166. for k, v := range defaultYaml {
  167. if config.Has(k) {
  168. if prop := config.Get(k); prop.props != nil {
  169. if v != nil {
  170. prop.ParseDefaultYaml(v.(map[string]any))
  171. }
  172. } else {
  173. dv := prop.assign(k, v)
  174. prop.Default = dv.Interface()
  175. if prop.Env == nil {
  176. prop.Ptr.Set(dv)
  177. }
  178. }
  179. }
  180. }
  181. }
  182. // ParseFile 第四步读取用户配置文件
  183. func (config *Config) ParseUserFile(conf map[string]any) {
  184. if conf == nil {
  185. return
  186. }
  187. config.File = conf
  188. for k, v := range conf {
  189. if config.Has(k) {
  190. if prop := config.Get(k); prop.props != nil {
  191. if v != nil {
  192. prop.ParseUserFile(v.(map[string]any))
  193. }
  194. } else {
  195. fv := prop.assign(k, v)
  196. prop.File = fv.Interface()
  197. if prop.Env == nil {
  198. prop.Ptr.Set(fv)
  199. }
  200. }
  201. }
  202. }
  203. }
  204. // ParseModifyFile 第五步读取动态修改配置文件
  205. func (config *Config) ParseModifyFile(conf map[string]any) {
  206. if conf == nil {
  207. return
  208. }
  209. config.Modify = conf
  210. for k, v := range conf {
  211. if config.Has(k) {
  212. if prop := config.Get(k); prop.props != nil {
  213. if v != nil {
  214. vmap := v.(map[string]any)
  215. prop.ParseModifyFile(vmap)
  216. if len(vmap) == 0 {
  217. delete(conf, k)
  218. }
  219. }
  220. } else {
  221. mv := prop.assign(k, v)
  222. v = mv.Interface()
  223. vwm := prop.valueWithoutModify()
  224. if equal(vwm, v) {
  225. delete(conf, k)
  226. if prop.Modify != nil {
  227. prop.Modify = nil
  228. prop.Ptr.Set(reflect.ValueOf(vwm))
  229. }
  230. continue
  231. }
  232. prop.Modify = v
  233. prop.Ptr.Set(mv)
  234. }
  235. }
  236. }
  237. if len(conf) == 0 {
  238. config.Modify = nil
  239. }
  240. }
  241. func (config *Config) valueWithoutModify() any {
  242. if config.Env != nil {
  243. return config.Env
  244. }
  245. if config.File != nil {
  246. return config.File
  247. }
  248. if config.Global != nil {
  249. return config.Global.GetValue()
  250. }
  251. return config.Default
  252. }
  253. func equal(vwm, v any) bool {
  254. ft := reflect.TypeOf(vwm)
  255. switch ft {
  256. case regexpType:
  257. return vwm.(Regexp).String() == v.(Regexp).String()
  258. default:
  259. switch ft.Kind() {
  260. case reflect.Slice, reflect.Array, reflect.Map:
  261. return reflect.DeepEqual(vwm, v)
  262. }
  263. return vwm == v
  264. }
  265. }
  266. func (config *Config) GetMap() map[string]any {
  267. m := make(map[string]any)
  268. for k, v := range config.propsMap {
  269. if v.props != nil {
  270. if vv := v.GetMap(); vv != nil {
  271. m[k] = vv
  272. }
  273. } else if v.GetValue() != nil {
  274. m[k] = v.GetValue()
  275. }
  276. }
  277. if len(m) > 0 {
  278. return m
  279. }
  280. return nil
  281. }
  282. var regexPureNumber = regexp.MustCompile(`^\d+$`)
  283. func (config *Config) assign(k string, v any) (target reflect.Value) {
  284. ft := config.Ptr.Type()
  285. source := reflect.ValueOf(v)
  286. switch ft {
  287. case durationType:
  288. target = reflect.New(ft).Elem()
  289. if source.Type() == durationType {
  290. target.Set(source)
  291. } else if source.IsZero() || !source.IsValid() {
  292. target.SetInt(0)
  293. } else {
  294. timeStr := source.String()
  295. if d, err := time.ParseDuration(timeStr); err == nil && !regexPureNumber.MatchString(timeStr) {
  296. target.SetInt(int64(d))
  297. } else {
  298. if Global.LogLang == "zh" {
  299. log.Errorf("%s 无效的时间值: %v 请添加单位(s,m,h,d),例如:100ms, 10s, 4m, 1h", k, source)
  300. } else {
  301. log.Errorf("%s invalid duration value: %v please add unit (s,m,h,d),eg: 100ms, 10s, 4m, 1h", k, source)
  302. }
  303. os.Exit(1)
  304. }
  305. }
  306. case regexpType:
  307. target = reflect.New(ft).Elem()
  308. regexpStr := source.String()
  309. target.Set(reflect.ValueOf(Regexp{regexp.MustCompile(regexpStr)}))
  310. default:
  311. tmpStruct := reflect.StructOf([]reflect.StructField{
  312. {
  313. Name: strings.ToUpper(k),
  314. Type: ft,
  315. },
  316. })
  317. tmpValue := reflect.New(tmpStruct)
  318. tmpByte, _ := yaml.Marshal(map[string]any{k: v})
  319. yaml.Unmarshal(tmpByte, tmpValue.Interface())
  320. target = tmpValue.Elem().Field(0)
  321. }
  322. return
  323. }