summaryrefslogtreecommitdiff
path: root/inotify/channels.go
diff options
context:
space:
mode:
Diffstat (limited to 'inotify/channels.go')
-rw-r--r--inotify/channels.go96
1 files changed, 96 insertions, 0 deletions
diff --git a/inotify/channels.go b/inotify/channels.go
new file mode 100644
index 0000000..737b312
--- /dev/null
+++ b/inotify/channels.go
@@ -0,0 +1,96 @@
+// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>.
+//
+// This is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this manual; if not, see
+// <http://www.gnu.org/licenses/>.
+
+package inotify
+
+import (
+ "os"
+ "syscall"
+)
+
+// A Watcher is a wrapper around an (*Inotify) that exposes a
+// channel-based interface that is much nicer to work with.
+type Watcher struct {
+ Events <-chan Event
+ Errors <-chan error
+ events chan<- Event
+ errors chan<- error
+ in *Inotify
+}
+
+// Wraps InotifyInit()
+func WatcherInit() (*Watcher, error) {
+ in, err := InotifyInit()
+ return newWatcher(in, err)
+}
+
+// Wraps InotifyInit1()
+func WatcherInit1(flags int) (*Watcher, error) {
+ in, err := InotifyInit1(flags &^ IN_NONBLOCK)
+ return newWatcher(in, err)
+}
+
+func newWatcher(in *Inotify, err error) (*Watcher, error) {
+ events := make(chan Event)
+ errors := make(chan error)
+ o := &Watcher{
+ Events: events,
+ events: events,
+ Errors: errors,
+ errors: errors,
+ in: in,
+ }
+ go o.worker()
+ return o, err
+}
+
+// Wraps Inotify.AddWatch(); adds or modifies a watch.
+func (o *Watcher) AddWatch(path string, mask Mask) (Wd, error) {
+ return o.in.AddWatch(path, mask)
+}
+
+// Wraps Inotify.RmWatch(); removes a watch.
+func (o *Watcher) RmWatch(wd Wd) error {
+ return o.in.RmWatch(wd)
+}
+
+// Wraps Inotify.Close(). Unlike Inotify.Close(),
+// this cannot block. Also unlike Inotify.Close(), nothing
+// may be received from the channel after this is called.
+func (o *Watcher) Close() {
+ func() {
+ defer recover()
+ close(o.events)
+ close(o.errors)
+ }()
+ go o.in.Close()
+}
+
+func (o *Watcher) worker() {
+ defer recover()
+ for {
+ ev, err := o.in.Read()
+ if ev.Wd >= 0 {
+ o.events <- ev
+ }
+ if err != nil {
+ if err.(*os.SyscallError).Err == syscall.EBADF {
+ o.Close()
+ }
+ o.errors <- err
+ }
+ }
+}