mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-05 08:36:56 +08:00
187 lines
3.7 KiB
Go
187 lines
3.7 KiB
Go
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
|
||
}
|