Files
chenxin 6981148727 🔧 chore: 初始化番茄小说 API 项目结构
新增项目基础框架,包含核心 API 实现、算法模块、HTTP 处理器等完整功能模块
2026-08-28 15:22:22 +08:00

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
}