package confg import ( "bytes" "github.com/fsnotify/fsnotify" "github.com/goccy/go-json" "github.com/spf13/viper" "go.uber.org/zap" "path/filepath" "sync" ) type RWLock interface { sync.Locker RLock() RUnlock() } type Config interface { RWLock } func WriteConf(path string, conf any) (err error) { var data []byte data, err = json.Marshal(conf) v := newViper(path) if err = v.ReadConfig(bytes.NewBuffer(data)); err != nil { return } v.SetConfigType(filepath.Ext(path)) err = v.WriteConfig() return } func ReadConf(path string, conf any) error { return updateConfig(newViper(path), conf) } func ReadConfAndWatch(path string, conf Config, up func()) (err error) { v := newViper(path) if err = updateConfig(v, conf); err != nil { return } onUpdate := func(in fsnotify.Event) { zap.L().Info("watch file", zap.Any("event", in)) if in.Name == "WRITE" { conf.Lock() defer conf.Unlock() err = updateConfig(v, conf) } if err != nil { zap.L().Error("auto update config err", zap.String("path", path), zap.Error(err)) return } if up != nil { up() } } // watch config WRITE event reread config v.OnConfigChange(onUpdate) v.WatchConfig() return } func newViper(path string) (v *viper.Viper) { v = viper.New() v.SetConfigFile(path) ext := filepath.Ext(path) v.SetConfigType(ext[1:]) return } func updateConfig(v *viper.Viper, conf any) (err error) { if err = v.ReadInConfig(); err != nil { return } if err = v.Unmarshal(conf); err != nil { return } return }