recwatch

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jan 7, 2020 License: BSD-2-Clause Imports: 14 Imported by: 4

README

recwatch

Build Status

Watch filesystem changes recursively.

recwatch started out as a fork of looper (by Nathan Youngman), but most of the code is now original.

Features and limitations

  • Can be used for watching filesystem changes recursively.
  • Can be used for setting up a SSE (server-sent events) server, for serving filesystem changes as events.
  • Filenames beginning with . or _ are ignored.
  • The file search is concurrent.
  • Will follow symlinks.

Example usage

Short example
recwatch.EventServer(pathToWatch, "*", eventAddr, eventPath, refreshDuration)
Longer example
package main

import (
	"github.com/xyproto/recwatch"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"time"
)

func plural(passed time.Duration) string {
	if passed.Seconds() != 1 {
		return "s"
	}
	return ""
}

// Some errors are ignored since this is just a quick example
func main() {
	eventAddr := "0.0.0.0:5555"
	eventPath := "/"
	pathToWatch := "tempdir"
	refreshDuration, err := time.ParseDuration("350ms")
	if err != nil {
		log.Fatalln(err)
	}
	now := time.Now().UTC()
	_ = os.Mkdir(pathToWatch, 0755)
	recwatch.EventServer(pathToWatch, "*", eventAddr, eventPath, refreshDuration)
	URL := "http://" + strings.Replace(eventAddr, "0.0.0.0", "localhost", 1) + eventPath
	log.Printf("Serving filesystem events for %s as SSE (server-sent events) on %s\n", pathToWatch, URL)
	tempFileName := filepath.Join(pathToWatch, "hello.txt")
	_ = os.Remove(tempFileName)
	// Set up a handler for SIGINT (ctrl-c)
	quit := false
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for range c {
			// ctrl-c was pressed
			quit = true
			log.Println("ctrl-c was pressed, cleaning up")
			_ = os.Remove(tempFileName)
			_ = os.Remove(pathToWatch) // will only remove the directory if it's empty
			log.Println("done")
		}
	}()
	for {
		passed := time.Since(now)
		log.Printf("%.0f second%s passed. Visit %s to see events appear.\n", passed.Seconds(), plural(passed), URL)
		time.Sleep(1 * time.Second)
		if quit {
			break
		}
		log.Println("Creating and writing to " + tempFileName)
		data := []byte("Hi\n")
		err := ioutil.WriteFile(tempFileName, data, 0644)
		if err != nil {
			log.Fatal(err)
		}
		time.Sleep(1 * time.Second)
		if quit {
			break
		}
		log.Println("Removing " + tempFileName)
		err = os.Remove(tempFileName)
		if err != nil {
			log.Fatal(err)
		}
		time.Sleep(1 * time.Second)
		if quit {
			break
		}
		if passed.Seconds() > 200 {
			log.Println("Time waits for no man.")
		}
	}
}

General info

Documentation

Overview

Package recwatch provides a way to watch directories recursively, using fsnotify

Index

Constants

This section is empty.

Variables

View Source
var Exists = func(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

Exists checks if the given path exists, using os.Stat

View Source
var FatalExit = func(err error) {
	log.Fatalln(err)
}

FatalExit ends the program after logging a message

View Source
var LogError = func(err error) {
	log.Println(err.Error())
}

LogError logs a message as an error, but does not end the program

View Source
var LogInfo = func(msg string) {
	log.Println(msg)
}

LogInfo logs a message as information

Functions

func CollectFileChangeEvents

func CollectFileChangeEvents(watcher *RecursiveWatcher, mut *sync.Mutex, events TimeEventMap, maxAge time.Duration)

CollectFileChangeEvents gathers filesystem events in a way that web handle functions can use

func EventServer

func EventServer(path, allowed, eventAddr, eventPath string, refreshDuration time.Duration)

EventServer serves events on a dedicated port. addr is the host address ([host][:port]) The filesystem events are gathered independently of that. Allowed can be "*" or a hostname and sets a header in the SSE stream.

func Flush

func Flush(w http.ResponseWriter) bool

Flush can flush the given ResponseWriter. Returns false if it wasn't an http.Flusher.

func GenFileChangeEvents

func GenFileChangeEvents(events TimeEventMap, mut *sync.Mutex, maxAge time.Duration, allowed string) http.HandlerFunc

GenFileChangeEvents creates an SSE event whenever a file in the server directory changes.

Uses the following HTTP headers:

Content-Type: text/event-stream;charset=utf-8
Cache-Control: no-cache
Connection: keep-alive
Access-Control-Allow-Origin: (custom value)

The "Access-Control-Allow-Origin" header uses the value that is passed in the "allowed" argument.

func RemoveOldEvents

func RemoveOldEvents(events *TimeEventMap, maxAge time.Duration)

RemoveOldEvents can remove old filesystem events, after a certain duration. Needs to be called within a mutex!

func SetVerbose

func SetVerbose(enabled bool)

SetVerbose can be used to enable or disable logging of incoming events

func ShouldIgnoreFile

func ShouldIgnoreFile(name string) bool

ShouldIgnoreFile determines if a file should be ignored. File names that begin with "." or "_" are ignored by the go tool.

func Subfolders

func Subfolders(path string) (paths []string)

Subfolders returns a slice of subfolders (recursive), including the provided path

func WriteEvent

func WriteEvent(w http.ResponseWriter, id *uint64, message string, flush bool)

WriteEvent writes SSE events to the given ResponseWriter. id can be nil.

Types

type Event

type Event fsnotify.Event

Event is a custom type, so that packages that depends on recwatch does not also have to import fstnotify

func (Event) String

func (e Event) String() string

type RecursiveWatcher

type RecursiveWatcher struct {
	*fsnotify.Watcher
	Files   chan string
	Folders chan string
}

RecursiveWatcher keeps the data for watching files and directories

func NewRecursiveWatcher

func NewRecursiveWatcher(path string) (*RecursiveWatcher, error)

NewRecursiveWatcher creates a new RecursiveWatcher. Takes a path to a directory to watch.

func (*RecursiveWatcher) AddFolder

func (watcher *RecursiveWatcher) AddFolder(folder string) error

AddFolder adds a directory to watch, non-recursively

type TimeEventMap

type TimeEventMap map[time.Time]Event

TimeEventMap stores filesystem events

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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