185 lines
4.0 KiB
Go
185 lines
4.0 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"log"
|
|
|
|
"encoding/json"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
// Config 系统配置结构体
|
|
type Config struct {
|
|
Server ServerConfig `yaml:"server" json:"server"`
|
|
Storage StorageConfig `yaml:"storage" json:"storage"`
|
|
}
|
|
|
|
// ServerConfig 服务器配置
|
|
type ServerConfig struct {
|
|
Host string `yaml:"host" json:"host"`
|
|
Port int `yaml:"port" json:"port"`
|
|
}
|
|
|
|
// StorageConfig 存储配置
|
|
type StorageConfig struct {
|
|
Engine string `yaml:"engine" json:"engine"`
|
|
DataPath string `yaml:"dataPath" json:"dataPath"`
|
|
}
|
|
|
|
var (
|
|
configInstance *Config
|
|
once sync.Once
|
|
watcher *fsnotify.Watcher // 配置文件监视器
|
|
)
|
|
|
|
// NewDefaultConfig 创建默认配置
|
|
func NewDefaultConfig() *Config {
|
|
return &Config{
|
|
Server: ServerConfig{
|
|
Host: "0.0.0.0",
|
|
Port: 27017,
|
|
},
|
|
Storage: StorageConfig{
|
|
Engine: "memory",
|
|
DataPath: "/var/lib/goaidb",
|
|
},
|
|
}
|
|
}
|
|
|
|
// ParseConfig 解析配置文件
|
|
// 支持JSON和YAML格式
|
|
// 返回解析后的配置对象和错误信息
|
|
func ParseConfig(filePath string) (*Config, error) {
|
|
// 检查文件是否存在
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
return nil, fmt.Errorf("配置文件不存在: %s", filePath)
|
|
}
|
|
|
|
// 读取文件内容
|
|
data, err := ioutil.ReadFile(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("读取配置文件失败: %v", err)
|
|
}
|
|
|
|
// 根据文件扩展名选择解析方式
|
|
var cfg Config
|
|
switch filepath.Ext(filePath) {
|
|
case ".json":
|
|
if err := json.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("JSON解析失败: %v", err)
|
|
}
|
|
case ".yaml", ".yml":
|
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("YAML解析失败: %v", err)
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("不支持的配置文件格式")
|
|
}
|
|
|
|
return &cfg, nil
|
|
}
|
|
|
|
// ValidateConfig 验证配置有效性
|
|
// 返回验证结果和第一个发现的错误(如果有)
|
|
func (c *Config) Validate() (bool, error) {
|
|
// 验证服务器配置
|
|
if c.Server.Port < 1024 || c.Server.Port > 65535 {
|
|
return false, fmt.Errorf("端口必须在1024-65535之间: %d", c.Server.Port)
|
|
}
|
|
|
|
// 验证存储配置
|
|
if c.Storage.Engine != "memory" && c.Storage.Engine != "rocksdb" {
|
|
return false, fmt.Errorf("不支持的存储引擎: %s", c.Storage.Engine)
|
|
}
|
|
|
|
// 验证数据路径是否存在
|
|
if _, err := os.Stat(c.Storage.DataPath); os.IsNotExist(err) {
|
|
return false, fmt.Errorf("数据目录不存在: %s", c.Storage.DataPath)
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// WatchConfig 监听配置文件变化并自动重载
|
|
func WatchConfig(filePath string) error {
|
|
// 创建文件监视器
|
|
w, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return fmt.Errorf("创建文件监视器失败: %v", err)
|
|
}
|
|
|
|
// 添加文件监视
|
|
dir := filepath.Dir(filePath)
|
|
fileName := filepath.Base(filePath)
|
|
|
|
err = w.Add(dir)
|
|
if err != nil {
|
|
return fmt.Errorf("添加文件监视失败: %v", err)
|
|
}
|
|
|
|
// 启动监听协程
|
|
go func() {
|
|
for {
|
|
select {
|
|
case event, ok := <-w.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
// 当配置文件被修改或创建时重新加载
|
|
if (event.Op&fsnotify.Write == fsnotify.Write ||
|
|
event.Op&fsnotify.Create == fsnotify.Create) &&
|
|
filepath.Base(event.Name) == fileName {
|
|
|
|
// 重新加载配置
|
|
newCfg, err := ParseConfig(filePath)
|
|
if err != nil {
|
|
log.Printf("配置重载失败: %v", err)
|
|
continue
|
|
}
|
|
|
|
// 更新全局配置
|
|
SetGlobalConfig(newCfg)
|
|
log.Printf("配置已更新")
|
|
}
|
|
|
|
case err, ok := <-w.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
log.Printf("文件监视错误: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
watcher = w
|
|
return nil
|
|
}
|
|
|
|
// CloseWatcher 关闭配置文件监视器
|
|
func CloseWatcher() {
|
|
if watcher != nil {
|
|
watcher.Close()
|
|
}
|
|
}
|
|
|
|
// GetConfig 获取全局配置实例
|
|
func GetConfig() *Config {
|
|
once.Do(func() {
|
|
configInstance = NewDefaultConfig()
|
|
})
|
|
return configInstance
|
|
}
|
|
|
|
// SetGlobalConfig 设置全局配置实例
|
|
func SetGlobalConfig(cfg *Config) {
|
|
once.Do(func() {
|
|
configInstance = cfg
|
|
})
|
|
}
|