wood chen 33d6a51416 refactor(web): Migrate to modern web frontend and simplify admin routes
- 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
2025-02-15 11:44:09 +08:00

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)
}