-
Notifications
You must be signed in to change notification settings - Fork 5
/
watcher.go
104 lines (84 loc) · 2.24 KB
/
watcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package watcher
import (
"time"
"github.com/bep/debounce"
fsnotify "github.com/fsnotify/fsnotify"
)
// Watcher is a wrapper around fsnotify to provide a slightly better API. The intention is to eventually extend it.
type Watcher struct {
watcher *fsnotify.Watcher
filePath string // path being watched
keepRunning bool // can be set to false (by "Stop()") to stop watching
changes chan struct{}
errors chan error
OnChange func(filePath string) // callback a user can set to listen for changes
OnError func(err error) // callback a user can set to listen for errors
}
// WatchPath creates a "file watcher" that will notify you when the given file has been updated
func WatchPath(pathToFile string) (*Watcher, error) {
fsWatcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
w := &Watcher{fsWatcher, pathToFile, true, make(chan struct{}), make(chan error), nil, nil}
// doNotify := createDebounced(1000*time.Millisecond, func() {
// w.changes <- struct{}{}
// })
debouncer := debounce.New(500 * time.Millisecond)
doNotify := func(filePath string) {
debouncer(func() {
if !w.keepRunning {
return
}
// w.changes <- struct{}{} // will block, we'd have to ensure it gets drained
callback := w.OnChange
if callback != nil {
callback(filePath)
}
})
}
go func() {
for w.keepRunning {
select {
case event := <-fsWatcher.Events:
if !isValidEvent(event) {
continue
}
doNotify(event.Name)
case err := <-fsWatcher.Errors:
//w.errors <- err
h := w.OnError
if h != nil {
h(err)
}
}
}
}()
err = fsWatcher.Add(pathToFile)
if err != nil {
w.Stop()
return nil, err
}
return w, nil
}
// Stop stops the watcher, releases all resources, ...
func (w *Watcher) Stop() {
if w.keepRunning == false {
return
}
w.keepRunning = false
w.watcher.Close()
}
func createDebounced(duration time.Duration, f func()) func() {
debouncer := debounce.New(duration)
debouncedFunc := func() { debouncer(f) }
return debouncedFunc
}
func isValidEvent(event fsnotify.Event) bool {
if (event.Op&fsnotify.Create == fsnotify.Create) ||
(event.Op&fsnotify.Rename == fsnotify.Rename) ||
(event.Op&fsnotify.Write == fsnotify.Write) {
return true
}
return false
}