package configure import ( "fmt" "go_dreamfactory/lego/sys/log" "io/fs" "io/ioutil" "os" "path" "reflect" "sync" "time" jsoniter "github.com/json-iterator/go" ) var typeOfIn = reflect.TypeOf(([]map[string]interface{})(nil)).Elem() var typeOfError = reflect.TypeOf((*error)(nil)).Elem() type configurehandle struct { configureType reflect.Type fn reflect.Value } func newSys(options Options) (sys *Configure, err error) { sys = &Configure{ options: options, closeSignal: make(chan struct{}), configurehandles: make(map[string]*configurehandle), configure: make(map[string]interface{}), fileinfos: make(map[string]*FileInfo), } return } type Configure struct { options Options closeSignal chan struct{} hlock sync.RWMutex configurehandles map[string]*configurehandle clock sync.RWMutex configure map[string]interface{} fileinfos map[string]*FileInfo } func (this *Configure) Start() (err error) { tc := time.NewTicker(time.Second * time.Duration(this.options.CheckInterval)) go func() { locp: for { select { case <-this.closeSignal: break locp case <-tc.C: this.checkConfigure() } } }() return } func (this *Configure) Stop() (err error) { this.closeSignal <- struct{}{} return } //加载配置文件 func (this *Configure) RegisterConfigure(name string, fn interface{}) (err error) { this.hlock.RLock() _, ok := this.configurehandles[name] this.hlock.RUnlock() if ok { err = fmt.Errorf("重复 注册配置【%s】", name) return } fnvalue := reflect.ValueOf(fn) if fnvalue.Type().NumIn() != 1 { err = fmt.Errorf("LoadConfigure fn 类型错误! 只接受fn( _buf []map[string]interface{})(v,error) 函数参数") return } inType := fnvalue.Type().In(0) if inType.Elem() != typeOfIn { err = fmt.Errorf("LoadConfigure fn 类型错误! 只接受fn( _buf []map[string]interface{})(v,error) 函数参数") return } if fnvalue.Type().NumOut() != 2 { err = fmt.Errorf("LoadConfigure fn 类型错误! 只接受fn( _buf []map[string]interface{})(v,error) 函数参数") return } dataType := fnvalue.Type().Out(0) if dataType.Kind() != reflect.Ptr { err = fmt.Errorf("LoadConfigure fn 类型错误! 只接受fn( _buf []map[string]interface{})(v,error) 函数参数") return } if returnType := fnvalue.Type().Out(1); returnType != typeOfError { err = fmt.Errorf("LoadConfigure fn 类型错误! 只接受fn( _buf []map[string]interface{})(v,error) 函数参数") return } handle := &configurehandle{ configureType: dataType, fn: fnvalue, } if err = this.loaderConfigure(name, handle); err != nil { return } this.hlock.Lock() this.configurehandles[name] = handle this.hlock.Unlock() return } //更新配置信息 func (this *Configure) UpdateConfigure(names ...string) (err error) { for _, v := range names { this.hlock.RLock() handle, ok := this.configurehandles[v] this.hlock.RUnlock() if !ok { continue } if err = this.loaderConfigure(v, handle); err != nil { err = fmt.Errorf("loaderConfigure:%s err:%v", v, err) return } } return } //读取配置文件 func (this *Configure) GetConfigure(name string) (v interface{}, err error) { this.clock.RLock() v, ok := this.configure[name] this.clock.RUnlock() if !ok { err = fmt.Errorf("no LoadConfigure:%s", name) } return } //加载配置文件 func (this *Configure) loaderConfigure(name string, handle *configurehandle) (err error) { var ( fliepath string fileInfo fs.FileInfo file *os.File bytes []byte data []map[string]interface{} returnValues []reflect.Value ) fliepath = path.Join(this.options.ConfigurePath, name) if fileInfo, err = os.Stat(fliepath); err != nil { err = fmt.Errorf("no found file:%s", fliepath) return } if file, err = os.Open(fliepath); err != nil { err = fmt.Errorf("no found file:%s", fliepath) return } defer file.Close() if bytes, err = ioutil.ReadAll(file); err != nil { err = fmt.Errorf("read file:%s err:%v", fliepath, err) return } if err = jsoniter.Unmarshal(bytes, &data); err != nil { err = fmt.Errorf("read file:%s json.Unmarshal err:%v", fliepath, err) return } returnValues = handle.fn.Call([]reflect.Value{reflect.ValueOf(data)}) errInter := returnValues[1].Interface() if errInter != nil { err = fmt.Errorf("read file:%s load.fn err:%v", fliepath, errInter) return } this.clock.Lock() this.configure[name] = returnValues[0].Interface() this.fileinfos[fileInfo.Name()] = &FileInfo{Name: name, Size: fileInfo.Size(), ModTime: fileInfo.ModTime()} this.clock.Unlock() return } //检查配置文件是否有更新 func (this *Configure) checkConfigure() { if dir, err := ioutil.ReadDir(this.options.ConfigurePath); err != nil { log.Errorf("[Configure Sys] checkConfigure err:%v", err) } else { for _, fi := range dir { if !fi.IsDir() { //不处理目录代码 this.clock.RLock() v, ok := this.fileinfos[fi.Name()] this.clock.RUnlock() if ok && fi.ModTime().After(v.ModTime) { this.hlock.RLock() handle := this.configurehandles[v.Name] this.hlock.RUnlock() if err = this.loaderConfigure(v.Name, handle); err != nil { return } } } } } }