-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnotify.go
More file actions
139 lines (128 loc) · 2.83 KB
/
notify.go
File metadata and controls
139 lines (128 loc) · 2.83 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package peony
import (
"github.com/howeyc/fsnotify"
"os"
"path/filepath"
"strings"
"sync"
)
type Observer interface {
Refresh() error
ForceRefresh() bool
Path() []string
}
type IgnoreObserver interface {
Observer
IgnoreDir(file os.FileInfo) bool
IgnoreFile(file string) bool
}
type observerWatcher struct {
observer Observer
watcher *fsnotify.Watcher
path string
}
type Notifier struct {
watchers []*observerWatcher
lastError Error
mutex *sync.Mutex
}
func NewNotifier() *Notifier {
n := &Notifier{}
n.watchers = []*observerWatcher{}
n.mutex = &sync.Mutex{}
return n
}
func (n *Notifier) contain(abspath string) bool {
for _, obswatcher := range n.watchers {
if obswatcher.path == abspath {
return true
}
}
return false
}
func (n *Notifier) Watch(o Observer) {
var err error
var abspath string
for _, basePath := range o.Path() {
abspath, err = filepath.Abs(basePath)
if err != nil {
ERROR.Println("create watcher error:", err)
continue
}
if n.contain(abspath) {
continue
}
var watcher *fsnotify.Watcher
watcher, err = fsnotify.NewWatcher()
//collect 100 events
watcher.Event = make(chan *fsnotify.FileEvent, 200)
//collect 10 error
watcher.Error = make(chan error, 20)
obsWatcher := &observerWatcher{o, watcher, abspath}
n.watchers = append(n.watchers, obsWatcher)
var ignoreObserver IgnoreObserver = nil
var isIgnoreObserver bool
ignoreObserver, isIgnoreObserver = o.(IgnoreObserver)
watcher.Watch(abspath)
err = filepath.Walk(abspath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
return nil
}
if isIgnoreObserver {
if info.IsDir() && ignoreObserver.IgnoreDir(info) {
return filepath.SkipDir
}
}
watcher.Watch(path)
return nil
})
if err != nil {
ERROR.Println("watch error:", err)
}
}
}
func (n *Notifier) Notify() error {
n.mutex.Lock()
defer n.mutex.Unlock()
flush := false
for _, obswatcher := range n.watchers {
//get all event events store in chan obswatcher.watcher.Event
for {
select {
case evt := <-obswatcher.watcher.Event:
//ignore file name start with "." like ".xxx"
if !strings.HasPrefix(filepath.Base(evt.Name), ".") {
if ignoreObserver, ok := obswatcher.observer.(IgnoreObserver); ok {
if ignoreObserver.IgnoreFile(evt.Name) {
continue
}
}
flush = true
}
continue
case <-obswatcher.watcher.Error:
continue
default:
}
break
}
if obswatcher.observer.ForceRefresh() || flush {
if err := obswatcher.observer.Refresh(); err != nil {
return err
}
}
}
return nil
}
func GetNotifyFilter(svr *Server) Filter {
return func(c *Controller, filter []Filter) {
if err := svr.notifier.Notify(); err != nil {
RenderError(err).Apply(c)
return
}
filter[0](c, filter[1:])
}
}