go func() {
for {
select {
- case ev := <-watcher.Event:
+ case ev := <-watcher.Events:
log.Println("event:", ev)
- case err := <-watcher.Error:
+ case err := <-watcher.Errors:
log.Println("error:", err)
}
}
femut sync.Mutex // Protects access to fileExists.
externalWatches map[string]bool // Map of watches added by user of the library.
ewmut sync.Mutex // Protects access to externalWatches.
- Error chan error // Errors are sent on this channel
- Event chan *FileEvent // Events are returned on this channel
+ Errors chan error // Errors are sent on this channel
+ Events chan *FileEvent // Events are returned on this channel
done chan bool // Channel for sending a "quit message" to the reader goroutine
isClosed bool // Set to true when Close() is first called
}
finfo: make(map[int]os.FileInfo),
fileExists: make(map[string]bool),
externalWatches: make(map[string]bool),
- Event: make(chan *FileEvent),
- Error: make(chan error),
+ Events: make(chan *FileEvent),
+ Errors: make(chan error),
done: make(chan bool, 1),
}
}
// readEvents reads from the kqueue file descriptor, converts the
-// received events into Event objects and sends them via the Event channel
+// received events into Event objects and sends them via the Events channel
func (w *Watcher) readEvents() {
var (
eventbuf [10]syscall.Kevent_t // Event buffer
if done {
errno := syscall.Close(w.kq)
if errno != nil {
- w.Error <- os.NewSyscallError("close", errno)
+ w.Errors <- os.NewSyscallError("close", errno)
}
- close(w.Event)
- close(w.Error)
+ close(w.Events)
+ close(w.Errors)
return
}
// EINTR is okay, basically the syscall was interrupted before
// timeout expired.
if errno != nil && errno != syscall.EINTR {
- w.Error <- os.NewSyscallError("kevent", errno)
+ w.Errors <- os.NewSyscallError("kevent", errno)
continue
}
w.sendDirectoryChangeEvents(fileEvent.Name)
} else {
// Send the event on the events channel
- w.Event <- fileEvent
+ w.Events <- fileEvent
}
// Move to next event
// Get all files
files, err := ioutil.ReadDir(dirPath)
if err != nil {
- w.Error <- err
+ w.Errors <- err
}
// Search for new files
fileEvent := new(FileEvent)
fileEvent.Name = filePath
fileEvent.create = true
- w.Event <- fileEvent
+ w.Events <- fileEvent
}
w.femut.Lock()
w.fileExists[filePath] = true
fd int // File descriptor (as returned by the inotify_init() syscall)
watches map[string]*watch // Map of inotify watches (key: path)
paths map[int]string // Map of watched paths (key: watch descriptor)
- Error chan error // Errors are sent on this channel
- Event chan *FileEvent // Events are returned on this channel
+ Errors chan error // Errors are sent on this channel
+ Events chan *FileEvent // Events are returned on this channel
done chan bool // Channel for sending a "quit message" to the reader goroutine
isClosed bool // Set to true when Close() is first called
}
fd: fd,
watches: make(map[string]*watch),
paths: make(map[int]string),
- Event: make(chan *FileEvent),
- Error: make(chan error),
+ Events: make(chan *FileEvent),
+ Errors: make(chan error),
done: make(chan bool, 1),
}
}
// readEvents reads from the inotify file descriptor, converts the
-// received events into Event objects and sends them via the Event channel
+// received events into Event objects and sends them via the Events channel
func (w *Watcher) readEvents() {
var (
buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
select {
case <-w.done:
syscall.Close(w.fd)
- close(w.Event)
- close(w.Error)
+ close(w.Events)
+ close(w.Errors)
return
default:
}
// If EOF is received
if n == 0 {
syscall.Close(w.fd)
- close(w.Event)
- close(w.Error)
+ close(w.Events)
+ close(w.Errors)
return
}
if n < 0 {
- w.Error <- os.NewSyscallError("read", errno)
+ w.Errors <- os.NewSyscallError("read", errno)
continue
}
if n < syscall.SizeofInotifyEvent {
- w.Error <- errors.New("inotify: short read in readEvents()")
+ w.Errors <- errors.New("inotify: short read in readEvents()")
continue
}
// Send the events that are not ignored on the events channel
if !event.ignoreLinux() {
- w.Event <- event
+ w.Events <- event
}
// Move to the next event in the buffer
}
}
-// Certain types of events can be "ignored" and not sent over the Event
+// Certain types of events can be "ignored" and not sent over the Events
// channel. Such as events marked ignore by the kernel, or MODIFY events
// against files that do not exist.
func (e *FileEvent) ignoreLinux() bool {
var errorsReceived counter
// Receive errors on the error channel on a separate goroutine
go func() {
- for errors := range watcher.Error {
+ for errors := range watcher.Errors {
t.Logf("Received error: %s", errors)
errorsReceived.increment()
}
// Count the CREATE events received
var createEventsReceived, otherEventsReceived counter
go func() {
- for ev := range watcher.Event {
+ for ev := range watcher.Events {
t.Logf("event received: %s", ev)
if ev.IsCreate() {
createEventsReceived.increment()
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
addWatch(t, watcher, testDir)
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var createReceived, modifyReceived, deleteReceived, renameReceived counter
done := make(chan bool)
go func() {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
addWatch(t, watcher, testDir)
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var createReceived, modifyReceived, deleteReceived counter
done := make(chan bool)
go func() {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var createReceived, modifyReceived, deleteReceived counter
done := make(chan bool)
go func() {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var deleteReceived counter
go func() {
for event := range eventstream {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var createReceived, deleteReceived counter
done := make(chan bool)
go func() {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var renameReceived counter
done := make(chan bool)
go func() {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var createReceived counter
done := make(chan bool)
go func() {
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
var eventReceived counter
done := make(chan bool)
go func() {
go func() {
select {
- case ev := <-watcher.Event:
+ case ev := <-watcher.Events:
t.Fatalf("We received event: %v\n", ev)
case <-time.After(500 * time.Millisecond):
t.Log("No event received, as expected.")
// Receive errors on the error channel on a separate goroutine
go func() {
- for err := range watcher.Error {
+ for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
// Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
+ eventstream := watcher.Events
// The modifyReceived counter counts IsModify events that are not IsAttrib,
// and the attribReceived counts IsAttrib events (which are also IsModify as
// a consequence).
)
// Event is the type of the notification messages
-// received on the watcher's Event channel.
+// received on the watcher's Events channel.
type FileEvent struct {
mask uint32 // Mask of events
cookie uint32 // Unique cookie associating related events (for rename)
port syscall.Handle // Handle to completion port
watches watchMap // Map of watches (key: i-number)
input chan *input // Inputs to the reader are sent on this channel
- Event chan *FileEvent // Events are returned on this channel
- Error chan error // Errors are sent on this channel
+ Events chan *FileEvent // Events are returned on this channel
+ Errors chan error // Errors are sent on this channel
isClosed bool // Set to true when Close() is first called
quit chan chan<- error
cookie uint32
port: port,
watches: make(watchMap),
input: make(chan *input, 1),
- Event: make(chan *FileEvent, 50),
- Error: make(chan error),
+ Events: make(chan *FileEvent, 50),
+ Errors: make(chan error),
quit: make(chan chan<- error, 1),
}
go w.readEvents()
// Must run within the I/O thread.
func (w *Watcher) startRead(watch *watch) error {
if e := syscall.CancelIo(watch.ino.handle); e != nil {
- w.Error <- os.NewSyscallError("CancelIo", e)
+ w.Errors <- os.NewSyscallError("CancelIo", e)
w.deleteWatch(watch)
}
mask := toWindowsFlags(watch.mask)
}
if mask == 0 {
if e := syscall.CloseHandle(watch.ino.handle); e != nil {
- w.Error <- os.NewSyscallError("CloseHandle", e)
+ w.Errors <- os.NewSyscallError("CloseHandle", e)
}
w.mu.Lock()
delete(w.watches[watch.ino.volume], watch.ino.index)
}
// readEvents reads from the I/O completion port, converts the
-// received events into Event objects and sends them via the Event channel.
+// received events into Event objects and sends them via the Events channel.
// Entry point to the I/O thread.
func (w *Watcher) readEvents() {
var (
if e := syscall.CloseHandle(w.port); e != nil {
err = os.NewSyscallError("CloseHandle", e)
}
- close(w.Event)
- close(w.Error)
+ close(w.Events)
+ close(w.Errors)
ch <- err
return
case in := <-w.input:
switch e {
case sys_ERROR_MORE_DATA:
if watch == nil {
- w.Error <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
+ w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
} else {
// The i/o succeeded but the buffer is full.
// In theory we should be building up a full packet.
// CancelIo was called on this handle
continue
default:
- w.Error <- os.NewSyscallError("GetQueuedCompletionPort", e)
+ w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
continue
case nil:
}
var offset uint32
for {
if n == 0 {
- w.Event <- &FileEvent{mask: sys_FS_Q_OVERFLOW}
- w.Error <- errors.New("short read in readEvents()")
+ w.Events <- &FileEvent{mask: sys_FS_Q_OVERFLOW}
+ w.Errors <- errors.New("short read in readEvents()")
break
}
// Error!
if offset >= n {
- w.Error <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
+ w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
break
}
}
if err := w.startRead(watch); err != nil {
- w.Error <- err
+ w.Errors <- err
}
}
}
select {
case ch := <-w.quit:
w.quit <- ch
- case w.Event <- event:
+ case w.Events <- event:
}
return true
}