Files
engine/config/config.go

187 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package config
import (
"net"
"net/http"
"reflect"
"strings"
"time"
"go.uber.org/zap"
"m7s.live/engine/v4/log"
)
type Config map[string]any
type Second int
func (s Second) Duration() time.Duration {
return time.Duration(s) * time.Second
}
type Plugin interface {
// 可能的入参类型FirstConfig 第一次初始化配置Config 后续配置更新SE系列StateEvent流状态变化事件
OnEvent(any)
}
type TCPPlugin interface {
Plugin
ServeTCP(*net.TCPConn)
}
type HTTPPlugin interface {
Plugin
http.Handler
}
func (config Config) Unmarshal(s any) {
if s == nil {
return
}
var el reflect.Value
if v, ok := s.(reflect.Value); ok {
el = v
} else {
el = reflect.ValueOf(s)
}
if el.Kind() == reflect.Pointer {
el = el.Elem()
}
t := el.Type()
if t.Kind() == reflect.Map {
for k, v := range config {
el.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v).Convert(t.Elem()))
}
return
}
//字段映射,小写对应的大写
nameMap := make(map[string]string)
for i, j := 0, t.NumField(); i < j; i++ {
name := t.Field(i).Name
nameMap[strings.ToLower(name)] = name
}
for k, v := range config {
name, ok := nameMap[k]
if !ok {
log.Error("no config named:", k)
continue
}
// 需要被写入的字段
fv := el.FieldByName(name)
if value := reflect.ValueOf(v); value.Kind() == reflect.Slice {
l := value.Len()
s := reflect.MakeSlice(fv.Type(), l, value.Cap())
for i := 0; i < l; i++ {
fv := value.Field(i)
if fv.Type() == reflect.TypeOf(config) {
fv.FieldByName("Unmarshal").Call([]reflect.Value{s.Field(i)})
} else {
s.Field(i).Set(fv)
}
}
fv.Set(s)
} else if child, ok := v.(Config); ok {
if fv.Kind() == reflect.Map {
if fv.IsNil() {
fv.Set(reflect.MakeMap(fv.Type()))
}
}
child.Unmarshal(fv)
} else {
fv.Set(value)
}
}
}
// 覆盖配置
func (config Config) Assign(source Config) {
for k, v := range source {
switch m := config[k].(type) {
case Config:
m.Assign(v.(Config))
default:
config[k] = v
}
}
}
// 合并配置,不覆盖
func (config Config) Merge(source Config) {
for k, v := range source {
if _, ok := config[k]; !ok {
switch m := config[k].(type) {
case Config:
m.Merge(v.(Config))
default:
log.Debug("merge", zap.String("k", k), zap.Any("v", v))
config[k] = v
}
} else {
log.Debug("exist", zap.String("k", k))
}
}
}
func (config *Config) Set(key string, value any) {
if *config == nil {
*config = Config{strings.ToLower(key): value}
} else {
(*config)[strings.ToLower(key)] = value
}
}
func (config Config) Get(key string) any {
v, _ := config[strings.ToLower(key)]
return v
}
func (config Config) Has(key string) (ok bool) {
_, ok = config[strings.ToLower(key)]
return
}
func (config Config) HasChild(key string) (ok bool) {
_, ok = config[strings.ToLower(key)].(Config)
return ok
}
func (config Config) GetChild(key string) Config {
if v, ok := config[strings.ToLower(key)]; ok {
return v.(Config)
}
return nil
}
func Struct2Config(s any) (config Config) {
config = make(Config)
var t reflect.Type
var v reflect.Value
if vv, ok := s.(reflect.Value); ok {
v = vv
t = vv.Type()
} else {
t = reflect.TypeOf(s)
v = reflect.ValueOf(s)
if t.Kind() == reflect.Pointer {
v = v.Elem()
t = t.Elem()
}
}
for i, j := 0, t.NumField(); i < j; i++ {
ft := t.Field(i)
if !ft.IsExported() {
continue
}
name := strings.ToLower(ft.Name)
switch ft.Type.Kind() {
case reflect.Struct:
config[name] = Struct2Config(v.Field(i))
case reflect.Slice:
fallthrough
default:
reflect.ValueOf(config).SetMapIndex(reflect.ValueOf(name), v.Field(i))
}
}
return
}