From 0fce6c8c2cadf940d70dd7a45622f06c24d14bda Mon Sep 17 00:00:00 2001 From: Volker Schukai <volker.schukai@schukai.com> Date: Sat, 9 Sep 2023 22:44:21 +0200 Subject: [PATCH] chore: setup project --- .idea/.gitignore | 8 ++++ .idea/aws.xml | 17 ++++++++ .idea/libraries/fs.xml | 9 ++++ .idea/libraries/testdata.xml | 36 +++++++++++++++ .idea/libraries/zoneinfo.xml | 9 ++++ .idea/markdown.xml | 9 ++++ .idea/misc.xml | 6 +++ .idea/modules.xml | 8 ++++ .idea/vcs.xml | 6 +++ .idea/watch.iml | 10 +++++ go.mod | 5 +++ go.sum | 4 ++ watch.go | 85 ++++++++++++++++++++++++++++++++++++ watch_test.go | 47 ++++++++++++++++++++ 14 files changed, 259 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/aws.xml create mode 100644 .idea/libraries/fs.xml create mode 100644 .idea/libraries/testdata.xml create mode 100644 .idea/libraries/zoneinfo.xml create mode 100644 .idea/markdown.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/watch.iml create mode 100644 go.sum create mode 100644 watch.go create mode 100644 watch_test.go diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/aws.xml b/.idea/aws.xml new file mode 100644 index 0000000..ec328d0 --- /dev/null +++ b/.idea/aws.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="accountSettings"> + <option name="activeProfile" value="profile:default" /> + <option name="activeRegion" value="eu-west-1" /> + <option name="recentlyUsedProfiles"> + <list> + <option value="profile:default" /> + </list> + </option> + <option name="recentlyUsedRegions"> + <list> + <option value="eu-west-1" /> + </list> + </option> + </component> +</project> \ No newline at end of file diff --git a/.idea/libraries/fs.xml b/.idea/libraries/fs.xml new file mode 100644 index 0000000..8b6d565 --- /dev/null +++ b/.idea/libraries/fs.xml @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="fs"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/html/template/testdata/fs.zip!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/testdata.xml b/.idea/libraries/testdata.xml new file mode 100644 index 0000000..35c65e8 --- /dev/null +++ b/.idea/libraries/testdata.xml @@ -0,0 +1,36 @@ +<component name="libraryTable"> + <library name="testdata"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-22738.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/crc32-not-streamed.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-win7.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/test-trailing-junk.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/readme.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/zip64.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/utf8-winzip.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-7zip.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/winxp.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/utf8-infozip.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-osx.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/test.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-infozip.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-go.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/utf8-osx.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/zip64-2.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/test-prefix.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/dupdir.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/go-with-datadesc-sig.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/unix.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/utf8-winrar.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/utf8-7zip.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/dd.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/symlink.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-winzip.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/time-winrar.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/subdir.zip!/" /> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/src/archive/zip/testdata/test-baddirsz.zip!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/zoneinfo.xml b/.idea/libraries/zoneinfo.xml new file mode 100644 index 0000000..4d0d4c0 --- /dev/null +++ b/.idea/libraries/zoneinfo.xml @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="zoneinfo"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/.devenv/profile/share/go/lib/time/zoneinfo.zip!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file diff --git a/.idea/markdown.xml b/.idea/markdown.xml new file mode 100644 index 0000000..ec0b30f --- /dev/null +++ b/.idea/markdown.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="MarkdownSettings"> + <enabledExtensions> + <entry key="MermaidLanguageExtension" value="false" /> + <entry key="PlantUMLLanguageExtension" value="true" /> + </enabledExtensions> + </component> +</project> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f355a0c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/watch.iml" filepath="$PROJECT_DIR$/.idea/watch.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/.idea/watch.iml b/.idea/watch.iml new file mode 100644 index 0000000..25ed3f6 --- /dev/null +++ b/.idea/watch.iml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="Go" enabled="true" /> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file diff --git a/go.mod b/go.mod index d1381c6..dae053a 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,8 @@ module gitlab.schukai.com/oss/libraries/go/utilities/watch go 1.20 + +require ( + golang.org/x/sys v0.12.0 // indirect + gopkg.in/fsnotify.v1 v1.6.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8150683 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/watch.go b/watch.go new file mode 100644 index 0000000..b7c9791 --- /dev/null +++ b/watch.go @@ -0,0 +1,85 @@ +package watch + +import ( + "gopkg.in/fsnotify.v1" + "sync" +) + +type WatchEvent int + +const ( + FileChanged WatchEvent = iota + FileAdded + FileDeleted + FileRemoved +) + +type EventHandler func(string, WatchEvent) + +type Watch struct { + watcher *fsnotify.Watcher + handlers map[string]EventHandler + queue chan string + mu sync.Mutex +} + +func NewWatch() (*Watch, error) { + w, err := fsnotify.NewWatcher() + if err != nil { + return nil, err + } + return &Watch{ + watcher: w, + handlers: make(map[string]EventHandler), + queue: make(chan string, 100), + }, nil +} + +func (w *Watch) Add(path string, handler EventHandler) error { + w.mu.Lock() + defer w.mu.Unlock() + w.handlers[path] = handler + return w.watcher.Add(path) +} + +func (w *Watch) Remove(path string) error { + w.mu.Lock() + defer w.mu.Unlock() + delete(w.handlers, path) + return w.watcher.Remove(path) +} + +func (w *Watch) startWorker(concurrency int) { + for i := 0; i < concurrency; i++ { + go func() { + for path := range w.queue { + if handler, exists := w.handlers[path]; exists { + handler(path, FileChanged) + } + } + }() + } +} + +func (w *Watch) Watch(concurrency int) { + w.startWorker(concurrency) + + for { + select { + case event := <-w.watcher.Events: + if handler, exists := w.handlers[event.Name]; exists { + we := FileChanged // Map fsnotify events to WatchEvent here + w.queue <- event.Name + handler(event.Name, we) + } + case err := <-w.watcher.Errors: + // Handle errors + println("Error:", err) + } + } +} + +func (w *Watch) Stop() { + close(w.queue) + w.watcher.Close() +} diff --git a/watch_test.go b/watch_test.go new file mode 100644 index 0000000..9ac9a06 --- /dev/null +++ b/watch_test.go @@ -0,0 +1,47 @@ +package watch + +import ( + "io/ioutil" + "os" + "testing" + "time" +) + +func TestWatch(t *testing.T) { + w, err := NewWatch() + if err != nil { + t.Fatal(err) + } + + tmpFile, err := ioutil.TempFile("", "watch_test") + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpFile.Name()) + + called := make(chan bool) + handler := func(path string, event WatchEvent) { + if path == tmpFile.Name() && event == FileChanged { + called <- true + } + } + + if err := w.Add(tmpFile.Name(), handler); err != nil { + t.Fatal(err) + } + + go w.Watch(1) + defer w.Stop() + + _, err = tmpFile.WriteString("test") + if err != nil { + t.Fatal(err) + } + + select { + case <-called: + // Success + case <-time.After(time.Second * 2): + t.Fatal("Event handler not called") + } +} -- GitLab