128 lines
2.8 KiB
Go
128 lines
2.8 KiB
Go
package config
|
|
|
|
import (
|
|
"log/slog"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
type Config struct {
|
|
Database DatabaseConfig
|
|
Server ServerConfig
|
|
App AppConfig
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Driver string
|
|
DSN string
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Port int
|
|
Mode string
|
|
}
|
|
|
|
type AppConfig struct {
|
|
Name string
|
|
Description string
|
|
Author string
|
|
Theme string
|
|
}
|
|
|
|
var globalConfig *Config
|
|
|
|
// Load 加载配置(支持环境变量和配置文件)
|
|
func Load() *Config {
|
|
// 1. 初始化 viper
|
|
viper.SetConfigName("config")
|
|
viper.SetConfigType("yaml")
|
|
viper.AddConfigPath("./config")
|
|
viper.AddConfigPath(".")
|
|
|
|
// 2. 设置默认值
|
|
setDefaults()
|
|
|
|
// 3. 自动读取环境变量
|
|
viper.AutomaticEnv()
|
|
viper.SetEnvPrefix("GOBLOG")
|
|
|
|
// 4. 读取配置文件(如果存在)
|
|
if err := viper.ReadInConfig(); err != nil {
|
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
|
slog.Warn("读取配置文件失败,使用默认配置", "error", err)
|
|
}
|
|
} else {
|
|
slog.Info("配置文件加载成功", "file", viper.ConfigFileUsed())
|
|
}
|
|
|
|
// 5. 解析配置
|
|
cfg := parseConfig()
|
|
globalConfig = cfg
|
|
|
|
// 6. 监听配置变更
|
|
watchConfig()
|
|
|
|
return cfg
|
|
}
|
|
|
|
// setDefaults 设置默认配置值
|
|
func setDefaults() {
|
|
viper.SetDefault("server.port", 8080)
|
|
viper.SetDefault("server.mode", "debug")
|
|
viper.SetDefault("database.driver", "sqlite")
|
|
viper.SetDefault("database.dsn", "goblog.db")
|
|
viper.SetDefault("app.name", "GoBlog")
|
|
viper.SetDefault("app.description", "一个简洁的个人博客")
|
|
viper.SetDefault("app.author", "Admin")
|
|
viper.SetDefault("app.theme", "default")
|
|
}
|
|
|
|
// parseConfig 解析配置到结构体
|
|
func parseConfig() *Config {
|
|
return &Config{
|
|
Database: DatabaseConfig{
|
|
Driver: viper.GetString("database.driver"),
|
|
DSN: viper.GetString("database.dsn"),
|
|
},
|
|
Server: ServerConfig{
|
|
Port: viper.GetInt("server.port"),
|
|
Mode: viper.GetString("server.mode"),
|
|
},
|
|
App: AppConfig{
|
|
Name: viper.GetString("app.name"),
|
|
Description: viper.GetString("app.description"),
|
|
Author: viper.GetString("app.author"),
|
|
Theme: viper.GetString("app.theme"),
|
|
},
|
|
}
|
|
}
|
|
|
|
// watchConfig 监听配置文件变更
|
|
func watchConfig() {
|
|
viper.OnConfigChange(func(e fsnotify.Event) {
|
|
slog.Info("配置文件已变更", "file", e.Name, "operation", e.Op.String())
|
|
// 重新解析配置
|
|
globalConfig = parseConfig()
|
|
slog.Info("配置已重新加载",
|
|
"theme", globalConfig.App.Theme,
|
|
"port", globalConfig.Server.Port,
|
|
)
|
|
})
|
|
|
|
viper.WatchConfig()
|
|
}
|
|
|
|
// GetGlobalConfig 获取全局配置(可用于热更新场景)
|
|
func GetGlobalConfig() *Config {
|
|
return globalConfig
|
|
}
|
|
|
|
// getConfig 获取全局配置(启动时已初始化,直接返回)
|
|
func GetConfig() *Config {
|
|
if cfg := GetGlobalConfig(); cfg != nil {
|
|
return cfg
|
|
}
|
|
return Load()
|
|
}
|