github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/config/watcher.go (about) 1 package config 2 3 import ( 4 "path/filepath" 5 6 "github.com/fsnotify/fsnotify" 7 "github.com/pkg/errors" 8 9 "github.com/masterhung0112/hk_server/v5/shared/mlog" 10 ) 11 12 // watcher monitors a file for changes 13 type watcher struct { 14 fsWatcher *fsnotify.Watcher 15 close chan struct{} 16 closed chan struct{} 17 } 18 19 // newWatcher creates a new instance of watcher to monitor for file changes. 20 func newWatcher(path string, callback func()) (w *watcher, err error) { 21 fsWatcher, err := fsnotify.NewWatcher() 22 if err != nil { 23 return nil, errors.Wrapf(err, "failed to create fsnotify watcher for %s", path) 24 } 25 26 path = filepath.Clean(path) 27 28 // Watch the entire containing directory. 29 configDir, _ := filepath.Split(path) 30 if err := fsWatcher.Add(configDir); err != nil { 31 if closeErr := fsWatcher.Close(); closeErr != nil { 32 mlog.Error("failed to stop fsnotify watcher for %s", mlog.String("path", path), mlog.Err(closeErr)) 33 } 34 return nil, errors.Wrapf(err, "failed to watch directory %s", configDir) 35 } 36 37 w = &watcher{ 38 fsWatcher: fsWatcher, 39 close: make(chan struct{}), 40 closed: make(chan struct{}), 41 } 42 43 go func() { 44 defer close(w.closed) 45 defer func() { 46 if err := fsWatcher.Close(); err != nil { 47 mlog.Error("failed to stop fsnotify watcher for %s", mlog.String("path", path)) 48 } 49 }() 50 51 for { 52 select { 53 case event := <-fsWatcher.Events: 54 // We only care about the given file. 55 if filepath.Clean(event.Name) == path { 56 if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { 57 mlog.Info("Config file watcher detected a change", mlog.String("path", path)) 58 go callback() 59 } 60 } 61 case err := <-fsWatcher.Errors: 62 mlog.Error("Failed while watching config file", mlog.String("path", path), mlog.Err(err)) 63 case <-w.close: 64 return 65 } 66 } 67 }() 68 69 return w, nil 70 } 71 72 func (w *watcher) Close() error { 73 close(w.close) 74 <-w.closed 75 76 return nil 77 }