diff --git a/helpers/watcher.go b/helpers/watcher.go index 2e3f768..5028968 100644 --- a/helpers/watcher.go +++ b/helpers/watcher.go @@ -1,38 +1,93 @@ package helpers import ( + "errors" + "io/fs" "log" + "path/filepath" + "sync" + "time" "github.com/fsnotify/fsnotify" ) +var NotInitializedError = errors.New("FileWatcher not initialized") +var NoWatchFunctionError = errors.New("No watch function provided") + type IFileWatcher interface { - GetEvents() chan string + RecursiveDir(path string) error + Dir(path string) error + Append(fn func(string)) + Prepend(fn func(string)) + Watch() error + Close() + Restart() } type FileWatcher struct { - path []string - events chan string + mu sync.Mutex + wf []func(string) + paths []string watcher *fsnotify.Watcher } -func NewFileWatcher(path []string) (*FileWatcher, error) { - fw := &FileWatcher{path: path, events: make(chan string, 48)} - err := fw.Watch(path) - if err != nil { - return nil, err - } +func NewFileWatcher() (*FileWatcher, error) { + + fw := &FileWatcher{mu: sync.Mutex{}} + fw.Watch() return fw, nil } -func (fw *FileWatcher) Watch(paths []string) error { - fw.events = make(chan string, 48) +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() { @@ -44,7 +99,12 @@ func (fw *FileWatcher) Watch(paths []string) error { } log.Println("event:", event) if !event.Has(fsnotify.Chmod) { - fw.events <- event.Name + time.Sleep(50 * time.Millisecond) + fw.mu.Lock() + for _, wf := range fw.wf { + wf(event.Name) + } + fw.mu.Unlock() } case err, ok := <-watcher.Errors: if !ok { @@ -55,21 +115,23 @@ func (fw *FileWatcher) Watch(paths []string) error { } }() - for _, path := range paths { - err = watcher.Add(path) - if err != nil { - return err - } - } - return nil } -func (fw *FileWatcher) GetEvents() chan string { - return fw.events +// 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) Close() { - fw.watcher.Close() - close(fw.events) +func (fw *FileWatcher) Restart() { + fw.Close() + fw.Watch() } diff --git a/server/server.go b/server/server.go index 8fd2683..d2b16d5 100644 --- a/server/server.go +++ b/server/server.go @@ -2,8 +2,7 @@ package server import ( "fmt" - "io/fs" - "path/filepath" + "log" "sync" "time" @@ -47,6 +46,8 @@ type Server struct { running chan bool shutdown *sync.WaitGroup cache *memory.Storage + + watcher *helpers.FileWatcher } func Start(k *app.KGPZ, c *providers.ConfigProvider) *Server { @@ -55,33 +56,23 @@ func Start(k *app.KGPZ, c *providers.ConfigProvider) *Server { } } -// INFO: this is a hacky way to add watchers to the server, which will restart the server if the files change -// It is very rudimentary and just restarts everything -// TODO: send a reload on a websocket -func (e *Server) AddWatchers(paths []string) error { - var dirs []string - for _, path := range paths { - // Get all subdirectories for paths - filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { - if d.IsDir() { - dirs = append(dirs, path) - } - return nil - }) - } +func (s *Server) Watcher() error { + watcher, err := helpers.NewFileWatcher() + s.watcher = watcher + s.watcher.Append(func(path string) { + log.Println("Restarting server") + s.Restart() + }) - watcher, err := helpers.NewFileWatcher(dirs) + err = s.watcher.RecursiveDir(ROUTES_FILEPATH) if err != nil { return err } - go func() { - w := watcher.GetEvents() - <-w - watcher.Close() - time.Sleep(200 * time.Millisecond) - e.Restart() - }() + err = s.watcher.RecursiveDir(LAYOUT_FILEPATH) + if err != nil { + return err + } return nil } @@ -149,7 +140,7 @@ func (s *Server) Start() { s.runner(srv) if s.Config.Debug { - err := s.AddWatchers([]string{ROUTES_FILEPATH, LAYOUT_FILEPATH}) + err := s.Watcher() if err != nil { fmt.Println(err) } diff --git a/views/routes/body.tmpl b/views/routes/body.tmpl index 62c2052..2d49a94 100644 --- a/views/routes/body.tmpl +++ b/views/routes/body.tmpl @@ -1,3 +1,3 @@ {{ define "body" }} -
Changed again! Hello from body
+Change! Hello from body
{{ end }}