// 热重载驱动:fsnotify 文件监听 + 防抖(热更新.md §4.5)。 package mods import ( "fmt" "path/filepath" "sync" "time" "github.com/fsnotify/fsnotify" ) // Watcher 脚本文件监听器(开发模式)。 type Watcher struct { w *fsnotify.Watcher mu sync.Mutex reload map[string]func() error // 脚本路径 → 重载函数 timers map[string]*time.Timer // 防抖计时器(500ms) } // NewWatcher 创建监听器。 func NewWatcher() (*Watcher, error) { w, err := fsnotify.NewWatcher() if err != nil { return nil, fmt.Errorf("mods.NewWatcher: %w", err) } return &Watcher{w: w, reload: make(map[string]func() error), timers: make(map[string]*time.Timer)}, nil } // WatchFile 监听一个脚本文件:变化后防抖触发 reload(热更新.md §4.5 防抖 500ms)。 func (w *Watcher) WatchFile(path string, reload func() error) error { if err := w.w.Add(filepath.Dir(path)); err != nil { return fmt.Errorf("mods.WatchFile %s: %w", path, err) } w.mu.Lock() w.reload[path] = reload w.mu.Unlock() return nil } // Run 事件循环(goroutine):文件变化 → 防抖 → 重载。 func (w *Watcher) Run() { for { select { case ev, ok := <-w.w.Events: if !ok { return } if ev.Op&(fsnotify.Write|fsnotify.Create) == 0 { continue } w.mu.Lock() fn, ok := w.reload[ev.Name] if !ok { w.mu.Unlock() continue } if t, exists := w.timers[ev.Name]; exists { t.Stop() } reloadFn := fn w.timers[ev.Name] = time.AfterFunc(500*time.Millisecond, func() { _ = reloadFn() }) w.mu.Unlock() case _, ok := <-w.w.Errors: if !ok { return } } } } // Close 停止监听。 func (w *Watcher) Close() error { return w.w.Close() }