Files
go_typecho/config/config.go
T

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