github.com/zly-app/zapp@v1.3.3/config/watch.generic.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 "sync/atomic" 8 9 "go.uber.org/zap" 10 11 "github.com/zly-app/zapp/core" 12 "github.com/zly-app/zapp/logger" 13 ) 14 15 // 观察选项 16 type watchKeyGeneric[T any] struct { 17 keyObject *watchKeyObject 18 19 callbacks []core.ConfigWatchKeyStructCallback[T] // 必须自己管理, 因为 watchKeyObject 是通过协程调用的 callback 20 watchMx sync.Mutex // 用于锁 callback 21 22 rawData atomic.Value // 这里只保留成功解析的数据 23 data atomic.Value 24 dataType reflect.Type 25 26 initWG sync.WaitGroup 27 } 28 29 func (w *watchKeyGeneric[T]) GroupName() string { return w.keyObject.GroupName() } 30 func (w *watchKeyGeneric[T]) KeyName() string { return w.keyObject.KeyName() } 31 32 func (w *watchKeyGeneric[T]) AddCallback(callback ...core.ConfigWatchKeyStructCallback[T]) { 33 w.waitInit() 34 w.watchMx.Lock() 35 defer w.watchMx.Unlock() 36 37 items := make([]core.ConfigWatchKeyStructCallback[T], 0, len(callback)) 38 items = append(items, callback...) 39 w.callbacks = append(w.callbacks, items...) 40 41 // 立即触发 42 data := w.Get() 43 for _, fn := range callback { 44 fn(true, data, data) // 这里无法保证 data 被 callback 函数修改数据 45 } 46 } 47 48 func (w *watchKeyGeneric[T]) GetData() []byte { 49 w.waitInit() 50 data := w.rawData.Load().([]byte) 51 return data 52 } 53 54 func (w *watchKeyGeneric[T]) Get() T { 55 w.waitInit() 56 data := w.data.Load().(T) 57 return data 58 } 59 60 // 重新解析数据 61 func (w *watchKeyGeneric[T]) reset(first bool, newData []byte) error { 62 replica := reflect.New(w.dataType).Interface() 63 var err error 64 switch t := w.keyObject.Opts().StructType; t { 65 case Json: 66 err = w.keyObject.ParseJSON(replica) 67 case Yaml: 68 err = w.keyObject.ParseYaml(replica) 69 default: 70 err = fmt.Errorf("未定义的解析类型: %v", t) 71 } 72 if err != nil { 73 return fmt.Errorf("解析配置失败: %v", err) 74 } 75 76 var oldData T 77 if !first { 78 oldData = w.Get() 79 } 80 81 // 最终注入的hook 82 resultData := newData 83 var cancel bool 84 for _, hook := range resetInjectStructuredHooks { 85 if replica, resultData, cancel = hook(replica, resultData); cancel { 86 logger.Log.Warn(fmt.Sprintf( 87 "注入对象已被解析, 但是被拦截了! group: %s, key: %s, obj: %+v", 88 w.GroupName(), w.KeyName(), replica)) 89 return nil 90 } 91 } 92 93 w.data.Store(replica) 94 w.rawData.Store(resultData) 95 96 w.watchMx.Lock() 97 defer w.watchMx.Unlock() 98 for _, fn := range w.callbacks { 99 go fn(first, oldData, replica.(T)) // 这里无法保证 newData 被 callback 函数修改数据 100 } 101 return nil 102 } 103 104 func (w *watchKeyGeneric[T]) watchCallback(first bool, oldData, newData []byte) { 105 err := w.reset(first, newData) 106 if err == nil { 107 return 108 } 109 if first { 110 logger.Log.Fatal("首次解析数据失败", 111 zap.String("groupName", w.GroupName()), 112 zap.String("keyName", w.KeyName()), 113 zap.String("data", string(newData)), 114 zap.Error(err), 115 ) 116 } 117 logger.Log.Error("重置数据失败", 118 zap.String("groupName", w.GroupName()), 119 zap.String("keyName", w.KeyName()), 120 zap.String("oldData", string(oldData)), 121 zap.String("newData", string(newData)), 122 zap.Error(err), 123 ) 124 } 125 126 func (w *watchKeyGeneric[T]) init() { 127 w.initWG.Add(1) 128 go func() { 129 w.keyObject.AddCallback(w.watchCallback) // 等待app初始化完毕后, 这里底层的w会立即触发回调 130 w.initWG.Done() 131 }() 132 } 133 134 // 等待初始化 135 func (w *watchKeyGeneric[T]) waitInit() { 136 w.initWG.Wait() 137 } 138 139 func newWatchKeyStruct[T any](groupName, keyName string, opts ...core.ConfigWatchOption) core.IConfigWatchKeyStruct[T] { 140 temp := *new(T) // 消除new指针 141 vTemp := reflect.TypeOf(temp) 142 if vTemp.Kind() != reflect.Ptr { 143 logger.Log.Fatal("泛型类型必须是指针", zap.String("T", fmt.Sprintf("%T", temp))) 144 } 145 146 warp := &watchKeyGeneric[T]{ 147 keyObject: newWatchKeyObject(groupName, keyName, opts...), 148 dataType: vTemp.Elem(), // 实际结构 149 } 150 warp.init() 151 return warp 152 } 153 154 // 观察key结构化数据, 失败会fatal, 默认为json格式 155 func WatchKeyStruct[T any](groupName, keyName string, opts ...core.ConfigWatchOption) core.IConfigWatchKeyStruct[T] { 156 w := newWatchKeyStruct[T](groupName, keyName, opts...) 157 return w 158 } 159 160 // 观察json配置数据, 失败会fatal 161 func WatchJson[T any](groupName, keyName string, opts ...core.ConfigWatchOption) core.IConfigWatchKeyStruct[T] { 162 opts = append(make([]core.ConfigWatchOption, 0, len(opts)+1), opts...) 163 opts = append(opts, WithWatchStructJson()) 164 return newWatchKeyStruct[T](groupName, keyName, opts...) 165 } 166 167 // 观察yaml配置数据, 失败会fatal 168 func WatchYaml[T any](groupName, keyName string, opts ...core.ConfigWatchOption) core.IConfigWatchKeyStruct[T] { 169 opts = append(make([]core.ConfigWatchOption, 0, len(opts)+1), opts...) 170 opts = append(opts, WithWatchStructYaml()) 171 return newWatchKeyStruct[T](groupName, keyName, opts...) 172 }