diff --git a/share/settings/users.go b/share/settings/users.go index a6f0a093..b877247c 100644 --- a/share/settings/users.go +++ b/share/settings/users.go @@ -5,8 +5,12 @@ import ( "errors" "fmt" "os" + "path/filepath" "regexp" + "runtime" + "strings" "sync" + "time" "github.com/fsnotify/fsnotify" "github.com/jpillora/chisel/share/cio" @@ -102,20 +106,60 @@ func (u *UserIndex) addWatchEvents() error { if err != nil { return err } - if err := watcher.Add(u.configFile); err != nil { + configPath, err := filepath.Abs(u.configFile) + if err != nil { + return err + } + if err := watcher.Add(filepath.Dir(configPath)); err != nil { return err } go func() { - for e := range watcher.Events { - if e.Op&fsnotify.Write != fsnotify.Write { - continue - } - if err := u.loadUserIndex(); err != nil { - u.Infof("Failed to reload the users configuration: %s", err) - } else { - u.Debugf("Users configuration successfully reloaded from: %s", u.configFile) + var debounceTimer *time.Timer + var debounceMutex sync.Mutex + for { + select { + case e, ok := <-watcher.Events: { + if !ok { + u.Infof("Stop watching the users configuration: fsnotify Events channel closed.") + return + } + eventPath, err := filepath.Abs(e.Name) + if err != nil { + continue + } + if runtime.GOOS == "windows" { + if !strings.EqualFold(eventPath, configPath) { + continue + } + } else if eventPath != configPath { + continue + } + if e.Op&(fsnotify.Write|fsnotify.Create|fsnotify.Rename) == 0 { + continue + } + if debounceTimer != nil { + debounceTimer.Stop() + } + debounceTimer = time.AfterFunc(200*time.Millisecond, func() { + debounceMutex.Lock() + defer debounceMutex.Unlock() + if err := u.loadUserIndex(); err != nil { + u.Infof("Failed to reload the users configuration: %s", err) + } else { + u.Debugf("Users configuration successfully reloaded from: %s", u.configFile) + } + }) + } + case err, ok := <-watcher.Errors: { + if !ok { + u.Infof("Stop watching the users configuration: fsnotify Errors channel closed.") + return + } + // just log and continue running with current config + u.Infof("Error while watching the users configuration: %s", err) + } } - } + } }() return nil }