231 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}