github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/config/local.go (about)

     1  package config
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
     9  	"github.com/fsnotify/fsnotify"
    10  )
    11  
    12  const (
    13  	LocalDynamicConfigPath = "config.dynamic.json"
    14  )
    15  
    16  type LocalClient struct {
    17  	path    string
    18  	dir     string
    19  	fecConf *FecConfig
    20  	logger  log.Logger
    21  	watcher *fsnotify.Watcher
    22  	close   chan struct{}
    23  }
    24  
    25  func NewLocalClient(path string, oecConf *FecConfig, logger log.Logger) (*LocalClient, error) {
    26  	if logger == nil {
    27  		logger = log.NewNopLogger()
    28  	}
    29  	dir := filepath.Dir(path)
    30  	watcher, err := fsnotify.NewWatcher()
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	client := &LocalClient{
    35  		path:    path,
    36  		dir:     dir,
    37  		fecConf: oecConf,
    38  		logger:  logger,
    39  		watcher: watcher,
    40  		close:   make(chan struct{}),
    41  	}
    42  	go func() {
    43  		for {
    44  			select {
    45  			case event, ok := <-watcher.Events:
    46  				if !ok {
    47  					return
    48  				}
    49  				// logger.Debug("local config event", "event", event)
    50  				if event.Name == client.path && (event.Has(fsnotify.Write) || event.Has(fsnotify.Create)) {
    51  					logger.Debug("local config changed", "path", path)
    52  					ok = client.LoadConfig()
    53  					if !ok {
    54  						logger.Debug("local config changed but failed to load")
    55  					} else {
    56  						logger.Debug("local config changed and loaded")
    57  					}
    58  				}
    59  			case err, ok := <-watcher.Errors:
    60  				if !ok {
    61  					return
    62  				}
    63  				logger.Error("local config watcher error", "err", err)
    64  			case <-client.close:
    65  				logger.Debug("local client closed")
    66  				return
    67  			}
    68  		}
    69  	}()
    70  
    71  	return client, nil
    72  }
    73  
    74  func (a *LocalClient) Close() error {
    75  	close(a.close)
    76  	return a.watcher.Close()
    77  }
    78  
    79  func (a *LocalClient) Enable() (err error) {
    80  	return a.watcher.Add(a.dir)
    81  }
    82  
    83  func (a *LocalClient) configExists() bool {
    84  	_, err := os.Stat(a.path)
    85  	return !os.IsNotExist(err)
    86  }
    87  
    88  func (a *LocalClient) LoadConfig() (loaded bool) {
    89  	var conf map[string]string
    90  	bz, err := os.ReadFile(a.path)
    91  	if err != nil {
    92  		a.logger.Error("failed to read local config", "path", a.path, "err", err)
    93  		return false
    94  	}
    95  	err = json.Unmarshal(bz, &conf)
    96  	if err != nil {
    97  		a.logger.Error("failed to unmarshal local config", "path", a.path, "err", err)
    98  		return false
    99  	}
   100  	loaded = true
   101  	for k, v := range conf {
   102  		a.fecConf.updateFromKVStr(k, v)
   103  	}
   104  	a.logger.Info(a.fecConf.format())
   105  	return
   106  }