From 5050fea4f6b9923c876d423966619e616996efa3 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Thu, 6 Jan 2022 23:09:09 +0000 Subject: [PATCH 01/11] WATCHER: (WIP) Add queue --- watcher/queue.go | 35 +++++++++++++++++++++++++++++++++++ watcher/queue_test.go | 0 2 files changed, 35 insertions(+) create mode 100644 watcher/queue.go create mode 100644 watcher/queue_test.go diff --git a/watcher/queue.go b/watcher/queue.go new file mode 100644 index 0000000..9b9333c --- /dev/null +++ b/watcher/queue.go @@ -0,0 +1,35 @@ +package watcher + +import ( + "crypto/md5" + "fmt" + + "github.com/cian911/switchboard/event" +) + +type Queue struct { + queue map[string]event.Event +} + +func New() *Queue { + return &Queue{ + queue: make(map[string]event.Event), + } +} + +func (q *Queue) Add(hash string, ev event.Event) { + q.queue[hash] = ev +} + +func (q *Queue) Retrieve(hash string) event.Event { + return q.queue[hash] +} + +func (q *Queue) Remove(hash string) { + delete(q.queue, hash) +} + +func generateHash(ev event.Event) string { + data := []byte(fmt.Sprintf("%s%s%s%s", ev.File, ev.Path, ev.Destination, ev.Ext)) + return fmt.Sprintf("%x", md5.Sum(data)) +} diff --git a/watcher/queue_test.go b/watcher/queue_test.go new file mode 100644 index 0000000..e69de29 From 32809f86dd4c40b0f9397dac1f82fdd1de02c32a Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Thu, 6 Jan 2022 23:09:22 +0000 Subject: [PATCH 02/11] WATCHER: (WIP) Add poller --- watcher/poller.go | 12 ++++++++++++ watcher/poller_test.go | 0 2 files changed, 12 insertions(+) create mode 100644 watcher/poller.go create mode 100644 watcher/poller_test.go diff --git a/watcher/poller.go b/watcher/poller.go new file mode 100644 index 0000000..9b90c5d --- /dev/null +++ b/watcher/poller.go @@ -0,0 +1,12 @@ +package watcher + +import "time" + +func Poll(interval int) { + ticker := time.NewTicker(interval * time.Second) + for { + select { + case <-ticker.C: + } + } +} diff --git a/watcher/poller_test.go b/watcher/poller_test.go new file mode 100644 index 0000000..e69de29 From eeef14df1a991f17c73846d9152d3c15b79e2409 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Thu, 6 Jan 2022 23:09:38 +0000 Subject: [PATCH 03/11] EVENT: Add epoch timestamp to event struct --- event/event.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/event/event.go b/event/event.go index 0d9e8a7..bdc927b 100644 --- a/event/event.go +++ b/event/event.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "os" + "time" "github.com/cian911/switchboard/utils" ) @@ -22,6 +23,8 @@ type Event struct { Operation string // IsDir is the new create vent a directory IsDir bool + // Timestamp in unix time epoch + Timestamp int64 } // New creates and returns a new event struct @@ -31,6 +34,7 @@ func New(file, path, dest, ext string) *Event { Path: path, Destination: dest, Ext: ext, + Timestamp: time.Now().Unix(), } } From 4a197e08ae81fe82d6ebb3940e3f33f978953039 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Fri, 7 Jan 2022 10:49:44 +0000 Subject: [PATCH 04/11] WATCHER: Add package def to test files. --- watcher/poller_test.go | 1 + watcher/queue_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/watcher/poller_test.go b/watcher/poller_test.go index e69de29..8278790 100644 --- a/watcher/poller_test.go +++ b/watcher/poller_test.go @@ -0,0 +1 @@ +package watcher diff --git a/watcher/queue_test.go b/watcher/queue_test.go index e69de29..8278790 100644 --- a/watcher/queue_test.go +++ b/watcher/queue_test.go @@ -0,0 +1 @@ +package watcher From 91554dc316991fdcccdcdcfdde4de3f7e64a5ca8 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Sun, 9 Jan 2022 23:33:48 +0000 Subject: [PATCH 05/11] WATCHER: Make queue functional with poller --- watcher/poller.go | 19 ++++++++++++++--- watcher/queue.go | 42 ++++++++++++++++++++++++++------------ watcher/queue_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++ watcher/watcher.go | 30 ++++++++++++++++++++++----- 4 files changed, 117 insertions(+), 21 deletions(-) diff --git a/watcher/poller.go b/watcher/poller.go index 9b90c5d..1c7a110 100644 --- a/watcher/poller.go +++ b/watcher/poller.go @@ -1,12 +1,25 @@ package watcher -import "time" +import ( + "log" + "time" +) -func Poll(interval int) { - ticker := time.NewTicker(interval * time.Second) +// Poll polls the queue for valid events given an interval (in seconds) +func (pw *PathWatcher) Poll(interval int) { + ticker := time.NewTicker(time.Duration(interval) * time.Second) for { select { case <-ticker.C: + log.Printf("Polling... - Queue Size: %d\n", pw.Queue.Size()) + + for hsh, ev := range pw.Queue.Queue { + timeDiff := ev.Timestamp.Sub(time.Now()) + if timeDiff < (time.Duration(-interval) * time.Second) { + pw.Notify(ev.Path, ev.Operation) + pw.Queue.Remove(hsh) + } + } } } } diff --git a/watcher/queue.go b/watcher/queue.go index 9b9333c..91c536b 100644 --- a/watcher/queue.go +++ b/watcher/queue.go @@ -7,29 +7,45 @@ import ( "github.com/cian911/switchboard/event" ) -type Queue struct { - queue map[string]event.Event +// Q holds the Queue +type Q struct { + Queue map[string]event.Event } -func New() *Queue { - return &Queue{ - queue: make(map[string]event.Event), +// NewQueue create a new Q object +func NewQueue() *Q { + return &Q{ + Queue: make(map[string]event.Event), } } -func (q *Queue) Add(hash string, ev event.Event) { - q.queue[hash] = ev +// Add adds to the queue +func (q *Q) Add(ev event.Event) { + q.Queue[Hash(ev)] = ev } -func (q *Queue) Retrieve(hash string) event.Event { - return q.queue[hash] +// Retrieve get an item from the queue given a valid hash +func (q *Q) Retrieve(hash string) event.Event { + return q.Queue[hash] } -func (q *Queue) Remove(hash string) { - delete(q.queue, hash) +// Remove removes an item from the queue +func (q *Q) Remove(hash string) { + delete(q.Queue, hash) } -func generateHash(ev event.Event) string { - data := []byte(fmt.Sprintf("%s%s%s%s", ev.File, ev.Path, ev.Destination, ev.Ext)) +// Size returns the size of the queue +func (q *Q) Size() int { + return len(q.Queue) +} + +// Empty returns a bool indicating if the queue is empty or not +func (q *Q) Empty() bool { + return len(q.Queue) == 0 +} + +// Hash returns a md5 hash composed of an event File, Path, and Ext +func Hash(ev event.Event) string { + data := []byte(fmt.Sprintf("%s%s%s", ev.File, ev.Path, ev.Ext)) return fmt.Sprintf("%x", md5.Sum(data)) } diff --git a/watcher/queue_test.go b/watcher/queue_test.go index 8278790..8948402 100644 --- a/watcher/queue_test.go +++ b/watcher/queue_test.go @@ -1 +1,48 @@ package watcher + +import ( + "testing" + "time" + + "github.com/cian911/switchboard/event" +) + +func TestQueue(t *testing.T) { + t.Run("It adds one event to the queue", func(t *testing.T) { + q := setupQueue() + ev := testEvent() + + q.Add(*ev) + + if q.Size() != 1 { + t.Errorf("Could size did not increase as expected. want=%d, got=%d", 1, q.Size()) + } + }) + + t.Run("It updates the event in the queue", func(t *testing.T) { + q := setupQueue() + ev := testEvent() + + q.Add(*ev) + q.Add(*ev) + q.Add(*ev) + + if q.Size() != 1 { + // Queue size should not increase + t.Errorf("Could size did not increase as expected. want=%d, got=%d", 1, q.Size()) + } + }) +} + +func setupQueue() *Q { + return NewQueue() +} + +func testEvent() *event.Event { + return &event.Event{ + File: "sample.txt", + Path: "/var/sample.txt", + Ext: ".txt", + Timestamp: time.Now(), + } +} diff --git a/watcher/watcher.go b/watcher/watcher.go index e650fb0..4a32d4e 100644 --- a/watcher/watcher.go +++ b/watcher/watcher.go @@ -4,6 +4,7 @@ import ( "log" "os" "path/filepath" + "time" "github.com/cian911/switchboard/event" "github.com/cian911/switchboard/utils" @@ -18,7 +19,7 @@ type Producer interface { // Unregister a consumer from the producer Unregister(consumer *Consumer) // Notify consumers of an event - notify(path, event string) + Notify(path, event string) // Observe the producer Observe() } @@ -38,6 +39,8 @@ type Consumer interface { type PathWatcher struct { // List of consumers Consumers []*Consumer + // Queue + Queue *Q // Watcher instance Watcher fsnotify.Watcher // Path to watch @@ -67,6 +70,7 @@ func (pc *PathConsumer) Receive(path, ev string) { Path: path, Destination: pc.Destination, Ext: utils.ExtractFileExt(path), + Timestamp: time.Now(), Operation: ev, } @@ -86,7 +90,7 @@ func (pc *PathConsumer) Receive(path, ev string) { func (pc *PathConsumer) Process(e *event.Event) { err := e.Move(e.Path, "") if err != nil { - log.Fatalf("Unable to move file from { %s } to { %s }: %v", e.Path, e.Destination, err) + log.Printf("Unable to move file from { %s } to { %s }: %v\n", e.Path, e.Destination, err) } else { log.Println("Event has been processed.") } @@ -134,6 +138,11 @@ func (pw *PathWatcher) Unregister(consumer *Consumer) { // Observe the producer func (pw *PathWatcher) Observe() { + pw.Queue = NewQueue() + go func() { + pw.Poll(3) + }() + watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatalf("Could not create new watcher: %v", err) @@ -164,9 +173,10 @@ func (pw *PathWatcher) Observe() { case event := <-watcher.Events: if event.Op.String() == "CREATE" && utils.IsDir(event.Name) { watcher.Add(event.Name) + } else if event.Op.String() == "CREATE" || event.Op.String() == "WRITE" { + ev := newEvent(event.Name, event.Op.String()) + pw.Queue.Add(*ev) } - - pw.notify(event.Name, event.Op.String()) case err := <-watcher.Errors: log.Printf("Watcher encountered an error when observing %s: %v", pw.Path, err) } @@ -177,8 +187,18 @@ func (pw *PathWatcher) Observe() { } // Notify consumers of an event -func (pw *PathWatcher) notify(path, event string) { +func (pw *PathWatcher) Notify(path, event string) { for _, cons := range pw.Consumers { (*cons).Receive(path, event) } } + +func newEvent(path, ev string) *event.Event { + return &event.Event{ + File: filepath.Base(path), + Path: path, + Ext: utils.ExtractFileExt(path), + Timestamp: time.Now(), + Operation: ev, + } +} From 71fed6d9da10ba7324ed3710914d66e17deded55 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Sun, 9 Jan 2022 23:35:27 +0000 Subject: [PATCH 06/11] CLI: Update logger --- cli/watch.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/watch.go b/cli/watch.go index a632f15..b11875e 100644 --- a/cli/watch.go +++ b/cli/watch.go @@ -154,5 +154,7 @@ func registerSingleConsumer() { } pw.Register(&pc) + + log.Println("Observing") pw.Observe() } From 83f024f595d311ad531c4686faf890a3f20cdb80 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Sun, 9 Jan 2022 23:35:52 +0000 Subject: [PATCH 07/11] EVENT: Add Timestamp to event struct. --- event/event.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/event/event.go b/event/event.go index bdc927b..a36d933 100644 --- a/event/event.go +++ b/event/event.go @@ -24,7 +24,7 @@ type Event struct { // IsDir is the new create vent a directory IsDir bool // Timestamp in unix time epoch - Timestamp int64 + Timestamp time.Time } // New creates and returns a new event struct @@ -34,7 +34,7 @@ func New(file, path, dest, ext string) *Event { Path: path, Destination: dest, Ext: ext, - Timestamp: time.Now().Unix(), + Timestamp: time.Now(), } } @@ -48,7 +48,7 @@ func (e *Event) Move(path, file string) error { // IsValidEvent checks if the event operation and file extension is valid func (e *Event) IsValidEvent(ext string) bool { - if ext == e.Ext && e.Operation == "CREATE" { + if ext == e.Ext && e.Operation == "CREATE" || e.Operation == "WRITE" { return true } From b46a23a3fafda377df6f5b310a959471f66a13ea Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Sun, 9 Jan 2022 23:36:16 +0000 Subject: [PATCH 08/11] CLI: Update logger. --- cli/watch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/watch.go b/cli/watch.go index b11875e..2d4844b 100644 --- a/cli/watch.go +++ b/cli/watch.go @@ -38,7 +38,7 @@ type Watcher struct { // Ext is the file extention you want to watch for Ext string `yaml:"ext"` // Operation is the event operation you want to watch for - // CREATE, MODIFY, REMOVE, CHMOD etc. + // CREATE, MODIFY, REMOVE, CHMOD, WRITE itc. Operation string `yaml:"operation"` } From 041bf85932d20d07d301f61dd7a5fbb172a2e8f7 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Mon, 10 Jan 2022 23:34:47 +0000 Subject: [PATCH 09/11] CLI: Add poll flag --- cli/watch.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cli/watch.go b/cli/watch.go index 2d4844b..f34c0f3 100644 --- a/cli/watch.go +++ b/cli/watch.go @@ -67,11 +67,13 @@ func initCmd(runCmd cobra.Command) { runCmd.PersistentFlags().StringP("path", "p", "", "Path you want to watch.") runCmd.PersistentFlags().StringP("destination", "d", "", "Path you want files to be relocated.") runCmd.PersistentFlags().StringP("ext", "e", "", "File type you want to watch for.") + runCmd.PersistentFlags().IntP("poll", "", 3, "Specify a polling time in seconds.") runCmd.PersistentFlags().StringVar(&configFile, "config", "", "Pass an optional config file containing multiple paths to watch.") viper.BindPFlag("path", runCmd.PersistentFlags().Lookup("path")) viper.BindPFlag("destination", runCmd.PersistentFlags().Lookup("destination")) viper.BindPFlag("ext", runCmd.PersistentFlags().Lookup("ext")) + viper.BindPFlag("poll", runCmd.PersistentFlags().Lookup("poll")) var rootCmd = &cobra.Command{} rootCmd.AddCommand(&runCmd) @@ -139,7 +141,7 @@ func registerMultiConsumers() { } log.Println("Observing") - pw.Observe() + pw.Observe(viper.GetInt("poll")) } func registerSingleConsumer() { @@ -156,5 +158,5 @@ func registerSingleConsumer() { pw.Register(&pc) log.Println("Observing") - pw.Observe() + pw.Observe(viper.GetInt("poll")) } From f987ec1d6d538c0f868e2a58c409ac31dbebada8 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Mon, 10 Jan 2022 23:35:43 +0000 Subject: [PATCH 10/11] WATCHER: Fix bug wherein multiple consumers will try and process the same event. Add tests for queue and poller. --- watcher/poller.go | 24 +++++++++-------- watcher/poller_test.go | 34 ++++++++++++++++++++++++ watcher/queue_test.go | 58 ++++++++++++++++++++++++++++++++++++----- watcher/watcher.go | 22 ++++++---------- watcher/watcher_test.go | 3 ++- 5 files changed, 109 insertions(+), 32 deletions(-) diff --git a/watcher/poller.go b/watcher/poller.go index 1c7a110..58adc29 100644 --- a/watcher/poller.go +++ b/watcher/poller.go @@ -7,19 +7,21 @@ import ( // Poll polls the queue for valid events given an interval (in seconds) func (pw *PathWatcher) Poll(interval int) { - ticker := time.NewTicker(time.Duration(interval) * time.Second) - for { - select { - case <-ticker.C: - log.Printf("Polling... - Queue Size: %d\n", pw.Queue.Size()) + go func() { + ticker := time.NewTicker(time.Duration(interval) * time.Second) + for { + select { + case <-ticker.C: + log.Printf("Polling... - Queue Size: %d\n", pw.Queue.Size()) - for hsh, ev := range pw.Queue.Queue { - timeDiff := ev.Timestamp.Sub(time.Now()) - if timeDiff < (time.Duration(-interval) * time.Second) { - pw.Notify(ev.Path, ev.Operation) - pw.Queue.Remove(hsh) + for hsh, ev := range pw.Queue.Queue { + timeDiff := ev.Timestamp.Sub(time.Now()) + if timeDiff < (time.Duration(-interval) * time.Second) { + pw.Notify(ev.Path, ev.Operation) + pw.Queue.Remove(hsh) + } } } } - } + }() } diff --git a/watcher/poller_test.go b/watcher/poller_test.go index 8278790..d47cf0c 100644 --- a/watcher/poller_test.go +++ b/watcher/poller_test.go @@ -1 +1,35 @@ package watcher + +import ( + "testing" + "time" +) + +var ( + pollInterval = 1 +) + +func TestPoller(t *testing.T) { + t.Run("It successfully notifies of a new event", func(t *testing.T) { + pw := setupPathwatcher("/tmp") + pw.Poll(pollInterval) + + ev := eventSetup(t) + pw.Queue.Add(*ev) + + if pw.Queue.Size() != 1 { + t.Errorf("Queue size did not increase. want=%d, got=%d", 1, pw.Queue.Size()) + } + <-time.After(3 * time.Second) + + if pw.Queue.Size() != 0 { + t.Errorf("Queue size did not decrease. want=%d, got=%d", 0, pw.Queue.Size()) + } + }) +} + +func setupPathwatcher(path string) *PathWatcher { + return &PathWatcher{ + Queue: NewQueue(), + } +} diff --git a/watcher/queue_test.go b/watcher/queue_test.go index 8948402..e9a2228 100644 --- a/watcher/queue_test.go +++ b/watcher/queue_test.go @@ -1,16 +1,23 @@ package watcher import ( + "reflect" "testing" "time" "github.com/cian911/switchboard/event" ) +var ( + gFile = "sample.txt" + gPath = "/var/sample.txt" + gExt = ".txt" +) + func TestQueue(t *testing.T) { t.Run("It adds one event to the queue", func(t *testing.T) { q := setupQueue() - ev := testEvent() + ev := testEvent(gFile, gPath, gExt) q.Add(*ev) @@ -21,7 +28,7 @@ func TestQueue(t *testing.T) { t.Run("It updates the event in the queue", func(t *testing.T) { q := setupQueue() - ev := testEvent() + ev := testEvent(gFile, gPath, gExt) q.Add(*ev) q.Add(*ev) @@ -32,17 +39,56 @@ func TestQueue(t *testing.T) { t.Errorf("Could size did not increase as expected. want=%d, got=%d", 1, q.Size()) } }) + + t.Run("It gets an item from the queue", func(t *testing.T) { + q := setupQueue() + ev := testEvent(gFile, gPath, gExt) + + hash := Hash(*ev) + q.Add(*ev) + e := q.Retrieve(hash) + + if !reflect.DeepEqual(ev, &e) { + t.Errorf("Events are not the same. want=%v, got=%v", ev, e) + } + }) + + t.Run("It removes an item from the queue", func(t *testing.T) { + q := setupQueue() + ev := testEvent(gFile, gPath, gExt) + + hash := Hash(*ev) + q.Add(*ev) + q.Remove(hash) + + if q.Size() != 0 { + t.Errorf("Could size did not increase as expected. want=%d, got=%d", 0, q.Size()) + } + }) + + t.Run("It returns a unique hash for a given event", func(t *testing.T) { + ev1 := testEvent(gFile, gPath, gExt) + ev2 := testEvent("sample2.txt", "/var/sample2.txt", ".txt") + + h1 := Hash(*ev1) + h2 := Hash(*ev2) + + if h1 == h2 { + t.Errorf("Hashes are the same when they shouldn't be. want=%s, got=%s", h1, h2) + } + }) } func setupQueue() *Q { return NewQueue() } -func testEvent() *event.Event { +func testEvent(file, path, ext string) *event.Event { return &event.Event{ - File: "sample.txt", - Path: "/var/sample.txt", - Ext: ".txt", + File: file, + Path: path, + Ext: ext, Timestamp: time.Now(), } + } diff --git a/watcher/watcher.go b/watcher/watcher.go index 4a32d4e..57c7d98 100644 --- a/watcher/watcher.go +++ b/watcher/watcher.go @@ -21,7 +21,7 @@ type Producer interface { // Notify consumers of an event Notify(path, event string) // Observe the producer - Observe() + Observe(pollInterval int) } // Consumer interface @@ -61,10 +61,6 @@ type PathConsumer struct { // Receive takes a path and an event operation, determines its validity // and passes it to be processed it if valid func (pc *PathConsumer) Receive(path, ev string) { - log.Printf("Event Received: %s, Path: %s\n", ev, path) - - // TODO: Move IsNewDirEvent to utils and call func on event struct - // TODO: If is a dir event, there should not be a file ext e := &event.Event{ File: filepath.Base(path), Path: path, @@ -74,14 +70,14 @@ func (pc *PathConsumer) Receive(path, ev string) { Operation: ev, } - if e.IsNewDirEvent() { - log.Println("Event is a new dir") + if !e.IsNewDirEvent() && ev != pc.Ext && filepath.Dir(path) != pc.Path { + // Do not process event for consumers not watching file + return + } - // Recursively scan dir for items with our ext - // Then add all recursive dirs as paths + if e.IsNewDirEvent() { pc.ProcessDirEvent(e) } else if e.IsValidEvent(pc.Ext) { - log.Println("Event is valid") pc.Process(e) } } @@ -137,11 +133,9 @@ func (pw *PathWatcher) Unregister(consumer *Consumer) { } // Observe the producer -func (pw *PathWatcher) Observe() { +func (pw *PathWatcher) Observe(pollInterval int) { pw.Queue = NewQueue() - go func() { - pw.Poll(3) - }() + pw.Poll(pollInterval) watcher, err := fsnotify.NewWatcher() if err != nil { diff --git a/watcher/watcher_test.go b/watcher/watcher_test.go index 9da731f..00d5e79 100644 --- a/watcher/watcher_test.go +++ b/watcher/watcher_test.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "testing" + "time" "github.com/cian911/switchboard/event" "github.com/cian911/switchboard/utils" @@ -59,7 +60,6 @@ func TestWatcher(t *testing.T) { pw, pc := setup(ev.Path, ev.Destination, ev.Ext) pw.Register(&pc) pw.Unregister(&pc) - t.Log("PATH: " + ev.Path + " FILE: " + ev.File) for i := 1; i <= 3; i++ { file := createTempFile(ev.Path, ".txt", t) @@ -112,6 +112,7 @@ func eventSetup(t *testing.T) *event.Event { Destination: t.TempDir(), Ext: ext, Operation: "CREATE", + Timestamp: time.Now(), } } From 9dd957d99f4fa167f333b93b8675c9eaa129fc84 Mon Sep 17 00:00:00 2001 From: Cian Gallagher Date: Mon, 10 Jan 2022 23:45:34 +0000 Subject: [PATCH 11/11] DOCS: Update ascii cinema video --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b7ae1df..b20be08 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Switchboard works by monitoring a directory you provide (or list of directories) See the video below as example. Here, I give switchboard a path to watch, a destination where I want matched files to move to, and the file extension of the type of files I want to move. -[![asciicast](https://asciinema.org/a/cWSUfcUCU4Wd5rQEs5Detf7gn.svg)](https://asciinema.org/a/cWSUfcUCU4Wd5rQEs5Detf7gn) +[![asciicast](https://asciinema.org/a/OwbnYltbn0jcSAGzfdmujwklJ.svg)](https://asciinema.org/a/OwbnYltbn0jcSAGzfdmujwklJ) ### Installation @@ -60,6 +60,7 @@ Flags: -e, --ext string File type you want to watch for. -h, --help help for watch -p, --path string Path you want to watch. + --poll int Specify a polling time in seconds. (default 3) ``` To get started quickly, you can run the following command, passing in the path, destination, and file extenstion you want to watch for. See the example below.