2025-11-28 23:30:49 +08:00
package config
import (
"fmt"
"os"
"strconv"
2025-12-02 17:40:39 +08:00
"strings"
2025-11-28 23:30:49 +08:00
"time"
"github.com/joho/godotenv"
"github.com/spf13/viper"
)
// Config 应用配置结构体
type Config struct {
2025-11-30 18:56:56 +08:00
Environment string ` mapstructure:"environment" `
2025-12-08 19:12:30 +08:00
Site SiteConfig ` mapstructure:"site" `
2025-11-30 18:56:56 +08:00
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" `
Email EmailConfig ` mapstructure:"email" `
2025-12-02 17:40:39 +08:00
Security SecurityConfig ` mapstructure:"security" `
2025-11-28 23:30:49 +08:00
}
2025-12-08 19:12:30 +08:00
// SiteConfig 站点配置
type SiteConfig struct {
Name string ` mapstructure:"name" `
Description string ` mapstructure:"description" `
RegistrationEnabled bool ` mapstructure:"registration_enabled" `
DefaultAvatar string ` mapstructure:"default_avatar" `
MaxTexturesPerUser int ` mapstructure:"max_textures_per_user" `
MaxProfilesPerUser int ` mapstructure:"max_profiles_per_user" `
CheckinReward int ` mapstructure:"checkin_reward" `
TextureDownloadReward int ` mapstructure:"texture_download_reward" `
}
2025-11-28 23:30:49 +08:00
// ServerConfig 服务器配置
type ServerConfig struct {
2025-12-26 01:15:17 +08:00
Port string ` mapstructure:"port" `
Mode string ` mapstructure:"mode" `
ReadTimeout time . Duration ` mapstructure:"read_timeout" `
WriteTimeout time . Duration ` mapstructure:"write_timeout" `
SwaggerEnabled bool ` mapstructure:"swagger_enabled" `
2025-11-28 23:30:49 +08:00
}
// 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" `
2025-12-03 10:58:39 +08:00
ConnMaxIdleTime time . Duration ` mapstructure:"conn_max_idle_time" ` // 连接最大空闲时间
2025-11-28 23:30:49 +08:00
}
// RedisConfig Redis配置
type RedisConfig struct {
2025-12-03 10:58:39 +08:00
Host string ` mapstructure:"host" `
Port int ` mapstructure:"port" `
Password string ` mapstructure:"password" `
Database int ` mapstructure:"database" `
PoolSize int ` mapstructure:"pool_size" ` // 连接池大小
MinIdleConns int ` mapstructure:"min_idle_conns" ` // 最小空闲连接数
MaxRetries int ` mapstructure:"max_retries" ` // 最大重试次数
DialTimeout time . Duration ` mapstructure:"dial_timeout" ` // 连接超时
ReadTimeout time . Duration ` mapstructure:"read_timeout" ` // 读取超时
WriteTimeout time . Duration ` mapstructure:"write_timeout" ` // 写入超时
PoolTimeout time . Duration ` mapstructure:"pool_timeout" ` // 连接池超时
ConnMaxIdleTime time . Duration ` mapstructure:"conn_max_idle_time" ` // 连接最大空闲时间
2025-11-28 23:30:49 +08:00
}
// RustFSConfig RustFS对象存储配置 (S3兼容)
type RustFSConfig struct {
Endpoint string ` mapstructure:"endpoint" `
2025-12-02 11:22:14 +08:00
PublicURL string ` mapstructure:"public_url" ` // 公开访问URL (用于生成文件访问链接)
2025-11-28 23:30:49 +08:00
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 {
2025-11-30 18:56:56 +08:00
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" `
2025-11-28 23:30:49 +08:00
}
// 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" `
}
2025-12-02 17:40:39 +08:00
// SecurityConfig 安全配置
type SecurityConfig struct {
AllowedOrigins [ ] string ` mapstructure:"allowed_origins" ` // 允许的CORS来源
AllowedDomains [ ] string ` mapstructure:"allowed_domains" ` // 允许的头像/材质URL域名
}
2025-11-28 23:30:49 +08:00
// Load 加载配置 - 完全从环境变量加载, 不依赖YAML文件
func Load ( ) ( * Config , error ) {
// 加载.env文件( 如果存在)
2026-01-10 03:15:27 +08:00
if err := godotenv . Load ( ".env" ) ; err != nil {
2026-01-10 01:58:46 +08:00
fmt . Printf ( "[Config] 注意: 未加载 .env 文件 (原因: %v)\n" , err )
} else {
fmt . Println ( "[Config] 成功加载 .env 文件" )
2026-01-10 03:15:27 +08:00
}
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 设置默认值
setDefaults ( )
2025-11-30 18:56:56 +08:00
2026-01-10 03:15:27 +08:00
// 自动读取环境变量(不设置前缀,因为 BindEnv 已经明确指定了变量名)
2025-11-28 23:30:49 +08:00
viper . AutomaticEnv ( )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 手动设置环境变量映射
setupEnvMappings ( )
// 直接从环境变量解析配置
var config Config
if err := viper . Unmarshal ( & config ) ; err != nil {
return nil , fmt . Errorf ( "解析配置失败: %w" , err )
}
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 从环境变量中覆盖配置
overrideFromEnv ( & config )
2026-01-10 01:58:46 +08:00
// 打印关键配置加载状态
fmt . Println ( "==================================================" )
fmt . Println ( " CarrotSkin Configuration Check " )
fmt . Println ( "==================================================" )
fmt . Printf ( "Server Port: %s\n" , config . Server . Port )
fmt . Printf ( "Database Host: %s\n" , config . Database . Host )
fmt . Printf ( "Redis Host: %s\n" , config . Redis . Host )
fmt . Printf ( "Environment: %s\n" , config . Environment )
if config . Database . Host == "localhost" && os . Getenv ( "DATABASE_HOST" ) != "" && os . Getenv ( "DATABASE_HOST" ) != "localhost" {
fmt . Printf ( "[Warning] Database Host is 'localhost' but env DATABASE_HOST is set to '%s'. Viper binding might have failed.\n" , os . Getenv ( "DATABASE_HOST" ) )
}
fmt . Println ( "==================================================" )
2025-11-28 23:30:49 +08:00
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" )
2025-12-26 01:15:17 +08:00
viper . SetDefault ( "server.swagger_enabled" , true )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 数据库默认配置
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" )
2025-12-03 10:58:39 +08:00
viper . SetDefault ( "database.conn_max_idle_time" , "10m" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// Redis默认配置
viper . SetDefault ( "redis.host" , "localhost" )
viper . SetDefault ( "redis.port" , 6379 )
viper . SetDefault ( "redis.database" , 0 )
viper . SetDefault ( "redis.pool_size" , 10 )
2025-12-03 10:58:39 +08:00
viper . SetDefault ( "redis.min_idle_conns" , 5 )
viper . SetDefault ( "redis.max_retries" , 3 )
viper . SetDefault ( "redis.dial_timeout" , "5s" )
viper . SetDefault ( "redis.read_timeout" , "3s" )
viper . SetDefault ( "redis.write_timeout" , "3s" )
viper . SetDefault ( "redis.pool_timeout" , "4s" )
viper . SetDefault ( "redis.conn_max_idle_time" , "30m" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// RustFS默认配置
viper . SetDefault ( "rustfs.endpoint" , "127.0.0.1:9000" )
2025-12-02 17:40:39 +08:00
viper . SetDefault ( "rustfs.public_url" , "" ) // 为空时使用 endpoint 构建 URL
2025-11-28 23:30:49 +08:00
viper . SetDefault ( "rustfs.use_ssl" , false )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// JWT默认配置
viper . SetDefault ( "jwt.expire_hours" , 168 )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// Casbin默认配置
viper . SetDefault ( "casbin.model_path" , "configs/casbin/rbac_model.conf" )
viper . SetDefault ( "casbin.policy_adapter" , "gorm" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 日志默认配置
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 )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 邮件默认配置
viper . SetDefault ( "email.enabled" , false )
viper . SetDefault ( "email.smtp_port" , 587 )
2025-12-02 17:40:39 +08:00
// 安全默认配置
viper . SetDefault ( "security.allowed_origins" , [ ] string { "*" } )
viper . SetDefault ( "security.allowed_domains" , [ ] string { "localhost" , "127.0.0.1" } )
2025-12-08 19:12:30 +08:00
// 站点默认配置
viper . SetDefault ( "site.name" , "CarrotSkin" )
viper . SetDefault ( "site.description" , "一个优秀的Minecraft皮肤站" )
viper . SetDefault ( "site.registration_enabled" , true )
viper . SetDefault ( "site.default_avatar" , "" )
viper . SetDefault ( "site.max_textures_per_user" , 50 )
viper . SetDefault ( "site.max_profiles_per_user" , 5 )
viper . SetDefault ( "site.checkin_reward" , 10 )
viper . SetDefault ( "site.texture_download_reward" , 1 )
2025-11-28 23:30:49 +08:00
}
// 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" )
2025-12-26 01:15:17 +08:00
viper . BindEnv ( "server.swagger_enabled" , "SERVER_SWAGGER_ENABLED" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 数据库配置
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" )
2025-12-03 10:58:39 +08:00
viper . BindEnv ( "database.max_idle_conns" , "DATABASE_MAX_IDLE_CONNS" )
viper . BindEnv ( "database.max_open_conns" , "DATABASE_MAX_OPEN_CONNS" )
viper . BindEnv ( "database.conn_max_lifetime" , "DATABASE_CONN_MAX_LIFETIME" )
viper . BindEnv ( "database.conn_max_idle_time" , "DATABASE_CONN_MAX_IDLE_TIME" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 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" )
2025-12-03 10:58:39 +08:00
viper . BindEnv ( "redis.pool_size" , "REDIS_POOL_SIZE" )
viper . BindEnv ( "redis.min_idle_conns" , "REDIS_MIN_IDLE_CONNS" )
viper . BindEnv ( "redis.max_retries" , "REDIS_MAX_RETRIES" )
viper . BindEnv ( "redis.dial_timeout" , "REDIS_DIAL_TIMEOUT" )
viper . BindEnv ( "redis.read_timeout" , "REDIS_READ_TIMEOUT" )
viper . BindEnv ( "redis.write_timeout" , "REDIS_WRITE_TIMEOUT" )
viper . BindEnv ( "redis.pool_timeout" , "REDIS_POOL_TIMEOUT" )
viper . BindEnv ( "redis.conn_max_idle_time" , "REDIS_CONN_MAX_IDLE_TIME" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// RustFS配置
viper . BindEnv ( "rustfs.endpoint" , "RUSTFS_ENDPOINT" )
2025-12-02 11:22:14 +08:00
viper . BindEnv ( "rustfs.public_url" , "RUSTFS_PUBLIC_URL" )
2025-11-28 23:30:49 +08:00
viper . BindEnv ( "rustfs.access_key" , "RUSTFS_ACCESS_KEY" )
viper . BindEnv ( "rustfs.secret_key" , "RUSTFS_SECRET_KEY" )
viper . BindEnv ( "rustfs.use_ssl" , "RUSTFS_USE_SSL" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// JWT配置
viper . BindEnv ( "jwt.secret" , "JWT_SECRET" )
viper . BindEnv ( "jwt.expire_hours" , "JWT_EXPIRE_HOURS" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 日志配置
viper . BindEnv ( "log.level" , "LOG_LEVEL" )
viper . BindEnv ( "log.format" , "LOG_FORMAT" )
viper . BindEnv ( "log.output" , "LOG_OUTPUT" )
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 邮件配置
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" )
2025-12-08 19:12:30 +08:00
// 站点配置
viper . BindEnv ( "site.name" , "SITE_NAME" )
viper . BindEnv ( "site.description" , "SITE_DESCRIPTION" )
viper . BindEnv ( "site.registration_enabled" , "REGISTRATION_ENABLED" )
viper . BindEnv ( "site.default_avatar" , "DEFAULT_AVATAR" )
viper . BindEnv ( "site.max_textures_per_user" , "MAX_TEXTURES_PER_USER" )
viper . BindEnv ( "site.max_profiles_per_user" , "MAX_PROFILES_PER_USER" )
viper . BindEnv ( "site.checkin_reward" , "CHECKIN_REWARD" )
viper . BindEnv ( "site.texture_download_reward" , "TEXTURE_DOWNLOAD_REWARD" )
2025-11-28 23:30:49 +08:00
}
// overrideFromEnv 从环境变量中覆盖配置
func overrideFromEnv ( config * Config ) {
2026-01-10 03:15:27 +08:00
2025-11-28 23:30:49 +08:00
// 处理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
}
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
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
}
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
// 处理数据库连接池配置
if maxIdleConns := os . Getenv ( "DATABASE_MAX_IDLE_CONNS" ) ; maxIdleConns != "" {
if val , err := strconv . Atoi ( maxIdleConns ) ; err == nil {
config . Database . MaxIdleConns = val
}
}
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
if maxOpenConns := os . Getenv ( "DATABASE_MAX_OPEN_CONNS" ) ; maxOpenConns != "" {
if val , err := strconv . Atoi ( maxOpenConns ) ; err == nil {
config . Database . MaxOpenConns = val
}
}
2025-11-30 18:56:56 +08:00
2025-11-28 23:30:49 +08:00
if connMaxLifetime := os . Getenv ( "DATABASE_CONN_MAX_LIFETIME" ) ; connMaxLifetime != "" {
if val , err := time . ParseDuration ( connMaxLifetime ) ; err == nil {
config . Database . ConnMaxLifetime = val
}
}
2025-11-30 18:56:56 +08:00
2025-12-03 10:58:39 +08:00
if connMaxIdleTime := os . Getenv ( "DATABASE_CONN_MAX_IDLE_TIME" ) ; connMaxIdleTime != "" {
if val , err := time . ParseDuration ( connMaxIdleTime ) ; err == nil {
config . Database . ConnMaxIdleTime = val
}
}
2026-01-10 03:15:27 +08:00
// 处理Redis基本配置
if host := os . Getenv ( "REDIS_HOST" ) ; host != "" {
config . Redis . Host = host
}
if port := os . Getenv ( "REDIS_PORT" ) ; port != "" {
if val , err := strconv . Atoi ( port ) ; err == nil {
config . Redis . Port = val
}
}
if password := os . Getenv ( "REDIS_PASSWORD" ) ; password != "" {
config . Redis . Password = password
}
if database := os . Getenv ( "REDIS_DATABASE" ) ; database != "" {
if val , err := strconv . Atoi ( database ) ; err == nil {
config . Redis . Database = val
}
}
2025-12-03 10:58:39 +08:00
// 处理Redis连接池配置
2025-11-28 23:30:49 +08:00
if poolSize := os . Getenv ( "REDIS_POOL_SIZE" ) ; poolSize != "" {
if val , err := strconv . Atoi ( poolSize ) ; err == nil {
config . Redis . PoolSize = val
}
}
2025-11-30 18:56:56 +08:00
2025-12-03 10:58:39 +08:00
if minIdleConns := os . Getenv ( "REDIS_MIN_IDLE_CONNS" ) ; minIdleConns != "" {
if val , err := strconv . Atoi ( minIdleConns ) ; err == nil {
config . Redis . MinIdleConns = val
}
}
if maxRetries := os . Getenv ( "REDIS_MAX_RETRIES" ) ; maxRetries != "" {
if val , err := strconv . Atoi ( maxRetries ) ; err == nil {
config . Redis . MaxRetries = val
}
}
if dialTimeout := os . Getenv ( "REDIS_DIAL_TIMEOUT" ) ; dialTimeout != "" {
if val , err := time . ParseDuration ( dialTimeout ) ; err == nil {
config . Redis . DialTimeout = val
}
}
if readTimeout := os . Getenv ( "REDIS_READ_TIMEOUT" ) ; readTimeout != "" {
if val , err := time . ParseDuration ( readTimeout ) ; err == nil {
config . Redis . ReadTimeout = val
}
}
if writeTimeout := os . Getenv ( "REDIS_WRITE_TIMEOUT" ) ; writeTimeout != "" {
if val , err := time . ParseDuration ( writeTimeout ) ; err == nil {
config . Redis . WriteTimeout = val
}
}
if poolTimeout := os . Getenv ( "REDIS_POOL_TIMEOUT" ) ; poolTimeout != "" {
if val , err := time . ParseDuration ( poolTimeout ) ; err == nil {
config . Redis . PoolTimeout = val
}
}
if connMaxIdleTime := os . Getenv ( "REDIS_CONN_MAX_IDLE_TIME" ) ; connMaxIdleTime != "" {
if val , err := time . ParseDuration ( connMaxIdleTime ) ; err == nil {
config . Redis . ConnMaxIdleTime = val
}
}
2025-11-28 23:30:49 +08:00
// 处理邮件配置
if emailEnabled := os . Getenv ( "EMAIL_ENABLED" ) ; emailEnabled != "" {
config . Email . Enabled = emailEnabled == "true" || emailEnabled == "True" || emailEnabled == "TRUE" || emailEnabled == "1"
}
2025-11-30 18:56:56 +08:00
// 处理环境配置
if env := os . Getenv ( "ENVIRONMENT" ) ; env != "" {
config . Environment = env
}
2025-12-02 17:40:39 +08:00
// 处理安全配置
if allowedOrigins := os . Getenv ( "SECURITY_ALLOWED_ORIGINS" ) ; allowedOrigins != "" {
config . Security . AllowedOrigins = strings . Split ( allowedOrigins , "," )
}
if allowedDomains := os . Getenv ( "SECURITY_ALLOWED_DOMAINS" ) ; allowedDomains != "" {
config . Security . AllowedDomains = strings . Split ( allowedDomains , "," )
}
2025-11-30 18:56:56 +08:00
}
// IsTestEnvironment 判断是否为测试环境
func ( c * Config ) IsTestEnvironment ( ) bool {
return c . Environment == "test"
2025-11-28 23:30:49 +08:00
}