210 lines
4.5 KiB
Go

package config
import (
"encoding/json"
"log"
"os"
"strings"
"sync"
"sync/atomic"
)
// Config 配置结构体
type configImpl struct {
sync.RWMutex
Config
// 配置更新回调函数
onConfigUpdate []func(*Config)
}
var (
instance *configImpl
once sync.Once
configCallbacks []func(*Config)
callbackMutex sync.RWMutex
)
type ConfigManager struct {
config atomic.Value
configPath string
}
func NewConfigManager(configPath string) (*ConfigManager, error) {
cm := &ConfigManager{
configPath: configPath,
}
// 加载配置
config, err := Load(configPath)
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
}
// Load 加载配置
func Load(path string) (*Config, error) {
var err error
once.Do(func() {
instance = &configImpl{}
err = instance.reload(path)
// 如果文件不存在,创建默认配置并重新加载
if err != nil && os.IsNotExist(err) {
if createErr := createDefaultConfig(path); createErr == nil {
err = instance.reload(path)
} else {
err = createErr
}
}
})
return &instance.Config, err
}
// createDefaultConfig 创建默认配置文件
func createDefaultConfig(path string) error {
// 创建目录(如果不存在)
dir := path[:strings.LastIndex(path, "/")]
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(path, data, 0644)
}
// 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))
}
// Update 更新配置并触发回调
func (c *configImpl) Update(newConfig *Config) {
c.Lock()
defer c.Unlock()
// 确保所有路径配置的扩展名规则都已更新
for path, pc := range newConfig.MAP {
pc.ProcessExtensionMap()
newConfig.MAP[path] = pc // 更新回原始map
}
// 更新配置
c.MAP = newConfig.MAP
c.Compression = newConfig.Compression
// 触发回调
for _, callback := range c.onConfigUpdate {
callback(newConfig)
}
// 添加日志
log.Printf("[Config] 配置已更新: %d 个路径映射", len(newConfig.MAP))
}
// reload 重新加载配置文件
func (c *configImpl) reload(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
var newConfig Config
if err := json.Unmarshal(data, &newConfig); err != nil {
return err
}
c.Update(&newConfig)
return nil
}
func (cm *ConfigManager) loadConfig() error {
config, err := Load(cm.configPath)
if err != nil {
return 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 nil
}
func (cm *ConfigManager) GetConfig() *Config {
return cm.config.Load().(*Config)
}