mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-18 00:21:56 +08:00
添加动态压缩管理器支持,优化配置更新逻辑,确保压缩配置可动态调整。更新配置处理器以使用ConfigManager,简化配置保存和加载流程。
This commit is contained in:
parent
370bd1b74f
commit
83c544bd5b
@ -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
|
||||
// Load 加载配置(向后兼容)
|
||||
func Load(path string) (*Config, error) {
|
||||
if globalConfigManager == nil {
|
||||
var err error
|
||||
globalConfigManager, err = NewConfigManager(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
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)
|
||||
return globalConfigManager.GetConfig(), nil
|
||||
}
|
||||
|
@ -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
31
main.go
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
// 创建服务器
|
||||
|
Loading…
x
Reference in New Issue
Block a user