docproc/watcher/watcher.go

104 lines
1.9 KiB
Go

package watcher
import (
"log"
"os"
"path/filepath"
"strings"
"time"
"docproc/processor"
"github.com/fsnotify/fsnotify"
)
type Watcher struct {
proc *processor.Processor
watcher *fsnotify.Watcher
inbox string
stop chan struct{}
}
func New(proc *processor.Processor) (*Watcher, error) {
homeDir, _ := os.UserHomeDir()
inbox := filepath.Join(homeDir, "documents", "inbox")
// Ensure inbox exists
os.MkdirAll(inbox, 0755)
fsWatcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
if err := fsWatcher.Add(inbox); err != nil {
fsWatcher.Close()
return nil, err
}
return &Watcher{
proc: proc,
watcher: fsWatcher,
inbox: inbox,
stop: make(chan struct{}),
}, nil
}
func (w *Watcher) Watch() {
// Process any existing files first
w.processExisting()
for {
select {
case event, ok := <-w.watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Create == fsnotify.Create {
// Small delay to ensure file is fully written
time.Sleep(500 * time.Millisecond)
w.processFile(event.Name)
}
case err, ok := <-w.watcher.Errors:
if !ok {
return
}
log.Printf("Watcher error: %v", err)
case <-w.stop:
return
}
}
}
func (w *Watcher) processExisting() {
entries, err := os.ReadDir(w.inbox)
if err != nil {
log.Printf("Failed to read inbox: %v", err)
return
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
path := filepath.Join(w.inbox, entry.Name())
w.processFile(path)
}
}
func (w *Watcher) processFile(path string) {
ext := strings.ToLower(filepath.Ext(path))
if ext != ".pdf" && ext != ".png" && ext != ".jpg" && ext != ".jpeg" && ext != ".md" && ext != ".txt" {
return
}
if err := w.proc.ProcessFile(path); err != nil {
log.Printf("Failed to process %s: %v", path, err)
}
}
func (w *Watcher) Stop() {
close(w.stop)
w.watcher.Close()
}