mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-18 00:21:56 +08:00
- Remove legacy static files, templates, and JavaScript - Update main.go to serve SPA-style web application - Modify admin route handling to support client-side routing - Simplify configuration and metrics API endpoints - Remove server-side template rendering in favor of static file serving - Update Dockerfile and GitHub Actions to build web frontend
116 lines
2.1 KiB
Go
116 lines
2.1 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// 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(path string) *ConfigManager {
|
|
cm := &ConfigManager{configPath: path}
|
|
cm.loadConfig()
|
|
go cm.watchConfig()
|
|
return cm
|
|
}
|
|
|
|
func (cm *ConfigManager) watchConfig() {
|
|
ticker := time.NewTicker(30 * time.Second)
|
|
for range ticker.C {
|
|
cm.loadConfig()
|
|
}
|
|
}
|
|
|
|
// Load 加载配置
|
|
func Load(path string) (*Config, error) {
|
|
var err error
|
|
once.Do(func() {
|
|
instance = &configImpl{}
|
|
err = instance.reload(path)
|
|
})
|
|
return &instance.Config, err
|
|
}
|
|
|
|
// RegisterUpdateCallback 注册配置更新回调函数
|
|
func RegisterUpdateCallback(callback func(*Config)) {
|
|
callbackMutex.Lock()
|
|
defer callbackMutex.Unlock()
|
|
configCallbacks = append(configCallbacks, callback)
|
|
}
|
|
|
|
// TriggerCallbacks 触发所有回调
|
|
func TriggerCallbacks(cfg *Config) {
|
|
callbackMutex.RLock()
|
|
defer callbackMutex.RUnlock()
|
|
for _, callback := range configCallbacks {
|
|
callback(cfg)
|
|
}
|
|
}
|
|
|
|
// Update 更新配置并触发回调
|
|
func (c *configImpl) Update(newConfig *Config) {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
|
|
// 更新配置
|
|
c.MAP = newConfig.MAP
|
|
c.Compression = newConfig.Compression
|
|
c.FixedPaths = newConfig.FixedPaths
|
|
c.Metrics = newConfig.Metrics
|
|
|
|
// 触发回调
|
|
for _, callback := range c.onConfigUpdate {
|
|
callback(newConfig)
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
cm.config.Store(config)
|
|
return nil
|
|
}
|
|
|
|
func (cm *ConfigManager) GetConfig() *Config {
|
|
return cm.config.Load().(*Config)
|
|
}
|