package config import ( "encoding/json" "log" "os" "strings" "sync" "sync/atomic" ) var ( configCallbacks []func(*Config) callbackMutex sync.RWMutex ) type ConfigManager struct { config atomic.Value configPath string mu sync.RWMutex } func NewConfigManager(configPath string) (*ConfigManager, error) { cm := &ConfigManager{ configPath: configPath, } // 加载配置 config, err := cm.loadConfigFromFile() if err != nil { return nil, err } // 确保所有路径配置的扩展名规则都已更新 for path, pc := range config.MAP { pc.ProcessExtensionMap() config.MAP[path] = pc // 更新回原始map } cm.config.Store(config) log.Printf("[ConfigManager] 配置已加载: %d 个路径映射", len(config.MAP)) return cm, nil } // loadConfigFromFile 从文件加载配置 func (cm *ConfigManager) loadConfigFromFile() (*Config, error) { data, err := os.ReadFile(cm.configPath) if err != nil { // 如果文件不存在,创建默认配置 if os.IsNotExist(err) { if createErr := cm.createDefaultConfig(); createErr == nil { return cm.loadConfigFromFile() // 重新加载 } else { return nil, createErr } } return nil, err } var config Config if err := json.Unmarshal(data, &config); err != nil { return nil, err } return &config, nil } // createDefaultConfig 创建默认配置文件 func (cm *ConfigManager) createDefaultConfig() error { // 创建目录(如果不存在) dir := cm.configPath[:strings.LastIndex(cm.configPath, "/")] if err := os.MkdirAll(dir, 0755); err != nil { return err } // 创建默认配置 defaultConfig := Config{ MAP: map[string]PathConfig{ "/": { DefaultTarget: "http://localhost:8080", // 添加新式扩展名规则映射示例 ExtensionMap: []ExtRuleConfig{ { Extensions: "jpg,png,webp", Target: "https://img1.example.com", SizeThreshold: 500 * 1024, // 500KB MaxSize: 2 * 1024 * 1024, // 2MB }, { Extensions: "jpg,png,webp", Target: "https://img2.example.com", SizeThreshold: 2 * 1024 * 1024, // 2MB MaxSize: 5 * 1024 * 1024, // 5MB }, }, }, }, Compression: CompressionConfig{ Gzip: CompressorConfig{ Enabled: true, Level: 6, }, Brotli: CompressorConfig{ Enabled: true, Level: 6, }, }, } // 序列化为JSON data, err := json.MarshalIndent(defaultConfig, "", " ") if err != nil { return err } // 写入文件 return os.WriteFile(cm.configPath, data, 0644) } // GetConfig 获取当前配置 func (cm *ConfigManager) GetConfig() *Config { return cm.config.Load().(*Config) } // UpdateConfig 更新配置 func (cm *ConfigManager) UpdateConfig(newConfig *Config) error { cm.mu.Lock() defer cm.mu.Unlock() // 确保所有路径配置的扩展名规则都已更新 for path, pc := range newConfig.MAP { pc.ProcessExtensionMap() newConfig.MAP[path] = pc // 更新回原始map } // 保存到文件 if err := cm.saveConfigToFile(newConfig); err != nil { return err } // 更新内存中的配置 cm.config.Store(newConfig) // 触发回调 TriggerCallbacks(newConfig) log.Printf("[ConfigManager] 配置已更新: %d 个路径映射", len(newConfig.MAP)) return nil } // saveConfigToFile 保存配置到文件 func (cm *ConfigManager) saveConfigToFile(config *Config) error { // 将新配置格式化为JSON configData, err := json.MarshalIndent(config, "", " ") if err != nil { return err } // 保存到临时文件 tempFile := cm.configPath + ".tmp" if err := os.WriteFile(tempFile, configData, 0644); err != nil { return err } // 重命名临时文件为正式文件 return os.Rename(tempFile, cm.configPath) } // ReloadConfig 重新加载配置文件 func (cm *ConfigManager) ReloadConfig() error { config, err := cm.loadConfigFromFile() if err != nil { return err } // 确保所有路径配置的扩展名规则都已更新 for path, pc := range config.MAP { pc.ProcessExtensionMap() config.MAP[path] = pc // 更新回原始map } cm.config.Store(config) // 触发回调 TriggerCallbacks(config) log.Printf("[ConfigManager] 配置已重新加载: %d 个路径映射", len(config.MAP)) return nil } // RegisterUpdateCallback 注册配置更新回调函数 func RegisterUpdateCallback(callback func(*Config)) { callbackMutex.Lock() defer callbackMutex.Unlock() configCallbacks = append(configCallbacks, callback) } // TriggerCallbacks 触发所有回调 func TriggerCallbacks(cfg *Config) { // 确保所有路径配置的扩展名规则都已更新 for path, pc := range cfg.MAP { pc.ProcessExtensionMap() cfg.MAP[path] = pc // 更新回原始map } callbackMutex.RLock() defer callbackMutex.RUnlock() for _, callback := range configCallbacks { callback(cfg) } // 添加日志 log.Printf("[Config] 触发了 %d 个配置更新回调", len(configCallbacks)) } // 为了向后兼容,保留Load函数,但现在它使用ConfigManager var globalConfigManager *ConfigManager // Load 加载配置(向后兼容) func Load(path string) (*Config, error) { if globalConfigManager == nil { var err error globalConfigManager, err = NewConfigManager(path) if err != nil { return nil, err } } return globalConfigManager.GetConfig(), nil }