添加动态压缩管理器支持,优化配置更新逻辑,确保压缩配置可动态调整。更新配置处理器以使用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"
)
// Config 配置结构体
type configImpl struct {
sync.RWMutex
Config
// 配置更新回调函数
onConfigUpdate []func(*Config)
}
var (
instance *configImpl
once sync.Once
configCallbacks []func(*Config)
callbackMutex sync.RWMutex
)
@ -27,6 +17,7 @@ var (
type ConfigManager struct {
config atomic.Value
configPath string
mu sync.RWMutex
}
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 {
return nil, err
}
@ -52,28 +43,33 @@ func NewConfigManager(configPath string) (*ConfigManager, error) {
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)
// 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 {
err = createErr
return nil, createErr
}
}
})
return &instance.Config, err
return nil, err
}
var config Config
if err := json.Unmarshal(data, &config); err != nil {
return nil, err
}
return &config, nil
}
// 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 {
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 注册配置更新回调函数
@ -147,63 +214,17 @@ func TriggerCallbacks(cfg *Config) {
log.Printf("[Config] 触发了 %d 个配置更新回调", len(configCallbacks))
}
// Update 更新配置并触发回调
func (c *configImpl) Update(newConfig *Config) {
c.Lock()
defer c.Unlock()
// 为了向后兼容保留Load函数但现在它使用ConfigManager
var globalConfigManager *ConfigManager
// 确保所有路径配置的扩展名规则都已更新
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)
// Load 加载配置(向后兼容)
func Load(path string) (*Config, error) {
if globalConfigManager == nil {
var err error
globalConfigManager, err = NewConfigManager(path)
if err != nil {
return err
return nil, 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)
return globalConfigManager.GetConfig(), nil
}

View File

@ -11,13 +11,13 @@ import (
// ConfigHandler 配置管理处理器
type ConfigHandler struct {
config *config.Config
configManager *config.ConfigManager
}
// NewConfigHandler 创建新的配置管理处理器
func NewConfigHandler(cfg *config.Config) *ConfigHandler {
func NewConfigHandler(configManager *config.ConfigManager) *ConfigHandler {
return &ConfigHandler{
config: cfg,
configManager: configManager,
}
}
@ -67,42 +67,12 @@ func (h *ConfigHandler) handleSaveConfig(w http.ResponseWriter, r *http.Request)
return
}
// 确保对每个路径配置调用ProcessExtensionMap方法
for _, pathConfig := range newConfig.MAP {
pathConfig.ProcessExtensionMap()
}
// 将新配置格式化为JSON
configData, err := json.MarshalIndent(newConfig, "", " ")
if err != nil {
http.Error(w, fmt.Sprintf("格式化配置失败: %v", err), http.StatusInternalServerError)
// 使用ConfigManager更新配置
if err := h.configManager.UpdateConfig(&newConfig); err != nil {
http.Error(w, fmt.Sprintf("更新配置失败: %v", err), http.StatusInternalServerError)
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))

31
main.go
View File

@ -14,6 +14,7 @@ import (
"proxy-go/internal/metrics"
"proxy-go/internal/middleware"
"strings"
"sync/atomic"
"syscall"
)
@ -46,16 +47,32 @@ func main() {
// 初始化统计服务
metrics.Init(cfg)
// 创建压缩管理器
// 创建压缩管理器使用atomic.Value来支持动态更新
var compManagerAtomic atomic.Value
compManager := compression.NewManager(compression.Config{
Gzip: compression.CompressorConfig(cfg.Compression.Gzip),
Brotli: compression.CompressorConfig(cfg.Compression.Brotli),
})
compManagerAtomic.Store(compManager)
// 创建代理处理器
mirrorHandler := handler.NewMirrorProxyHandler()
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路由
apiRoutes := []Route{
{http.MethodGet, "/admin/api/auth", proxyHandler.LoginHandler, false},
@ -66,8 +83,8 @@ func main() {
}, true},
{http.MethodPost, "/admin/api/logout", proxyHandler.LogoutHandler, false},
{http.MethodGet, "/admin/api/metrics", proxyHandler.MetricsHandler, true},
{http.MethodGet, "/admin/api/config/get", handler.NewConfigHandler(cfg).ServeHTTP, true},
{http.MethodPost, "/admin/api/config/save", handler.NewConfigHandler(cfg).ServeHTTP, true},
{http.MethodGet, "/admin/api/config/get", configHandler.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.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},
@ -148,10 +165,14 @@ func main() {
http.NotFound(w, r)
})
// 添加压缩中间件
// 添加压缩中间件(使用动态压缩管理器)
var handler http.Handler = mainHandler
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)
})
}
// 创建服务器