Files
cellbot/internal/config/config.go

182 lines
4.7 KiB
Go
Raw Normal View History

package config
import (
"fmt"
"sync"
"github.com/BurntSushi/toml"
"github.com/fsnotify/fsnotify"
"go.uber.org/zap"
)
// Config 应用配置结构
type Config struct {
Server ServerConfig `toml:"server"`
Log LogConfig `toml:"log"`
Protocol ProtocolConfig `toml:"protocol"`
Bots []BotConfig `toml:"bots"`
}
// ServerConfig 服务器配置
type ServerConfig struct {
Host string `toml:"host"`
Port int `toml:"port"`
}
// LogConfig 日志配置
type LogConfig struct {
Level string `toml:"level"`
Output string `toml:"output"`
MaxSize int `toml:"max_size"`
MaxBackups int `toml:"max_backups"`
MaxAge int `toml:"max_age"`
}
// ProtocolConfig 协议配置
type ProtocolConfig struct {
Name string `toml:"name"`
Version string `toml:"version"`
Options map[string]string `toml:"options"`
}
// BotConfig Bot 配置
type BotConfig struct {
ID string `toml:"id"`
Protocol string `toml:"protocol"`
Enabled bool `toml:"enabled"`
Milky MilkyConfig `toml:"milky"`
OneBot11 OneBot11Config `toml:"onebot11"`
}
// MilkyConfig Milky 协议配置
type MilkyConfig struct {
ProtocolURL string `toml:"protocol_url"`
AccessToken string `toml:"access_token"`
EventMode string `toml:"event_mode"`
WebhookListenAddr string `toml:"webhook_listen_addr"`
Timeout int `toml:"timeout"`
RetryCount int `toml:"retry_count"`
}
// OneBot11Config OneBot11 协议配置
type OneBot11Config struct {
ConnectionType string `toml:"connection_type"` // ws, ws-reverse, http, http-post
Host string `toml:"host"`
Port int `toml:"port"`
AccessToken string `toml:"access_token"`
WSUrl string `toml:"ws_url"` // 正向WS地址
WSReverseUrl string `toml:"ws_reverse_url"` // 反向WS监听地址
HTTPUrl string `toml:"http_url"` // 正向HTTP地址
HTTPPostUrl string `toml:"http_post_url"` // HTTP POST上报地址
Secret string `toml:"secret"` // 签名密钥
Timeout int `toml:"timeout"` // 超时时间(秒)
Heartbeat int `toml:"heartbeat"` // 心跳间隔(秒)
ReconnectInterval int `toml:"reconnect_interval"` // 重连间隔(秒)
SelfID string `toml:"self_id"` // 机器人QQ号
Nickname string `toml:"nickname"` // 机器人昵称
}
// ConfigManager 配置管理器
type ConfigManager struct {
configPath string
config *Config
logger *zap.Logger
mu sync.RWMutex
callbacks []func(*Config)
}
// NewConfigManager 创建配置管理器
func NewConfigManager(configPath string, logger *zap.Logger) *ConfigManager {
return &ConfigManager{
configPath: configPath,
logger: logger,
callbacks: make([]func(*Config), 0),
}
}
// Load 加载配置文件
func (cm *ConfigManager) Load() error {
cm.mu.Lock()
defer cm.mu.Unlock()
var cfg Config
if _, err := toml.DecodeFile(cm.configPath, &cfg); err != nil {
return fmt.Errorf("failed to decode config: %w", err)
}
cm.config = &cfg
cm.logger.Info("Config loaded successfully",
zap.String("path", cm.configPath),
zap.String("server", fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)),
)
// 触发回调
for _, cb := range cm.callbacks {
cb(cm.config)
}
return nil
}
// Get 获取当前配置
func (cm *ConfigManager) Get() *Config {
cm.mu.RLock()
defer cm.mu.RUnlock()
return cm.config
}
// Reload 重新加载配置
func (cm *ConfigManager) Reload() error {
return cm.Load()
}
// RegisterCallback 注册配置变更回调
func (cm *ConfigManager) RegisterCallback(callback func(*Config)) {
cm.mu.Lock()
defer cm.mu.Unlock()
cm.callbacks = append(cm.callbacks, callback)
}
// Watch 监听配置文件变化
func (cm *ConfigManager) Watch() error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return fmt.Errorf("failed to create watcher: %w", err)
}
if err := watcher.Add(cm.configPath); err != nil {
return fmt.Errorf("failed to watch config file: %w", err)
}
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
cm.logger.Info("Config file changed, reloading...",
zap.String("file", event.Name))
if err := cm.Reload(); err != nil {
cm.logger.Error("Failed to reload config",
zap.Error(err))
}
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
cm.logger.Error("Watcher error", zap.Error(err))
}
}
}()
return nil
}
// Close 关闭配置管理器
func (cm *ConfigManager) Close() error {
return nil
}