From 522f6cb455d1241b63610ef4a5b142b996cfeae6 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 17 May 2021 13:43:36 +0800 Subject: [PATCH] fix issue of failing in folder watching with no recursive option for package gfsnotify --- os/gfsnotify/gfsnotify.go | 4 +- os/gfsnotify/gfsnotify_watcher_loop.go | 86 +++++++++++++------------- os/gfsnotify/gfsnotify_z_unit_test.go | 25 ++++++++ 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/os/gfsnotify/gfsnotify.go b/os/gfsnotify/gfsnotify.go index 07817a8e5..619454189 100644 --- a/os/gfsnotify/gfsnotify.go +++ b/os/gfsnotify/gfsnotify.go @@ -91,8 +91,8 @@ func New() (*Watcher, error) { intlog.Printf("New watcher failed: %v", err) return nil, err } - w.startWatchLoop() - w.startEventLoop() + w.watchLoop() + w.eventLoop() return w, nil } diff --git a/os/gfsnotify/gfsnotify_watcher_loop.go b/os/gfsnotify/gfsnotify_watcher_loop.go index a05c663de..531225051 100644 --- a/os/gfsnotify/gfsnotify_watcher_loop.go +++ b/os/gfsnotify/gfsnotify_watcher_loop.go @@ -11,8 +11,8 @@ import ( "github.com/gogf/gf/internal/intlog" ) -// startWatchLoop starts the loop for event listening fro underlying inotify monitor. -func (w *Watcher) startWatchLoop() { +// watchLoop starts the loop for event listening fro underlying inotify monitor. +func (w *Watcher) watchLoop() { go func() { for { select { @@ -40,47 +40,8 @@ func (w *Watcher) startWatchLoop() { }() } -// getCallbacks searches and returns all callbacks with given . -// It also searches its parent for callbacks if they're recursive. -func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) { - // Firstly add the callbacks of itself. - if v := w.callbacks.Get(path); v != nil { - for _, v := range v.(*glist.List).FrontAll() { - callback := v.(*Callback) - callbacks = append(callbacks, callback) - } - } - // Secondly searches its parent for callbacks. - dirPath := fileDir(path) - if v := w.callbacks.Get(dirPath); v != nil { - for _, v := range v.(*glist.List).FrontAll() { - callback := v.(*Callback) - if callback.recursive { - callbacks = append(callbacks, callback) - } - } - } - // Lastly searches the parent recursively for callbacks. - for { - parentDirPath := fileDir(dirPath) - if parentDirPath == dirPath { - break - } - if v := w.callbacks.Get(parentDirPath); v != nil { - for _, v := range v.(*glist.List).FrontAll() { - callback := v.(*Callback) - if callback.recursive { - callbacks = append(callbacks, callback) - } - } - } - dirPath = parentDirPath - } - return -} - -// startEventLoop is the core event handler. -func (w *Watcher) startEventLoop() { +// eventLoop is the core event handler. +func (w *Watcher) eventLoop() { go func() { for { if v := w.events.Pop(); v != nil { @@ -171,3 +132,42 @@ func (w *Watcher) startEventLoop() { } }() } + +// getCallbacks searches and returns all callbacks with given . +// It also searches its parents for callbacks if they're recursive. +func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) { + // Firstly add the callbacks of itself. + if v := w.callbacks.Get(path); v != nil { + for _, v := range v.(*glist.List).FrontAll() { + callback := v.(*Callback) + callbacks = append(callbacks, callback) + } + } + // Secondly searches its direct parent for callbacks. + // It is special handling here, which is the different between `recursive` and `not recursive` logic + // for direct parent folder of `path` that events are from. + dirPath := fileDir(path) + if v := w.callbacks.Get(dirPath); v != nil { + for _, v := range v.(*glist.List).FrontAll() { + callback := v.(*Callback) + callbacks = append(callbacks, callback) + } + } + // Lastly searches all the parents of directory of `path` recursively for callbacks. + for { + parentDirPath := fileDir(dirPath) + if parentDirPath == dirPath { + break + } + if v := w.callbacks.Get(parentDirPath); v != nil { + for _, v := range v.(*glist.List).FrontAll() { + callback := v.(*Callback) + if callback.recursive { + callbacks = append(callbacks, callback) + } + } + } + dirPath = parentDirPath + } + return +} diff --git a/os/gfsnotify/gfsnotify_z_unit_test.go b/os/gfsnotify/gfsnotify_z_unit_test.go index a1f195dc1..2fecbb7f2 100644 --- a/os/gfsnotify/gfsnotify_z_unit_test.go +++ b/os/gfsnotify/gfsnotify_z_unit_test.go @@ -7,6 +7,7 @@ package gfsnotify_test import ( + "github.com/gogf/gf/container/garray" "testing" "time" @@ -191,3 +192,27 @@ func TestWatcher_Callback2(t *testing.T) { t.Assert(v2.Val(), 2) }) } + +func TestWatcher_WatchFolderWithoutRecursively(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + array = garray.New(true) + dirPath = gfile.TempDir(gtime.TimestampNanoStr()) + ) + err = gfile.Mkdir(dirPath) + t.AssertNil(err) + + _, err = gfsnotify.Add(dirPath, func(event *gfsnotify.Event) { + array.Append(1) + }, false) + t.AssertNil(err) + time.Sleep(time.Millisecond * 100) + t.Assert(array.Len(), 0) + + err = gfile.PutContents(gfile.Join(dirPath, "1"), "1") + t.AssertNil(err) + time.Sleep(time.Millisecond * 100) + t.Assert(array.Len(), 1) + }) +}