Premier commit déjà bien avancé

This commit is contained in:
2025-11-10 18:33:24 +01:00
commit db4f0508cb
652 changed files with 440521 additions and 0 deletions

126
internal/watcher/watcher.go Normal file
View File

@ -0,0 +1,126 @@
package watcher
import (
"context"
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/fsnotify/fsnotify"
"github.com/mathieu/project-notes/internal/indexer"
)
// Watcher observe les modifications dans le repertoire des notes et relance l indexation au besoin.
type Watcher struct {
fs *fsnotify.Watcher
idx *indexer.Indexer
dir string
logger *log.Logger
wg sync.WaitGroup
}
// Start initialise le watcher et commence la surveillance dans une goroutine.
func Start(ctx context.Context, dir string, idx *indexer.Indexer, logger *log.Logger) (*Watcher, error) {
fsWatcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
w := &Watcher{
fs: fsWatcher,
idx: idx,
dir: dir,
logger: logger,
}
if err := w.addDirRecursive(dir); err != nil {
fsWatcher.Close()
return nil, err
}
w.wg.Add(1)
go w.run(ctx)
return w, nil
}
// Close arrete le watcher et attend la fin des goroutines.
func (w *Watcher) Close() error {
err := w.fs.Close()
w.wg.Wait()
return err
}
func (w *Watcher) run(ctx context.Context) {
defer w.wg.Done()
debounce := time.NewTimer(0)
if !debounce.Stop() {
<-debounce.C
}
for {
select {
case <-ctx.Done():
return
case event, ok := <-w.fs.Events:
if !ok {
return
}
if event.Op&fsnotify.Create != 0 {
if info, err := os.Stat(event.Name); err == nil && info.IsDir() {
if err := w.addDirRecursive(event.Name); err != nil {
w.logger.Printf("watcher: ajout repertoire %s impossible: %v", event.Name, err)
}
}
}
if w.shouldReindex(event.Name, event.Op) {
if !debounce.Stop() {
select {
case <-debounce.C:
default:
}
}
debounce.Reset(200 * time.Millisecond)
}
case err, ok := <-w.fs.Errors:
if !ok {
return
}
w.logger.Printf("watcher: erreur: %v", err)
case <-debounce.C:
w.logger.Printf("watcher: reindexation suite a modification")
if err := w.idx.Load(w.dir); err != nil {
w.logger.Printf("watcher: echec reindexation: %v", err)
}
}
}
}
func (w *Watcher) shouldReindex(path string, op fsnotify.Op) bool {
ext := strings.ToLower(filepath.Ext(path))
if ext != ".md" && op&fsnotify.Remove == 0 && op&fsnotify.Rename == 0 {
return false
}
return true
}
func (w *Watcher) addDirRecursive(root string) error {
return filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error {
if err != nil {
return err
}
if entry.IsDir() {
if err := w.fs.Add(path); err != nil {
return err
}
}
return nil
})
}