160 lines
4.5 KiB
Go
160 lines
4.5 KiB
Go
|
|
package config
|
||
|
|
|
||
|
|
import (
|
||
|
|
"log"
|
||
|
|
"os"
|
||
|
|
|
||
|
|
"github.com/spf13/viper"
|
||
|
|
)
|
||
|
|
|
||
|
|
type Config struct {
|
||
|
|
Server ServerConfig `mapstructure:"server"`
|
||
|
|
Database DatabaseConfig `mapstructure:"database"`
|
||
|
|
JWT JWTConfig `mapstructure:"jwt"`
|
||
|
|
Redis RedisConfig `mapstructure:"redis"`
|
||
|
|
App AppConfig `mapstructure:"app"`
|
||
|
|
Log LogConfig `mapstructure:"log"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type ServerConfig struct {
|
||
|
|
Port string `mapstructure:"port"`
|
||
|
|
Mode string `mapstructure:"mode"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type DatabaseConfig struct {
|
||
|
|
Host string `mapstructure:"host"`
|
||
|
|
Port string `mapstructure:"port"`
|
||
|
|
User string `mapstructure:"user"`
|
||
|
|
Password string `mapstructure:"password"`
|
||
|
|
DBName string `mapstructure:"dbname"`
|
||
|
|
Charset string `mapstructure:"charset"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type JWTConfig struct {
|
||
|
|
Secret string `mapstructure:"secret"`
|
||
|
|
AccessTokenTTL int `mapstructure:"access_token_ttl"`
|
||
|
|
RefreshTokenTTL int `mapstructure:"refresh_token_ttl"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type RedisConfig struct {
|
||
|
|
Host string `mapstructure:"host"`
|
||
|
|
Port string `mapstructure:"port"`
|
||
|
|
Password string `mapstructure:"password"`
|
||
|
|
DB int `mapstructure:"db"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type AppConfig struct {
|
||
|
|
Name string `mapstructure:"name"`
|
||
|
|
Version string `mapstructure:"version"`
|
||
|
|
Environment string `mapstructure:"environment"`
|
||
|
|
LogLevel string `mapstructure:"log_level"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type LogConfig struct {
|
||
|
|
Level string `mapstructure:"level"`
|
||
|
|
Format string `mapstructure:"format"`
|
||
|
|
Output string `mapstructure:"output"`
|
||
|
|
FilePath string `mapstructure:"file_path"`
|
||
|
|
MaxSize int `mapstructure:"max_size"`
|
||
|
|
MaxBackups int `mapstructure:"max_backups"`
|
||
|
|
MaxAge int `mapstructure:"max_age"`
|
||
|
|
Compress bool `mapstructure:"compress"`
|
||
|
|
}
|
||
|
|
|
||
|
|
var GlobalConfig *Config
|
||
|
|
|
||
|
|
func LoadConfig() {
|
||
|
|
// 获取环境变量,默认为 development
|
||
|
|
env := os.Getenv("GO_ENV")
|
||
|
|
if env == "" {
|
||
|
|
env = "development"
|
||
|
|
}
|
||
|
|
|
||
|
|
// 根据环境选择配置文件
|
||
|
|
configName := getConfigName(env)
|
||
|
|
|
||
|
|
viper.SetConfigName(configName)
|
||
|
|
viper.SetConfigType("yaml")
|
||
|
|
viper.AddConfigPath("./config")
|
||
|
|
viper.AddConfigPath(".")
|
||
|
|
|
||
|
|
// 设置环境变量前缀
|
||
|
|
viper.SetEnvPrefix("AI_ENGLISH")
|
||
|
|
viper.AutomaticEnv()
|
||
|
|
|
||
|
|
// 设置默认值
|
||
|
|
setDefaults()
|
||
|
|
|
||
|
|
if err := viper.ReadInConfig(); err != nil {
|
||
|
|
log.Printf("Warning: Config file '%s' not found, trying fallback...", configName)
|
||
|
|
// 尝试加载默认配置文件
|
||
|
|
viper.SetConfigName("config")
|
||
|
|
if err := viper.ReadInConfig(); err != nil {
|
||
|
|
log.Printf("Warning: Default config file not found, using defaults and environment variables: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
GlobalConfig = &Config{}
|
||
|
|
if err := viper.Unmarshal(GlobalConfig); err != nil {
|
||
|
|
log.Fatalf("Unable to decode config: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 从环境变量覆盖敏感配置
|
||
|
|
overrideFromEnv()
|
||
|
|
|
||
|
|
log.Printf("Loaded configuration for environment: %s (file: %s.yaml)", env, configName)
|
||
|
|
log.Printf("Server mode: %s, App environment: %s", GlobalConfig.Server.Mode, GlobalConfig.App.Environment)
|
||
|
|
}
|
||
|
|
|
||
|
|
// getConfigName 根据环境返回配置文件名
|
||
|
|
func getConfigName(env string) string {
|
||
|
|
switch env {
|
||
|
|
case "production", "prod":
|
||
|
|
return "config.prod"
|
||
|
|
case "development", "dev":
|
||
|
|
return "config.dev"
|
||
|
|
case "staging", "stage":
|
||
|
|
return "config.staging"
|
||
|
|
case "test":
|
||
|
|
return "config.test"
|
||
|
|
default:
|
||
|
|
return "config"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func setDefaults() {
|
||
|
|
viper.SetDefault("server.port", "8080")
|
||
|
|
viper.SetDefault("server.mode", "debug")
|
||
|
|
viper.SetDefault("database.host", "localhost")
|
||
|
|
viper.SetDefault("database.port", "3306")
|
||
|
|
viper.SetDefault("database.charset", "utf8mb4")
|
||
|
|
viper.SetDefault("jwt.access_token_ttl", 3600)
|
||
|
|
viper.SetDefault("jwt.refresh_token_ttl", 604800)
|
||
|
|
viper.SetDefault("redis.host", "localhost")
|
||
|
|
viper.SetDefault("redis.port", "6379")
|
||
|
|
viper.SetDefault("redis.db", 0)
|
||
|
|
viper.SetDefault("app.name", "AI English Learning")
|
||
|
|
viper.SetDefault("app.version", "1.0.0")
|
||
|
|
viper.SetDefault("app.environment", "development")
|
||
|
|
viper.SetDefault("app.log_level", "info")
|
||
|
|
viper.SetDefault("log.level", "info")
|
||
|
|
viper.SetDefault("log.format", "json")
|
||
|
|
viper.SetDefault("log.output", "both")
|
||
|
|
viper.SetDefault("log.file_path", "./logs/app.log")
|
||
|
|
viper.SetDefault("log.max_size", 100)
|
||
|
|
viper.SetDefault("log.max_backups", 10)
|
||
|
|
viper.SetDefault("log.max_age", 30)
|
||
|
|
viper.SetDefault("log.compress", true)
|
||
|
|
}
|
||
|
|
|
||
|
|
func overrideFromEnv() {
|
||
|
|
if dbPassword := os.Getenv("DB_PASSWORD"); dbPassword != "" {
|
||
|
|
GlobalConfig.Database.Password = dbPassword
|
||
|
|
}
|
||
|
|
if jwtSecret := os.Getenv("JWT_SECRET"); jwtSecret != "" {
|
||
|
|
GlobalConfig.JWT.Secret = jwtSecret
|
||
|
|
}
|
||
|
|
if redisPassword := os.Getenv("REDIS_PASSWORD"); redisPassword != "" {
|
||
|
|
GlobalConfig.Redis.Password = redisPassword
|
||
|
|
}
|
||
|
|
}
|