Files
backend/pkg/config/config.go

316 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package config
import (
"fmt"
"os"
"strconv"
"time"
"github.com/joho/godotenv"
"github.com/spf13/viper"
)
// Config 应用配置结构体
type Config struct {
Environment string `mapstructure:"environment"`
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
Redis RedisConfig `mapstructure:"redis"`
RustFS RustFSConfig `mapstructure:"rustfs"`
JWT JWTConfig `mapstructure:"jwt"`
Casbin CasbinConfig `mapstructure:"casbin"`
Log LogConfig `mapstructure:"log"`
Upload UploadConfig `mapstructure:"upload"`
Email EmailConfig `mapstructure:"email"`
}
// ServerConfig 服务器配置
type ServerConfig struct {
Port string `mapstructure:"port"`
Mode string `mapstructure:"mode"`
ReadTimeout time.Duration `mapstructure:"read_timeout"`
WriteTimeout time.Duration `mapstructure:"write_timeout"`
}
// DatabaseConfig 数据库配置
type DatabaseConfig struct {
Driver string `mapstructure:"driver"`
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Database string `mapstructure:"database"`
SSLMode string `mapstructure:"ssl_mode"`
Timezone string `mapstructure:"timezone"`
MaxIdleConns int `mapstructure:"max_idle_conns"`
MaxOpenConns int `mapstructure:"max_open_conns"`
ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"`
}
// RedisConfig Redis配置
type RedisConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Password string `mapstructure:"password"`
Database int `mapstructure:"database"`
PoolSize int `mapstructure:"pool_size"`
}
// RustFSConfig RustFS对象存储配置 (S3兼容)
type RustFSConfig struct {
Endpoint string `mapstructure:"endpoint"`
AccessKey string `mapstructure:"access_key"`
SecretKey string `mapstructure:"secret_key"`
UseSSL bool `mapstructure:"use_ssl"`
Buckets map[string]string `mapstructure:"buckets"`
}
// JWTConfig JWT配置
type JWTConfig struct {
Secret string `mapstructure:"secret"`
ExpireHours int `mapstructure:"expire_hours"`
}
// CasbinConfig Casbin权限配置
type CasbinConfig struct {
ModelPath string `mapstructure:"model_path"`
PolicyAdapter string `mapstructure:"policy_adapter"`
}
// LogConfig 日志配置
type LogConfig struct {
Level string `mapstructure:"level"`
Format string `mapstructure:"format"`
Output string `mapstructure:"output"`
MaxSize int `mapstructure:"max_size"`
MaxBackups int `mapstructure:"max_backups"`
MaxAge int `mapstructure:"max_age"`
Compress bool `mapstructure:"compress"`
}
// UploadConfig 文件上传配置
type UploadConfig struct {
MaxSize int64 `mapstructure:"max_size"`
AllowedTypes []string `mapstructure:"allowed_types"`
TextureMaxSize int64 `mapstructure:"texture_max_size"`
AvatarMaxSize int64 `mapstructure:"avatar_max_size"`
}
// EmailConfig 邮件配置
type EmailConfig struct {
Enabled bool `mapstructure:"enabled"`
SMTPHost string `mapstructure:"smtp_host"`
SMTPPort int `mapstructure:"smtp_port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
FromName string `mapstructure:"from_name"`
}
// Load 加载配置 - 完全从环境变量加载不依赖YAML文件
func Load() (*Config, error) {
// 加载.env文件如果存在
_ = godotenv.Load(".env")
// 设置默认值
setDefaults()
// 设置环境变量前缀
viper.SetEnvPrefix("CARROTSKIN")
viper.AutomaticEnv()
// 手动设置环境变量映射
setupEnvMappings()
// 直接从环境变量解析配置
var config Config
if err := viper.Unmarshal(&config); err != nil {
return nil, fmt.Errorf("解析配置失败: %w", err)
}
// 从环境变量中覆盖配置
overrideFromEnv(&config)
return &config, nil
}
// setDefaults 设置默认配置值
func setDefaults() {
// 服务器默认配置
viper.SetDefault("server.port", ":8080")
viper.SetDefault("server.mode", "debug")
viper.SetDefault("server.read_timeout", "30s")
viper.SetDefault("server.write_timeout", "30s")
// 数据库默认配置
viper.SetDefault("database.driver", "postgres")
viper.SetDefault("database.host", "localhost")
viper.SetDefault("database.port", 5432)
viper.SetDefault("database.ssl_mode", "disable")
viper.SetDefault("database.timezone", "Asia/Shanghai")
viper.SetDefault("database.max_idle_conns", 10)
viper.SetDefault("database.max_open_conns", 100)
viper.SetDefault("database.conn_max_lifetime", "1h")
// Redis默认配置
viper.SetDefault("redis.host", "localhost")
viper.SetDefault("redis.port", 6379)
viper.SetDefault("redis.database", 0)
viper.SetDefault("redis.pool_size", 10)
// RustFS默认配置
viper.SetDefault("rustfs.endpoint", "127.0.0.1:9000")
viper.SetDefault("rustfs.use_ssl", false)
// JWT默认配置
viper.SetDefault("jwt.expire_hours", 168)
// Casbin默认配置
viper.SetDefault("casbin.model_path", "configs/casbin/rbac_model.conf")
viper.SetDefault("casbin.policy_adapter", "gorm")
// 日志默认配置
viper.SetDefault("log.level", "info")
viper.SetDefault("log.format", "json")
viper.SetDefault("log.output", "logs/app.log")
viper.SetDefault("log.max_size", 100)
viper.SetDefault("log.max_backups", 3)
viper.SetDefault("log.max_age", 28)
viper.SetDefault("log.compress", true)
// 文件上传默认配置
viper.SetDefault("upload.max_size", 10485760)
viper.SetDefault("upload.texture_max_size", 2097152)
viper.SetDefault("upload.avatar_max_size", 1048576)
viper.SetDefault("upload.allowed_types", []string{"image/png", "image/jpeg"})
// 邮件默认配置
viper.SetDefault("email.enabled", false)
viper.SetDefault("email.smtp_port", 587)
}
// setupEnvMappings 设置环境变量映射
func setupEnvMappings() {
// 服务器配置
viper.BindEnv("server.port", "SERVER_PORT")
viper.BindEnv("server.mode", "SERVER_MODE")
viper.BindEnv("server.read_timeout", "SERVER_READ_TIMEOUT")
viper.BindEnv("server.write_timeout", "SERVER_WRITE_TIMEOUT")
// 数据库配置
viper.BindEnv("database.driver", "DATABASE_DRIVER")
viper.BindEnv("database.host", "DATABASE_HOST")
viper.BindEnv("database.port", "DATABASE_PORT")
viper.BindEnv("database.username", "DATABASE_USERNAME")
viper.BindEnv("database.password", "DATABASE_PASSWORD")
viper.BindEnv("database.database", "DATABASE_NAME")
viper.BindEnv("database.ssl_mode", "DATABASE_SSL_MODE")
viper.BindEnv("database.timezone", "DATABASE_TIMEZONE")
// Redis配置
viper.BindEnv("redis.host", "REDIS_HOST")
viper.BindEnv("redis.port", "REDIS_PORT")
viper.BindEnv("redis.password", "REDIS_PASSWORD")
viper.BindEnv("redis.database", "REDIS_DATABASE")
// RustFS配置
viper.BindEnv("rustfs.endpoint", "RUSTFS_ENDPOINT")
viper.BindEnv("rustfs.access_key", "RUSTFS_ACCESS_KEY")
viper.BindEnv("rustfs.secret_key", "RUSTFS_SECRET_KEY")
viper.BindEnv("rustfs.use_ssl", "RUSTFS_USE_SSL")
// JWT配置
viper.BindEnv("jwt.secret", "JWT_SECRET")
viper.BindEnv("jwt.expire_hours", "JWT_EXPIRE_HOURS")
// 日志配置
viper.BindEnv("log.level", "LOG_LEVEL")
viper.BindEnv("log.format", "LOG_FORMAT")
viper.BindEnv("log.output", "LOG_OUTPUT")
// 邮件配置
viper.BindEnv("email.enabled", "EMAIL_ENABLED")
viper.BindEnv("email.smtp_host", "EMAIL_SMTP_HOST")
viper.BindEnv("email.smtp_port", "EMAIL_SMTP_PORT")
viper.BindEnv("email.username", "EMAIL_USERNAME")
viper.BindEnv("email.password", "EMAIL_PASSWORD")
viper.BindEnv("email.from_name", "EMAIL_FROM_NAME")
}
// overrideFromEnv 从环境变量中覆盖配置
func overrideFromEnv(config *Config) {
// 处理RustFS存储桶配置
if texturesBucket := os.Getenv("RUSTFS_BUCKET_TEXTURES"); texturesBucket != "" {
if config.RustFS.Buckets == nil {
config.RustFS.Buckets = make(map[string]string)
}
config.RustFS.Buckets["textures"] = texturesBucket
}
if avatarsBucket := os.Getenv("RUSTFS_BUCKET_AVATARS"); avatarsBucket != "" {
if config.RustFS.Buckets == nil {
config.RustFS.Buckets = make(map[string]string)
}
config.RustFS.Buckets["avatars"] = avatarsBucket
}
// 处理数据库连接池配置
if maxIdleConns := os.Getenv("DATABASE_MAX_IDLE_CONNS"); maxIdleConns != "" {
if val, err := strconv.Atoi(maxIdleConns); err == nil {
config.Database.MaxIdleConns = val
}
}
if maxOpenConns := os.Getenv("DATABASE_MAX_OPEN_CONNS"); maxOpenConns != "" {
if val, err := strconv.Atoi(maxOpenConns); err == nil {
config.Database.MaxOpenConns = val
}
}
if connMaxLifetime := os.Getenv("DATABASE_CONN_MAX_LIFETIME"); connMaxLifetime != "" {
if val, err := time.ParseDuration(connMaxLifetime); err == nil {
config.Database.ConnMaxLifetime = val
}
}
// 处理Redis池大小
if poolSize := os.Getenv("REDIS_POOL_SIZE"); poolSize != "" {
if val, err := strconv.Atoi(poolSize); err == nil {
config.Redis.PoolSize = val
}
}
// 处理文件上传配置
if maxSize := os.Getenv("UPLOAD_MAX_SIZE"); maxSize != "" {
if val, err := strconv.ParseInt(maxSize, 10, 64); err == nil {
config.Upload.MaxSize = val
}
}
if textureMaxSize := os.Getenv("UPLOAD_TEXTURE_MAX_SIZE"); textureMaxSize != "" {
if val, err := strconv.ParseInt(textureMaxSize, 10, 64); err == nil {
config.Upload.TextureMaxSize = val
}
}
if avatarMaxSize := os.Getenv("UPLOAD_AVATAR_MAX_SIZE"); avatarMaxSize != "" {
if val, err := strconv.ParseInt(avatarMaxSize, 10, 64); err == nil {
config.Upload.AvatarMaxSize = val
}
}
// 处理邮件配置
if emailEnabled := os.Getenv("EMAIL_ENABLED"); emailEnabled != "" {
config.Email.Enabled = emailEnabled == "true" || emailEnabled == "True" || emailEnabled == "TRUE" || emailEnabled == "1"
}
// 处理环境配置
if env := os.Getenv("ENVIRONMENT"); env != "" {
config.Environment = env
}
}
// IsTestEnvironment 判断是否为测试环境
func (c *Config) IsTestEnvironment() bool {
return c.Environment == "test"
}