mirror of
				https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
				synced 2025-10-30 17:45:30 +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()
 | |
| }
 | 
