-
Notifications
You must be signed in to change notification settings - Fork 0
/
watch.go
112 lines (91 loc) · 1.54 KB
/
watch.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
105
106
107
108
109
110
111
112
package tail
import (
"context"
"github.com/fsnotify/fsnotify"
"path/filepath"
"sync"
)
type OP = fsnotify.Op
type Event fsnotify.Event
type handle func(Event)
type watch struct {
mu sync.RWMutex
file map[string]handle
ctx context.Context
wer *fsnotify.Watcher
}
func newW(ctx context.Context) (watch, error) {
var wx watch
w, err := fsnotify.NewWatcher()
if err != nil {
return wx, err
}
wx = watch{
ctx: ctx,
file: make(map[string]handle),
wer: w,
}
xEnv.Spawn(0, wx.loop)
return wx, nil
}
func (w *watch) call(ev Event) {
w.mu.RLock()
defer w.mu.RUnlock()
if hde, ok := w.file[ev.Name]; ok {
hde(ev)
return
}
if hde, ok := w.file[filepath.Dir(ev.Name)]; ok {
hde(ev)
return
}
}
func (w *watch) insert(path string, hde handle) {
if hde == nil {
return
}
if w.wer == nil {
return
}
w.mu.Lock()
defer w.mu.Unlock()
if _, ok := w.file[path]; ok {
xEnv.Errorf("%s file watcher already ok", path)
return
}
if e := w.wer.Add(path); e != nil {
xEnv.Errorf("%s file watcher add error %v", path, e)
return
}
w.file[path] = hde
}
func (w *watch) remove(path string) {
w.mu.Lock()
defer w.mu.Unlock()
delete(w.file, path)
w.wer.Remove(path)
}
func (w *watch) free() {
w.wer.Close()
w.file = nil
w.wer = nil
}
func (w *watch) loop() {
defer w.free()
for {
select {
case <-w.ctx.Done():
return
case ev, ok := <-w.wer.Events:
if !ok {
continue
}
w.call(Event(ev))
case err, ok := <-w.wer.Errors:
if !ok {
continue
}
xEnv.Errorf("watch %v", err)
}
}
}