121 lines
2.5 KiB
Go
121 lines
2.5 KiB
Go
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
|
|
}
|
|
|