From 6b8d872d680d019827cc45881186cce3f83f764a Mon Sep 17 00:00:00 2001 From: davy wybiral Date: Wed, 3 Jul 2019 14:44:31 -0500 Subject: [PATCH] added debounce (#11) --- pkg/app/app.go | 24 +------------------ pkg/app/watcher.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 pkg/app/watcher.go diff --git a/pkg/app/app.go b/pkg/app/app.go index baf3ccb..22ad91f 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -89,32 +89,10 @@ func (a *App) Run() error { } a.Watcher.Add(p.Path) } - go a.watch() + go startWatcher(a) return http.Serve(a.Listener, a.Router) } -// Watch the library path and update Library with changes. -func (a *App) watch() { - for { - e, ok := <-a.Watcher.Events - if !ok { - return - } - if e.Op&fsnotify.Create > 0 { - // add new files to library - a.Library.Add(e.Name) - } else if e.Op&(fsnotify.Write|fsnotify.Chmod) > 0 { - // writes and chmods should remove old file before adding again - a.Library.Remove(e.Name) - a.Library.Add(e.Name) - } else if e.Op&(fsnotify.Remove|fsnotify.Rename) > 0 { - // remove and rename just remove file - // fsnotify will signal a Create event with the new file name - a.Library.Remove(e.Name) - } - } -} - // HTTP handler for / func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) { log.Printf("/") diff --git a/pkg/app/watcher.go b/pkg/app/watcher.go new file mode 100644 index 0000000..2d7a761 --- /dev/null +++ b/pkg/app/watcher.go @@ -0,0 +1,59 @@ +package app + +import ( + "time" + + fs "github.com/fsnotify/fsnotify" +) + +// This is the amount of time to wait after changes before reacting to them. +// Debounce is done because moving files into the watched directories causes +// many rapid "Write" events to fire which would cause excessive Remove/Add +// method calls on the Library. To avoid this we accumulate the changes and +// only perform them once the events have stopped for this amount of time. +const debounceTimeout = time.Second * 5 + +// create, write, and chmod all require an add event +const addFlags = fs.Create | fs.Write | fs.Chmod + +// remove, rename, write, and chmod all require a remove event +const removeFlags = fs.Remove | fs.Rename | fs.Write | fs.Chmod + +// watch library paths and update Library with changes. +func startWatcher(a *App) { + timer := time.NewTimer(debounceTimeout) + addEvents := make(map[string]struct{}) + removeEvents := make(map[string]struct{}) + for { + select { + case e := <-a.Watcher.Events: + if e.Op&removeFlags > 0 { + removeEvents[e.Name] = struct{}{} + } + if e.Op&addFlags > 0 { + addEvents[e.Name] = struct{}{} + } + // reset timer + timer.Reset(debounceTimeout) + case <-timer.C: + // handle remove events first + if len(removeEvents) > 0 { + for p := range removeEvents { + a.Library.Remove(p) + } + // clear map + removeEvents = make(map[string]struct{}) + } + // then handle add events + if len(addEvents) > 0 { + for p := range addEvents { + a.Library.Add(p) + } + // clear map + addEvents = make(map[string]struct{}) + } + // reset timer + timer.Reset(debounceTimeout) + } + } +}