rfsnotify

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2025 License: MIT Imports: 6 Imported by: 1

README

rfsnotify

recursive directory notifications built as a wrapper around fsnotify (golang), forked from this repo

GoDoc

This is a thin wrapper around https://github.com/fsnotify/fsnotify instead of only monitoring a top level folder, it allows you to monitor all folders underneath the folder you specify.

Example:

(error handling omitted to improve readability)

    import "github.com/farmergreg/rfsnotify"

//rfsnotify works exactly like fsnotify and implements the same API.
    watcher, err := rfsnotify.NewWatcher()

//rfsnotify adds two new API entry points:
    watcher.AddRecursive("/tmp/")
    watcher.RemoveRecursive("/tmp/")

Documentation

Overview

Package rfsnotify implements recursive folder monitoring by wrapping the excellent fsnotify library

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type RWatcher

type RWatcher struct {
	Events chan fsnotify.Event
	Errors chan error
	// contains filtered or unexported fields
}

RWatcher wraps fsnotify.Watcher. When fsnotify adds recursive watches, you should be able to switch your code to use fsnotify.Watcher

func NewWatcher

func NewWatcher() (*RWatcher, error)

NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.

func (*RWatcher) Add

func (m *RWatcher) Add(name string) error

Add starts watching the named file or directory (non-recursively).

Example
// create test folder
rd := filepath.Join(os.TempDir(), "testRWatcher_add")
err := os.Mkdir(rd, 0o750)
if err != nil {
	fmt.Printf("could not create root test folder, error: %s", err)
	return
}
defer func() {
	if e := os.RemoveAll(rd); e != nil {
		fmt.Printf("could not remove test folder %s, error: %s", rd, e)
	}
}()
if err = os.MkdirAll(filepath.Join(rd, "a/b/c"), 0o750); err != nil {
	fmt.Printf("could not create test folders, error: %s", err)
	return
}

// create new watcher
watcher, err := NewWatcher()
if err != nil {
	fmt.Printf("could not create recursive watcher, error: %s", err)
	return
}

defer func() {
	if e := watcher.Close(); e != nil {
		fmt.Printf("could not close recursive watcher, error: %s", e)
	}
}()

// add dummy event listener, real one must use a controlled loop
wg := sync.WaitGroup{}
wg.Go(func() {
	event, ok := <-watcher.Events
	if !ok {
		fmt.Printf("ko event")
		return
	}
	fmt.Printf("received event %s", event)
})

// add test folder to be watched
err = watcher.Add(rd)
if err != nil {
	fmt.Printf("could not add recursive folder %s, error: %s", rd, err)
	return
}

// create a test file that will not trigger notify
f, err := os.Create(filepath.Clean(filepath.Join(rd, "a/b/c", "test.txt")))
if err != nil {
	fmt.Printf("could not create test file %s, error: %s", rd, err)
	return
}
defer func() {
	if e := f.Close(); e != nil {
		fmt.Printf("could not close file %s, error: %s", f.Name(), e)
	}
}()

// create a test file that will trigger notify
f2, err := os.Create(filepath.Clean(filepath.Join(rd, "test2.txt")))
if err != nil {
	fmt.Printf("could not create test file2 %s, error: %s", rd, err)
	return
}
defer func() {
	if e := f2.Close(); e != nil {
		fmt.Printf("could not close file %s, error: %s", f2.Name(), e)
	}
}()

// wait until dummy listener is informed of the file creation
wg.Wait()

// cleanup
if err = watcher.Remove(rd); err != nil {
	fmt.Printf("could not remove test folder %s from notify, error: %s", rd, err)
	return
}
Output:
received event CREATE        "/tmp/testRWatcher_add/test2.txt"

func (*RWatcher) AddRecursive

func (m *RWatcher) AddRecursive(name string) error

AddRecursive starts watching the named directory and all sub-directories.

Example
// create test folder
rd := filepath.Join(os.TempDir(), "testRWatcher_recursive")
err := os.Mkdir(rd, 0o750)
if err != nil {
	fmt.Printf("could not create root test folder, error: %s", err)
	return
}
defer func() {
	if e := os.RemoveAll(rd); e != nil {
		fmt.Printf("could not remove test folder %s, error: %s", rd, e)
	}
}()
if err = os.MkdirAll(filepath.Join(rd, "a/b/c"), 0o750); err != nil {
	fmt.Printf("could not create test folders, error: %s", err)
	return
}

// create new watcher
watcher, err := NewWatcher()
if err != nil {
	fmt.Printf("could not create recursive watcher, error: %s", err)
	return
}

defer func() {
	if e := watcher.Close(); e != nil {
		fmt.Printf("could not close recursive watcher, error: %s", e)
	}
}()

// add test folder to be watched
err = watcher.AddRecursive(rd)
if err != nil {
	fmt.Printf("could not add recursive folder %s, error: %s", rd, err)
	return
}

// create new monitored folder
if err = os.MkdirAll(filepath.Join(rd, "a/b/c/d"), 0o750); err != nil {
	fmt.Printf("could not create test folders, error: %s", err)
	return
}

// dump folder creation event

<-watcher.Events

// add dummy event listener, real one must use a controlled loop
wg := sync.WaitGroup{}
wg.Go(func() {
	event, ok := <-watcher.Events
	if !ok {
		fmt.Printf("ko event")
		return
	}
	fmt.Printf("received event %s", event)
})

// create a test file
f, err := os.Create(filepath.Clean(filepath.Join(rd, "a/b/c/d", "test.txt")))
if err != nil {
	fmt.Printf("could not create test file %s, error: %s", rd, err)
	return
}
defer func() {
	if e := f.Close(); e != nil {
		fmt.Printf("could not close file %s, error: %s", f.Name(), e)
	}
}()

// wait until dummy listener is informed of the file creation
wg.Wait()

// cleanup
if err = watcher.RemoveRecursive(rd); err != nil {
	fmt.Printf("could not remove test folder %s from notify, error: %s", rd, err)
	return
}
Output:
received event CREATE        "/tmp/testRWatcher_recursive/a/b/c/d/test.txt"

func (*RWatcher) Close

func (m *RWatcher) Close() error

Close removes all watches and closes the events channel.

func (*RWatcher) Remove

func (m *RWatcher) Remove(name string) error

Remove stops watching the the named file or directory (non-recursively).

func (*RWatcher) RemoveRecursive

func (m *RWatcher) RemoveRecursive(name string) error

RemoveRecursive stops watching the named directory and all sub-directories.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL