74 lines
1.7 KiB
Go
74 lines
1.7 KiB
Go
|
|
// 热重载驱动: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() }
|