From 707e43921181505f252f94fff53aada17dfd4f95 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Sun, 6 Mar 2022 23:33:53 +0700 Subject: lib/memfs: add method Watch to MemFS The Watch method create and start a DirWatcher that ready to be consumed. This is to simplify watching an existing MemFS instance because the internal fs inside the DirWatcher is not exported. --- lib/memfs/memfs.go | 42 +++++++++++++++++++++--- lib/memfs/memfs_example_test.go | 71 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/lib/memfs/memfs.go b/lib/memfs/memfs.go index 79caae1d..a1cfa331 100644 --- a/lib/memfs/memfs.go +++ b/lib/memfs/memfs.go @@ -35,8 +35,10 @@ type MemFS struct { PathNodes *PathNode Root *Node Opts *Options - incRE []*regexp.Regexp - excRE []*regexp.Regexp + dw *DirWatcher + + incRE []*regexp.Regexp + excRE []*regexp.Regexp } // @@ -316,9 +318,11 @@ func (mfs *MemFS) Open(path string) (http.File, error) { // If child is not part if node's childrens it will return nil. // func (mfs *MemFS) RemoveChild(parent *Node, child *Node) (removed *Node) { - removed = parent.removeChild(child) - if removed != nil { - mfs.PathNodes.Delete(removed.Path) + if parent != nil { + removed = parent.removeChild(child) + if removed != nil { + mfs.PathNodes.Delete(removed.Path) + } } return } @@ -402,6 +406,34 @@ func (mfs *MemFS) Update(node *Node, newInfo os.FileInfo) { } } +// +// Watch create and start the DirWatcher that monitor the memfs Root +// directory. +// The MemFS will update the tree and node content automatically if the file +// get deleted or updated. +// The returned channel nsq is ready to be consumed. +// +func (mfs *MemFS) Watch(d time.Duration) (dw *DirWatcher, err error) { + var ( + logp = "Watch" + ) + + dw = &DirWatcher{ + fs: mfs, + Delay: d, + Options: *mfs.Opts, + } + + err = dw.Start() + if err != nil { + // There should be no error here, since we already check and + // filled the required fields for DirWatcher. + return nil, fmt.Errorf("%s: %w", logp, err) + } + + return dw, nil +} + func (mfs *MemFS) createRoot() error { logp := "createRoot" diff --git a/lib/memfs/memfs_example_test.go b/lib/memfs/memfs_example_test.go index 250d7949..25f257e2 100644 --- a/lib/memfs/memfs_example_test.go +++ b/lib/memfs/memfs_example_test.go @@ -2,7 +2,11 @@ package memfs import ( "fmt" + "io/ioutil" "log" + "os" + "path/filepath" + "time" ) func ExampleNew() { @@ -87,3 +91,70 @@ func ExampleMemFS_Search() { // Path: /index.css // Snippets: ["body {\n}\n"] } + +func ExampleMemFS_Watch() { + var ( + mfs *MemFS + dw *DirWatcher + node *Node + opts Options + ns NodeState + err error + ) + + opts.Root, err = ioutil.TempDir("", "memfs_watch") + if err != nil { + log.Fatal(err) + } + + defer func() { + _ = os.RemoveAll(opts.Root) + }() + + mfs, err = New(&opts) + if err != nil { + log.Fatal(err) + } + + dw, err = mfs.Watch(200 * time.Millisecond) + if err != nil { + log.Fatal(err) + } + + // Wait for the goroutine on Watch run. + time.Sleep(200 * time.Millisecond) + + testFile := filepath.Join(opts.Root, "file") + err = os.WriteFile(testFile, []byte("dummy content"), 0700) + if err != nil { + log.Fatal(err) + } + + ns = <-dw.C + fmt.Printf("State: %s\n", ns.State) + + node, err = mfs.Get("/file") + if err != nil { + log.Fatal(err) + } + fmt.Printf("Node: %s: %q\n", node.Path, node.Content) + + err = os.Remove(testFile) + if err != nil { + log.Fatal(err) + } + + ns = <-dw.C + fmt.Printf("State: %s\n", ns.State) + + node, _ = mfs.Get("/file") + fmt.Printf("Node: %s: %v\n", ns.Node.Path, node) + + dw.Stop() + + //Output: + //State: FileStateCreated + //Node: /file: "dummy content" + //State: FileStateDeleted + //Node: /file: +} -- cgit v1.3