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