Watcher
package revel
type Listener interface {
Refresh() *Error
}
type DiscerningListener interface {
Listener
WatchDir(info os.FileInfo) bool
WatchFile(basename string) bool
}
type Watcher struct {
}
func NewWatcher() *Watcher {
return &Watcher{
forceRefresh: true,
lastError: -1,
}
}
func (w *Watcher) Listen(listener Listener, roots ...string) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
ERROR.Fatal(err)
}
watcher.Event = make(chan *fsnotify.FileEvent, 100)
watcher.Error = make(chan error, 10)
for _, p := range roots {
fi, err := os.Stat(p)
if err != nil {
ERROR.Println("Failed to stat watched path", p, ":", err)
continue
}
if !fi.IsDir() {
err = watcher.Watch(p)
if err != nil {
ERROR.Println("Failed to watch", p, ":", err)
}
TRACE.Println("Watching:", p)
continue
}
filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
if err != nil {
ERROR.Println("Error walking path:", err)
return nil
}
if info.IsDir() {
if dl, ok := listener.(DiscerningListener); ok {
if !dl.WatchDir(info) {
return filepath.SkipDir
}
}
err = watcher.Watch(path)
if err != nil {
ERROR.Println("Failed to watch", path, ":", err)
}
TRACE.Println("Watching:", path)
}
return nil
})
}
w.watchers = append(w.watchers, watcher)
w.listeners = append(w.listeners, listener)
}
func (w *Watcher) Notify() *Error {
w.notifyMutex.Lock()
defer w.notifyMutex.Unlock()
for i, watcher := range w.watchers {
listener := w.listeners[i]
refresh := false
for {
select {
case ev := <-watcher.Event:
if !strings.HasPrefix(path.Base(ev.Name), ".") {
if dl, ok := listener.(DiscerningListener); ok {
if !dl.WatchFile(ev.Name) {
continue
}
}
refresh = true
}
continue
case <-watcher.Error:
continue
default:
}
break
}
if w.forceRefresh || refresh || w.lastError == i {
err := listener.Refresh()
if err != nil {
w.lastError = i
return err
}
}
}
w.forceRefresh = false
w.lastError = -1
return nil
}
var WatchFilter = func(c *Controller, fc []Filter) {
if MainWatcher != nil {
err := MainWatcher.Notify()
if err != nil {
c.Result = c.RenderError(err)
return
}
}
fc[0](c, fc[1:])
}