From 88b60f2df01687b914167694d3f2892b3387446c Mon Sep 17 00:00:00 2001 From: KemoNine Date: Thu, 27 Aug 2020 10:02:44 -0400 Subject: [PATCH] Added inotify watcher for restarting slideshow when files are changed/deleted/added --- cmd/inotify/README.md | 3 ++ cmd/inotify/inotify.go | 68 ++++++++++++++++++++++++++++++++++++++++++ watchdog/README.md | 3 ++ watchdog/watchdog.go | 41 +++++++++++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 cmd/inotify/README.md create mode 100644 cmd/inotify/inotify.go create mode 100644 watchdog/README.md create mode 100644 watchdog/watchdog.go diff --git a/cmd/inotify/README.md b/cmd/inotify/README.md new file mode 100644 index 0000000..05f19c5 --- /dev/null +++ b/cmd/inotify/README.md @@ -0,0 +1,3 @@ +# inotify + +This is the main source code for the inotify watcher that restarts the PiFrame slide show when files have changed (add/remove/etc). diff --git a/cmd/inotify/inotify.go b/cmd/inotify/inotify.go new file mode 100644 index 0000000..686cad6 --- /dev/null +++ b/cmd/inotify/inotify.go @@ -0,0 +1,68 @@ +package main + +import ( + "log" + "os/exec" + "time" + + "github.com/dietsche/rfsnotify" + + "git.kemonine.info/PiFrame/watchdog" +) + +const ( + CMD_SYSTEMCTL = "/usr/bin/systemctl" + PATH_PICTURES = "/tank/pictures" + TIMEOUT = 5 * time.Second +) + +func main() { + // Create watchdog timer that restarts fim.service on timeout + watchdog := watchdog.New(TIMEOUT, func() { + err := exec.Command(CMD_SYSTEMCTL, "restart", "fim.service").Run() + if err != nil { + log.Fatalf("Error running %s : %s", CMD_SYSTEMCTL, err) + } + }) + watchdog.DeferredStart() + + // Create fswatcher + watcher, err := rfsnotify.NewWatcher() + if err != nil { + log.Fatal("Error setting up rfsnotify") + } + + // Ensure we clean stuff up no matter what + defer watcher.Close() + + // Setup goroutine and listen for events + done := make(chan bool) + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + // Print out event (this is where logic will go eventually)) + log.Printf("event: %#v\n", event) + // [Re]Start timer to restart slideshow after the fs events die down + watchdog.Kick() + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Println("Error: ", err) + } + } + }() + + // Setup paths to watch + err = watcher.AddRecursive(PATH_PICTURES) + if err != nil { + log.Fatalf("Error setting up recursive watch of %s", PATH_PICTURES) + } + + // Drain done channel... + <-done +} diff --git a/watchdog/README.md b/watchdog/README.md new file mode 100644 index 0000000..2244211 --- /dev/null +++ b/watchdog/README.md @@ -0,0 +1,3 @@ +# watchdog + +A very simple watchdog timer implementation. Borrowed from [here](https://codereview.stackexchange.com/questions/144273/watchdog-in-golang) and tweaked slightly. diff --git a/watchdog/watchdog.go b/watchdog/watchdog.go new file mode 100644 index 0000000..fe60efc --- /dev/null +++ b/watchdog/watchdog.go @@ -0,0 +1,41 @@ +// Adapted from https://codereview.stackexchange.com/questions/144273/watchdog-in-golang + +package watchdog + +import ( + "time" +) + +type watchdog struct { + interval time.Duration + callback func() + timer *time.Timer +} + +func New(interval time.Duration, callback func()) *watchdog { + w := watchdog{ + interval: interval, + callback: callback, + timer: nil, + } + return &w +} + +func (w *watchdog) Start() { + w.timer = time.AfterFunc(w.interval, w.callback) +} + +// Helper to allow the watchdog to be started by a call to Kick directly +func (w *watchdog) DeferredStart() { + w.Start() + w.Stop() +} + +func (w *watchdog) Stop() { + w.timer.Stop() +} + +func (w *watchdog) Kick() { + w.Stop() + w.timer.Reset(w.interval) +}