101 lines
1.6 KiB
Go
101 lines
1.6 KiB
Go
package smtp
|
|
|
|
import (
|
|
"math"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"gitlab.com/etke.cc/go/logger"
|
|
)
|
|
|
|
const fsdelay = 100 * time.Millisecond
|
|
|
|
type FSWatcher struct {
|
|
watcher *fsnotify.Watcher
|
|
files []string
|
|
log *logger.Logger
|
|
mu sync.Mutex
|
|
t map[string]*time.Timer
|
|
}
|
|
|
|
func NewFSWatcher(files []string, loglevel string) (*FSWatcher, error) {
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, file := range files {
|
|
err = watcher.Add(filepath.Dir(file))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
fswatcher := &FSWatcher{
|
|
watcher: watcher,
|
|
files: files,
|
|
log: logger.New("fs.", loglevel),
|
|
t: make(map[string]*time.Timer),
|
|
}
|
|
|
|
return fswatcher, nil
|
|
}
|
|
|
|
func (w *FSWatcher) watch(handler func(e fsnotify.Event)) {
|
|
for {
|
|
select {
|
|
case err, ok := <-w.watcher.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
w.log.Error("%v", err)
|
|
case e, ok := <-w.watcher.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
handler(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start watcher
|
|
func (w *FSWatcher) Start(handler func(e fsnotify.Event)) {
|
|
w.watch(func(e fsnotify.Event) {
|
|
var found bool
|
|
for _, f := range w.files {
|
|
if f == e.Name {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
return
|
|
}
|
|
w.mu.Lock()
|
|
t, ok := w.t[e.Name]
|
|
w.mu.Unlock()
|
|
if !ok {
|
|
t = time.AfterFunc(math.MaxInt64, func() {
|
|
w.log.Info("handling fs event %+v", e)
|
|
handler(e)
|
|
})
|
|
t.Stop()
|
|
|
|
w.mu.Lock()
|
|
w.t[e.Name] = t
|
|
w.mu.Unlock()
|
|
}
|
|
t.Reset(fsdelay)
|
|
})
|
|
}
|
|
|
|
// Stop watcher
|
|
func (w *FSWatcher) Stop() {
|
|
err := w.watcher.Close()
|
|
if err != nil {
|
|
w.log.Error("cannot stop fs watcher: %v", err)
|
|
}
|
|
}
|