summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2022-03-06 23:33:53 +0700
committerShulhan <ms@kilabit.info>2022-03-07 02:49:38 +0700
commit707e43921181505f252f94fff53aada17dfd4f95 (patch)
treea85ccbe7e72ee8c2bec608dd57699453355e0799
parent456bbd1166fd87984d98fbc6029b5ce9798e451b (diff)
downloadpakakeh.go-707e43921181505f252f94fff53aada17dfd4f95.tar.xz
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.
-rw-r--r--lib/memfs/memfs.go42
-rw-r--r--lib/memfs/memfs_example_test.go71
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: <nil>
+}