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  }