mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-28 16:45:32 +00:00
134 lines
2.3 KiB
Go
134 lines
2.3 KiB
Go
package helpers
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/Theodor-Springmann-Stiftung/kgpz_web/helpers/logging"
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
var NotInitializedError = errors.New("FileWatcher not initialized")
|
|
var NoWatchFunctionError = errors.New("No watch function provided")
|
|
|
|
type IFileWatcher interface {
|
|
RecursiveDir(path string) error
|
|
Dir(path string) error
|
|
Append(fn func(string))
|
|
Prepend(fn func(string))
|
|
Watch() error
|
|
Close()
|
|
Restart()
|
|
}
|
|
|
|
type FileWatcher struct {
|
|
mu sync.Mutex
|
|
wf []func(string)
|
|
paths []string
|
|
watcher *fsnotify.Watcher
|
|
}
|
|
|
|
func NewFileWatcher() (*FileWatcher, error) {
|
|
fw := &FileWatcher{mu: sync.Mutex{}}
|
|
fw.Watch()
|
|
return fw, nil
|
|
}
|
|
|
|
func (fw *FileWatcher) RecursiveDir(path string) error {
|
|
err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
|
|
if d.IsDir() {
|
|
err := fw.Dir(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func (fw *FileWatcher) Dir(path string) error {
|
|
fw.mu.Lock()
|
|
defer fw.mu.Unlock()
|
|
if fw.watcher != nil {
|
|
err := fw.watcher.Add(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
fw.paths = append(fw.paths, path)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (fw *FileWatcher) Append(fn func(string)) {
|
|
fw.mu.Lock()
|
|
defer fw.mu.Unlock()
|
|
fw.wf = append(fw.wf, fn)
|
|
}
|
|
|
|
func (fw *FileWatcher) Prepend(fn func(string)) {
|
|
fw.mu.Lock()
|
|
defer fw.mu.Unlock()
|
|
fw.wf = append([]func(string){fn}, fw.wf...)
|
|
}
|
|
|
|
func (fw *FileWatcher) Watch() error {
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fw.mu.Lock()
|
|
fw.watcher = watcher
|
|
fw.mu.Unlock()
|
|
|
|
// Start listening for events.
|
|
go func() {
|
|
for {
|
|
select {
|
|
case event, ok := <-watcher.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
if !event.Has(fsnotify.Chmod) {
|
|
fw.mu.Lock()
|
|
for _, wf := range fw.wf {
|
|
wf(event.Name)
|
|
}
|
|
fw.mu.Unlock()
|
|
}
|
|
case err, ok := <-watcher.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
logging.Error(err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
// INFO: After closing the watcher, you can't use it anymore.
|
|
// Also, after a restart, you need to re add the paths
|
|
func (fw *FileWatcher) Close() {
|
|
fw.mu.Lock()
|
|
defer fw.mu.Unlock()
|
|
|
|
if fw.watcher != nil {
|
|
fw.watcher.Close()
|
|
}
|
|
fw.watcher = nil
|
|
fw.paths = nil
|
|
}
|
|
|
|
func (fw *FileWatcher) Restart() {
|
|
fw.Close()
|
|
fw.Watch()
|
|
}
|