/* * Copyright (C) 2020-2022, IrineSistiana * * This file is part of mosdns. * * mosdns is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mosdns is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package coremain import ( "fmt" "io" "sync" "go.uber.org/zap" ) // HotReloadManager 热加载管理器 type HotReloadManager struct { mosdns *Mosdns mu sync.RWMutex isReloading bool configPath string } // NewHotReloadManager 创建热加载管理器 func NewHotReloadManager(m *Mosdns, configPath string) *HotReloadManager { return &HotReloadManager{ mosdns: m, configPath: configPath, } } // Reload 执行热加载 // 返回值:成功加载的插件数,错误信息 func (hrm *HotReloadManager) Reload() (int, error) { hrm.mu.Lock() if hrm.isReloading { hrm.mu.Unlock() return 0, fmt.Errorf("reload is already in progress") } hrm.isReloading = true hrm.mu.Unlock() defer func() { hrm.mu.Lock() hrm.isReloading = false hrm.mu.Unlock() }() hrm.mosdns.logger.Info("🔄 开始热加载配置...") // 1. 加载新配置 newCfg, actualPath, err := loadConfig(hrm.configPath) if err != nil { hrm.mosdns.logger.Error("failed to load config", zap.Error(err)) return 0, fmt.Errorf("配置文件加载失败: %w", err) } hrm.mosdns.logger.Info("✅ 配置文件加载成功", zap.String("path", actualPath)) // 2. 验证新配置 validator := NewConfigValidator(newCfg, hrm.mosdns.logger) if err := validator.Validate(); err != nil { hrm.mosdns.logger.Error("config validation failed", zap.Error(err)) return 0, fmt.Errorf("配置验证失败: %w", err) } hrm.mosdns.logger.Info("✅ 配置验证通过") // 3. 备份旧插件 oldPlugins := hrm.mosdns.plugins hrm.mosdns.logger.Info("📦 备份旧插件", zap.Int("count", len(oldPlugins))) // 4. 创建新插件映射 hrm.mosdns.plugins = make(map[string]any) // 5. 加载预设插件 if err := hrm.mosdns.loadPresetPlugins(); err != nil { // 恢复旧插件 hrm.mosdns.plugins = oldPlugins hrm.mosdns.logger.Error("failed to load preset plugins", zap.Error(err)) return 0, fmt.Errorf("预设插件加载失败: %w", err) } // 6. 加载新配置的插件 if err := hrm.mosdns.loadPluginsFromCfg(newCfg, 0); err != nil { // 恢复旧插件 hrm.mosdns.plugins = oldPlugins hrm.mosdns.logger.Error("failed to load plugins from new config", zap.Error(err)) return 0, fmt.Errorf("新插件加载失败: %w", err) } newPluginCount := len(hrm.mosdns.plugins) hrm.mosdns.logger.Info("✅ 新插件加载成功", zap.Int("count", newPluginCount)) // 7. 关闭旧插件(在新插件成功加载后) hrm.closeOldPlugins(oldPlugins) // 8. 更新配置引用 hrm.mosdns.config = newCfg hrm.mosdns.logger.Info("🎉 热加载完成!", zap.Int("old_plugin_count", len(oldPlugins)), zap.Int("new_plugin_count", newPluginCount)) return newPluginCount, nil } // closeOldPlugins 关闭旧插件 func (hrm *HotReloadManager) closeOldPlugins(oldPlugins map[string]any) { hrm.mosdns.logger.Info("🔒 开始关闭旧插件", zap.Int("count", len(oldPlugins))) closedCount := 0 for tag, p := range oldPlugins { if closer, ok := p.(io.Closer); ok { hrm.mosdns.logger.Debug("closing old plugin", zap.String("tag", tag)) if err := closer.Close(); err != nil { hrm.mosdns.logger.Warn("failed to close old plugin", zap.String("tag", tag), zap.Error(err)) } else { closedCount++ } } } hrm.mosdns.logger.Info("✅ 旧插件关闭完成", zap.Int("total", len(oldPlugins)), zap.Int("closed", closedCount)) } // IsReloading 检查是否正在重载 func (hrm *HotReloadManager) IsReloading() bool { hrm.mu.RLock() defer hrm.mu.RUnlock() return hrm.isReloading } // GetConfigPath 获取配置文件路径 func (hrm *HotReloadManager) GetConfigPath() string { return hrm.configPath } // SetConfigPath 设置配置文件路径 func (hrm *HotReloadManager) SetConfigPath(path string) { hrm.mu.Lock() defer hrm.mu.Unlock() hrm.configPath = path }