package config import ( "log" "path/filepath" "time" "github.com/fsnotify/fsnotify" ) // ConfigWatcher 配置文件监控器 type ConfigWatcher struct { watcher *fsnotify.Watcher configPath string stopCh chan struct{} } // NewConfigWatcher 创建配置文件监控器 func NewConfigWatcher(configPath string) (*ConfigWatcher, error) { watcher, err := fsnotify.NewWatcher() if err != nil { return nil, err } // 转换为绝对路径 absPath, err := filepath.Abs(configPath) if err != nil { return nil, err } return &ConfigWatcher{ watcher: watcher, configPath: absPath, stopCh: make(chan struct{}), }, nil } // Start 启动配置文件监控 func (w *ConfigWatcher) Start() error { // 监控配置文件所在目录 configDir := filepath.Dir(w.configPath) if err := w.watcher.Add(configDir); err != nil { return err } go w.watchLoop() return nil } // Stop 停止配置文件监控 func (w *ConfigWatcher) Stop() { close(w.stopCh) if w.watcher != nil { w.watcher.Close() } log.Println("配置文件监控已停止") } // watchLoop 监控循环 func (w *ConfigWatcher) watchLoop() { // 防抖动:在短时间内多次文件变化只处理一次 var debounceTimer *time.Timer const debounceDelay = 500 * time.Millisecond for { select { case event, ok := <-w.watcher.Events: if !ok { return } // 只处理配置文件的写入或创建事件 if filepath.Base(event.Name) == filepath.Base(w.configPath) { if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { // log.Printf("检测到配置文件变化: %s", event.Name) // 重置防抖动定时器 if debounceTimer != nil { debounceTimer.Stop() } debounceTimer = time.AfterFunc(debounceDelay, func() { if err := ReloadConfig(); err != nil { log.Printf("重新加载配置失败: %v", err) } else { log.Println("✅ 配置热更新成功!") } }) } } case err, ok := <-w.watcher.Errors: if !ok { return } log.Printf("配置文件监控错误: %v", err) case <-w.stopCh: if debounceTimer != nil { debounceTimer.Stop() } return } } } // StartConfigWatcher 启动配置文件监控(全局函数) func StartConfigWatcher(configPath string) (*ConfigWatcher, error) { watcher, err := NewConfigWatcher(configPath) if err != nil { return nil, err } if err := watcher.Start(); err != nil { return nil, err } return watcher, nil }