// Copyright 2015 Luke Shumaker . // // 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 // . 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 } } }