123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package mhayaDataConfig
- import (
- "os"
- "regexp"
- "time"
- cerr "github.com/mhaya/error"
- cfile "github.com/mhaya/extend/file"
- clog "github.com/mhaya/logger"
- cprofile "github.com/mhaya/profile"
- "github.com/radovskyb/watcher"
- )
- type (
- // SourceFile 本地读取数据配置文件
- SourceFile struct {
- fileConfig
- watcher *watcher.Watcher
- changeFn ConfigChangeFn
- monitorPath string
- }
- fileConfig struct {
- FilePath string `json:"file_path"` // 配置文件路径
- ExtName string `json:"ext_name"` // 文件扩展名
- ReloadTime int64 `json:"reload_time"` // 定时重载扫描(毫秒)
- }
- )
- func (f *SourceFile) Name() string {
- return "file"
- }
- func (f *SourceFile) Init(_ IDataConfig) {
- err := f.unmarshalFileConfig()
- if err != nil {
- clog.Panicf("Unmarshal fileConfig fail. err = %v", err)
- return
- }
- f.watcher = watcher.New()
- f.watcher.FilterOps(watcher.Write)
- var regexpFilter *regexp.Regexp
- regexpFilter, err = regexp.Compile(`.*\` + f.ExtName + `$`)
- if err != nil {
- clog.Panicf("AddFilterHook extName fail. err = %v", err)
- return
- }
- f.watcher.AddFilterHook(watcher.RegexFilterHook(regexpFilter, false))
- f.monitorPath, err = cfile.JoinPath(cprofile.Path(), f.FilePath)
- if err != nil {
- clog.Panicf("[name = %s] join path fail. err = %v.", f.Name(), err)
- return
- }
- err = f.watcher.Add(f.monitorPath)
- if err != nil {
- clog.Panicf("New watcher error. path=%s, err = %v", f.monitorPath, err)
- return
- }
- // new watcher
- go f.newWatcher()
- }
- func (f *SourceFile) ReadBytes(configName string) ([]byte, error) {
- if configName == "" {
- return nil, cerr.Error("Config name is empty.")
- }
- fullPath, err := cfile.JoinPath(f.monitorPath, configName+f.ExtName)
- if err != nil {
- return nil, cerr.Errorf("Config file not found. err = %v", err)
- }
- data, err := os.ReadFile(fullPath)
- if err != nil {
- return nil, cerr.Errorf("Read file error. [path = %s, err = %v]", fullPath, err)
- }
- if len(data) < 1 {
- return nil, cerr.Errorf("Data is empty. [configName = %s]", configName)
- }
- return data, err
- }
- func (f *SourceFile) OnChange(fn ConfigChangeFn) {
- f.changeFn = fn
- }
- func (f *SourceFile) newWatcher() {
- go func() {
- for {
- select {
- case ev := <-f.watcher.Event:
- {
- if ev.IsDir() {
- continue
- }
- configName := cfile.GetFileName(ev.FileInfo.Name(), true)
- clog.Infof("Trigger file change. [name = %s]", configName)
- data, err := f.ReadBytes(configName)
- if err != nil {
- clog.Warn("Read data fail. [name = %s, err = %s]", configName, err)
- continue
- }
- if f.changeFn != nil {
- f.changeFn(configName, data)
- }
- }
- case err := <-f.watcher.Error:
- {
- clog.Error(err)
- continue
- }
- case <-f.watcher.Closed:
- return
- }
- }
- }()
- err := f.watcher.Start(time.Duration(f.ReloadTime) * time.Millisecond)
- if err != nil {
- clog.Panic(err)
- }
- }
- func (f *SourceFile) Stop() {
- if f.watcher == nil {
- return
- }
- err := f.watcher.Remove(f.monitorPath)
- clog.Infof("Remote watcher [path = %s, err = %v]", f.monitorPath, err)
- f.watcher.Close()
- }
- func (f *SourceFile) unmarshalFileConfig() error {
- //read data_config->file node
- dataConfig := cprofile.GetConfig("data_config").GetConfig(f.Name())
- err := dataConfig.Unmarshal(&f.fileConfig)
- if err != nil {
- return err
- }
- if f.ReloadTime < 1 {
- f.ReloadTime = 3000
- }
- if len(f.ExtName) < 1 {
- f.ExtName = ".json"
- }
- if len(f.FilePath) < 1 {
- f.FilePath = "data/"
- }
- return nil
- }
|