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