mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-19 08:51:55 +08:00
添加动态压缩管理器支持,优化配置更新逻辑,确保压缩配置可动态调整。更新配置处理器以使用ConfigManager,简化配置保存和加载流程。
This commit is contained in:
parent
370bd1b74f
commit
83c544bd5b
@ -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)
|
|
||||||
}
|
}
|
||||||
|
@ -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
31
main.go
@ -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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建服务器
|
// 创建服务器
|
||||||
|
Loading…
x
Reference in New Issue
Block a user