more initial changes
This commit is contained in:
@@ -2,33 +2,125 @@ package watcher
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
|
||||
"mediawatcher/internal/config"
|
||||
"mediawatcher/internal/util"
|
||||
)
|
||||
|
||||
type FileHandler func(path string)
|
||||
|
||||
func WatchDirs(dirs []string, handler FileHandler) error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer watcher.Close()
|
||||
type Watcher struct {
|
||||
cfg *config.Config
|
||||
watcher *fsnotify.Watcher
|
||||
pending map[string]struct{}
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
for _, d := range dirs {
|
||||
if err := watcher.Add(d); err != nil {
|
||||
func New(cfg *config.Config) (*Watcher, error) {
|
||||
w, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Watcher{
|
||||
cfg: cfg,
|
||||
watcher: w,
|
||||
pending: make(map[string]struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *Watcher) Close() error {
|
||||
return w.watcher.Close()
|
||||
}
|
||||
|
||||
func (w *Watcher) Start(handler FileHandler) error {
|
||||
for _, dir := range w.cfg.Watch.Dirs {
|
||||
if err := w.addDir(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
go w.loop(handler)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Watcher) addDir(dir string) error {
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[watch] watching %s", dir)
|
||||
return w.watcher.Add(dir)
|
||||
}
|
||||
|
||||
func (w *Watcher) loop(handler FileHandler) {
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
if event.Op&(fsnotify.Create|fsnotify.Write) != 0 {
|
||||
handler(event.Name)
|
||||
case event, ok := <-w.watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if event.Op&(fsnotify.Create|fsnotify.Write|fsnotify.Rename) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
case err := <-watcher.Errors:
|
||||
log.Printf("Watcher error: %v\n", err)
|
||||
path := event.Name
|
||||
info, err := os.Stat(path)
|
||||
if err != nil || info.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
extIncl := util.HasExt(path, w.cfg.Watch.IncludeExt)
|
||||
extExcl := util.HasExt(path, w.cfg.Watch.ExcludeExt)
|
||||
if !extIncl || extExcl {
|
||||
continue
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
if _, exists := w.pending[path]; exists {
|
||||
w.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
w.pending[path] = struct{}{}
|
||||
w.mu.Unlock()
|
||||
|
||||
go w.handleFile(path, handler)
|
||||
|
||||
case err, ok := <-w.watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Printf("[watch] error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) handleFile(path string, handler FileHandler) {
|
||||
defer func() {
|
||||
w.mu.Lock()
|
||||
delete(w.pending, path)
|
||||
w.mu.Unlock()
|
||||
}()
|
||||
|
||||
stableFor := time.Duration(w.cfg.Watch.StableSeconds) * time.Second
|
||||
if err := util.WaitForStable(path, stableFor, 2*time.Hour); err != nil {
|
||||
log.Printf("[watch] file %s not stable: %v", path, err)
|
||||
return
|
||||
}
|
||||
|
||||
abs, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
abs = path
|
||||
}
|
||||
|
||||
handler(abs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user