添加动态压缩管理器支持,优化配置更新逻辑,确保压缩配置可动态调整。更新配置处理器以使用ConfigManager,简化配置保存和加载流程。

This commit is contained in:
wood chen 2025-06-02 07:52:33 +08:00
parent 370bd1b74f
commit 83c544bd5b
3 changed files with 137 additions and 125 deletions

View File

@ -9,17 +9,7 @@ import (
"sync/atomic" "sync/atomic"
) )
// Config 配置结构体
type configImpl struct {
sync.RWMutex
Config
// 配置更新回调函数
onConfigUpdate []func(*Config)
}
var ( var (
instance *configImpl
once sync.Once
configCallbacks []func(*Config) configCallbacks []func(*Config)
callbackMutex sync.RWMutex callbackMutex sync.RWMutex
) )
@ -27,6 +17,7 @@ var (
type ConfigManager struct { type ConfigManager struct {
config atomic.Value config atomic.Value
configPath string configPath string
mu sync.RWMutex
} }
func NewConfigManager(configPath string) (*ConfigManager, error) { func NewConfigManager(configPath string) (*ConfigManager, error) {
@ -35,7 +26,7 @@ func NewConfigManager(configPath string) (*ConfigManager, error) {
} }
// 加载配置 // 加载配置
config, err := Load(configPath) config, err := cm.loadConfigFromFile()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -52,28 +43,33 @@ func NewConfigManager(configPath string) (*ConfigManager, error) {
return cm, nil return cm, nil
} }
// Load 加载配置 // loadConfigFromFile 从文件加载配置
func Load(path string) (*Config, error) { func (cm *ConfigManager) loadConfigFromFile() (*Config, error) {
var err error data, err := os.ReadFile(cm.configPath)
once.Do(func() { if err != nil {
instance = &configImpl{} // 如果文件不存在,创建默认配置
err = instance.reload(path) if os.IsNotExist(err) {
// 如果文件不存在,创建默认配置并重新加载 if createErr := cm.createDefaultConfig(); createErr == nil {
if err != nil && os.IsNotExist(err) { return cm.loadConfigFromFile() // 重新加载
if createErr := createDefaultConfig(path); createErr == nil {
err = instance.reload(path)
} else { } else {
err = createErr return nil, createErr
} }
} }
}) return nil, err
return &instance.Config, err }
var config Config
if err := json.Unmarshal(data, &config); err != nil {
return nil, err
}
return &config, nil
} }
// createDefaultConfig 创建默认配置文件 // createDefaultConfig 创建默认配置文件
func createDefaultConfig(path string) error { func (cm *ConfigManager) createDefaultConfig() error {
// 创建目录(如果不存在) // 创建目录(如果不存在)
dir := path[:strings.LastIndex(path, "/")] dir := cm.configPath[:strings.LastIndex(cm.configPath, "/")]
if err := os.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0755); err != nil {
return err return err
} }
@ -119,7 +115,78 @@ func createDefaultConfig(path string) error {
} }
// 写入文件 // 写入文件
return os.WriteFile(path, data, 0644) 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 注册配置更新回调函数 // RegisterUpdateCallback 注册配置更新回调函数
@ -147,63 +214,17 @@ func TriggerCallbacks(cfg *Config) {
log.Printf("[Config] 触发了 %d 个配置更新回调", len(configCallbacks)) log.Printf("[Config] 触发了 %d 个配置更新回调", len(configCallbacks))
} }
// Update 更新配置并触发回调 // 为了向后兼容保留Load函数但现在它使用ConfigManager
func (c *configImpl) Update(newConfig *Config) { var globalConfigManager *ConfigManager
c.Lock()
defer c.Unlock()
// 确保所有路径配置的扩展名规则都已更新 // Load 加载配置(向后兼容)
for path, pc := range newConfig.MAP { func Load(path string) (*Config, error) {
pc.ProcessExtensionMap() if globalConfigManager == nil {
newConfig.MAP[path] = pc // 更新回原始map var err error
globalConfigManager, err = NewConfigManager(path)
if err != nil {
return nil, err
}
} }
return globalConfigManager.GetConfig(), nil
// 更新配置
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)
} }

View File

@ -11,13 +11,13 @@ import (
// ConfigHandler 配置管理处理器 // ConfigHandler 配置管理处理器
type ConfigHandler struct { type ConfigHandler struct {
config *config.Config configManager *config.ConfigManager
} }
// NewConfigHandler 创建新的配置管理处理器 // NewConfigHandler 创建新的配置管理处理器
func NewConfigHandler(cfg *config.Config) *ConfigHandler { func NewConfigHandler(configManager *config.ConfigManager) *ConfigHandler {
return &ConfigHandler{ return &ConfigHandler{
config: cfg, configManager: configManager,
} }
} }
@ -67,42 +67,12 @@ func (h *ConfigHandler) handleSaveConfig(w http.ResponseWriter, r *http.Request)
return return
} }
// 确保对每个路径配置调用ProcessExtensionMap方法 // 使用ConfigManager更新配置
for _, pathConfig := range newConfig.MAP { if err := h.configManager.UpdateConfig(&newConfig); err != nil {
pathConfig.ProcessExtensionMap() http.Error(w, fmt.Sprintf("更新配置失败: %v", err), http.StatusInternalServerError)
}
// 将新配置格式化为JSON
configData, err := json.MarshalIndent(newConfig, "", " ")
if err != nil {
http.Error(w, fmt.Sprintf("格式化配置失败: %v", err), http.StatusInternalServerError)
return return
} }
// 保存到临时文件
tempFile := "data/config.json.tmp"
if err := os.WriteFile(tempFile, configData, 0644); err != nil {
http.Error(w, fmt.Sprintf("保存配置失败: %v", err), http.StatusInternalServerError)
return
}
// 重命名临时文件为正式文件
if err := os.Rename(tempFile, "data/config.json"); err != nil {
http.Error(w, fmt.Sprintf("更新配置文件失败: %v", err), http.StatusInternalServerError)
return
}
// 更新运行时配置
*h.config = newConfig
// 确保在触发回调之前所有路径配置的processedExtMap都已更新
for _, pathConfig := range h.config.MAP {
pathConfig.ProcessExtensionMap()
}
// 触发配置更新回调
config.TriggerCallbacks(h.config)
// 添加日志 // 添加日志
fmt.Printf("[Config] 配置已更新: %d 个路径映射\n", len(newConfig.MAP)) fmt.Printf("[Config] 配置已更新: %d 个路径映射\n", len(newConfig.MAP))

31
main.go
View File

@ -14,6 +14,7 @@ import (
"proxy-go/internal/metrics" "proxy-go/internal/metrics"
"proxy-go/internal/middleware" "proxy-go/internal/middleware"
"strings" "strings"
"sync/atomic"
"syscall" "syscall"
) )
@ -46,16 +47,32 @@ func main() {
// 初始化统计服务 // 初始化统计服务
metrics.Init(cfg) metrics.Init(cfg)
// 创建压缩管理器 // 创建压缩管理器使用atomic.Value来支持动态更新
var compManagerAtomic atomic.Value
compManager := compression.NewManager(compression.Config{ compManager := compression.NewManager(compression.Config{
Gzip: compression.CompressorConfig(cfg.Compression.Gzip), Gzip: compression.CompressorConfig(cfg.Compression.Gzip),
Brotli: compression.CompressorConfig(cfg.Compression.Brotli), Brotli: compression.CompressorConfig(cfg.Compression.Brotli),
}) })
compManagerAtomic.Store(compManager)
// 创建代理处理器 // 创建代理处理器
mirrorHandler := handler.NewMirrorProxyHandler() mirrorHandler := handler.NewMirrorProxyHandler()
proxyHandler := handler.NewProxyHandler(cfg) proxyHandler := handler.NewProxyHandler(cfg)
// 创建配置处理器
configHandler := handler.NewConfigHandler(configManager)
// 注册压缩配置更新回调
config.RegisterUpdateCallback(func(newCfg *config.Config) {
// 更新压缩管理器
newCompManager := compression.NewManager(compression.Config{
Gzip: compression.CompressorConfig(newCfg.Compression.Gzip),
Brotli: compression.CompressorConfig(newCfg.Compression.Brotli),
})
compManagerAtomic.Store(newCompManager)
log.Printf("[Config] 压缩管理器配置已更新")
})
// 定义API路由 // 定义API路由
apiRoutes := []Route{ apiRoutes := []Route{
{http.MethodGet, "/admin/api/auth", proxyHandler.LoginHandler, false}, {http.MethodGet, "/admin/api/auth", proxyHandler.LoginHandler, false},
@ -66,8 +83,8 @@ func main() {
}, true}, }, true},
{http.MethodPost, "/admin/api/logout", proxyHandler.LogoutHandler, false}, {http.MethodPost, "/admin/api/logout", proxyHandler.LogoutHandler, false},
{http.MethodGet, "/admin/api/metrics", proxyHandler.MetricsHandler, true}, {http.MethodGet, "/admin/api/metrics", proxyHandler.MetricsHandler, true},
{http.MethodGet, "/admin/api/config/get", handler.NewConfigHandler(cfg).ServeHTTP, true}, {http.MethodGet, "/admin/api/config/get", configHandler.ServeHTTP, true},
{http.MethodPost, "/admin/api/config/save", handler.NewConfigHandler(cfg).ServeHTTP, true}, {http.MethodPost, "/admin/api/config/save", configHandler.ServeHTTP, true},
{http.MethodGet, "/admin/api/cache/stats", handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache).GetCacheStats, true}, {http.MethodGet, "/admin/api/cache/stats", handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache).GetCacheStats, true},
{http.MethodPost, "/admin/api/cache/enable", handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache).SetCacheEnabled, true}, {http.MethodPost, "/admin/api/cache/enable", handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache).SetCacheEnabled, true},
{http.MethodPost, "/admin/api/cache/clear", handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache).ClearCache, true}, {http.MethodPost, "/admin/api/cache/clear", handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache).ClearCache, true},
@ -148,10 +165,14 @@ func main() {
http.NotFound(w, r) http.NotFound(w, r)
}) })
// 添加压缩中间件 // 添加压缩中间件(使用动态压缩管理器)
var handler http.Handler = mainHandler var handler http.Handler = mainHandler
if cfg.Compression.Gzip.Enabled || cfg.Compression.Brotli.Enabled { if cfg.Compression.Gzip.Enabled || cfg.Compression.Brotli.Enabled {
handler = middleware.CompressionMiddleware(compManager)(handler) // 创建动态压缩中间件包装器
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
currentCompManager := compManagerAtomic.Load().(compression.Manager)
middleware.CompressionMiddleware(currentCompManager)(mainHandler).ServeHTTP(w, r)
})
} }
// 创建服务器 // 创建服务器