package config import ( "fmt" "os" "strconv" "time" "github.com/joho/godotenv" "github.com/spf13/viper" ) // Config 应用配置结构体 type Config struct { 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" } }