Files
ai_wht_wechat/go_backend/config/config.go
2026-01-07 22:55:12 +08:00

244 lines
9.6 KiB
Go
Raw Permalink 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"
"log"
"os"
"github.com/spf13/viper"
)
type Config struct {
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
Redis RedisConfig `mapstructure:"redis"`
JWT JWTConfig `mapstructure:"jwt"`
Wechat WechatConfig `mapstructure:"wechat"`
XHS XHSConfig `mapstructure:"xhs"`
Scheduler SchedulerConfig `mapstructure:"scheduler"`
Upload UploadConfig `mapstructure:"upload"`
AliSms AliSmsConfig `mapstructure:"ali_sms"`
}
type ServerConfig struct {
Port int `mapstructure:"port"`
Mode string `mapstructure:"mode"`
}
type DatabaseConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
DBName string `mapstructure:"dbname"`
Charset string `mapstructure:"charset"`
ParseTime bool `mapstructure:"parse_time"`
Loc string `mapstructure:"loc"`
MaxIdleConns int `mapstructure:"max_idle_conns"`
MaxOpenConns int `mapstructure:"max_open_conns"`
ConnMaxLifetime int `mapstructure:"conn_max_lifetime"`
}
type RedisConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Password string `mapstructure:"password"`
DB int `mapstructure:"db"`
PoolSize int `mapstructure:"pool_size"`
}
type JWTConfig struct {
Secret string `mapstructure:"secret"`
ExpireHours int `mapstructure:"expire_hours"`
}
type WechatConfig struct {
AppID string `mapstructure:"app_id"`
AppSecret string `mapstructure:"app_secret"`
}
type XHSConfig struct {
PythonServiceURL string `mapstructure:"python_service_url"`
}
type SchedulerConfig struct {
Enabled bool `mapstructure:"enabled"` // 是否启用定时任务
PublishCron string `mapstructure:"publish_cron"` // 发布任务的Cron表达式
MaxConcurrent int `mapstructure:"max_concurrent"` // 最大并发发布数
PublishTimeout int `mapstructure:"publish_timeout"` // 发布超时时间(秒)
MaxArticlesPerUserPerRun int `mapstructure:"max_articles_per_user_per_run"` // 每轮每个用户最大发文数
MaxFailuresPerUserPerRun int `mapstructure:"max_failures_per_user_per_run"` // 每轮每个用户最大失败次数
MaxDailyArticlesPerUser int `mapstructure:"max_daily_articles_per_user"` // 每个用户每日最大发文数
MaxHourlyArticlesPerUser int `mapstructure:"max_hourly_articles_per_user"` // 每个用户每小时最大发文数
Proxy string `mapstructure:"proxy"` // 全局代理地址(可选)
UserAgent string `mapstructure:"user_agent"` // 全局User-Agent可选
ProxyFetchURL string `mapstructure:"proxy_fetch_url"` // 动态获取代理的接口地址(可选)
}
// UploadConfig 文件上传配置
type UploadConfig struct {
MaxImageSize int64 `mapstructure:"max_image_size"` // 图片最大大小(字节)
MaxFileSize int64 `mapstructure:"max_file_size"` // 文件最大大小(字节)
ImageTypes []string `mapstructure:"image_types"` // 允许的图片类型
StaticPath string `mapstructure:"static_path"` // 静态文件路径(本地存储)
BaseURL string `mapstructure:"base_url"` // 静态文件访问基础URL本地存储
StorageType string `mapstructure:"storage_type"` // 存储类型local(本地) 或 oss(阿里云OSS)
OSS OSSConfig `mapstructure:"oss"` // OSS配置
}
type OSSConfig struct {
Endpoint string `mapstructure:"endpoint"` // OSS访问域名
AccessKeyID string `mapstructure:"access_key_id"` // AccessKey ID
AccessKeySecret string `mapstructure:"access_key_secret"` // AccessKey Secret
BucketName string `mapstructure:"bucket_name"` // Bucket名称
BasePath string `mapstructure:"base_path"` // 文件存储基础路径
Domain string `mapstructure:"domain"` // 自定义域名(可选)
}
// AliSmsConfig 阿里云短信配置
type AliSmsConfig struct {
AccessKeyID string `mapstructure:"access_key_id"` // AccessKey ID
AccessKeySecret string `mapstructure:"access_key_secret"` // AccessKey Secret
SignName string `mapstructure:"sign_name"` // 短信签名
TemplateCode string `mapstructure:"template_code"` // 短信模板CODE
}
var AppConfig *Config
// LoadConfig 加载配置文件
// 优先级: 环境变量 > 配置文件
func LoadConfig(env string) error {
// 1. 优先从环境变量 APP_ENV 获取环境配置
if envFromEnv := os.Getenv("APP_ENV"); envFromEnv != "" {
env = envFromEnv
log.Printf("从环境变量 APP_ENV 读取环境: %s", env)
}
if env == "" {
env = "dev"
}
// 2. 加载配置文件
viper.SetConfigName(fmt.Sprintf("config.%s", env))
viper.SetConfigType("yaml")
viper.AddConfigPath("./config")
viper.AddConfigPath("../config")
if err := viper.ReadInConfig(); err != nil {
return fmt.Errorf("读取配置文件失败: %w", err)
}
// 3. 绑定环境变量(自动读取环境变量覆盖配置)
viper.AutomaticEnv()
// 绑定特定的环境变量到配置项
bindEnvVariables()
AppConfig = &Config{}
if err := viper.Unmarshal(AppConfig); err != nil {
return fmt.Errorf("解析配置文件失败: %w", err)
}
// 打印OSS配置来源调试信息
log.Printf("\n=== OSS配置来源检查 ===")
log.Printf("upload.oss.access_key_secret 配置值: [%s]", AppConfig.Upload.OSS.AccessKeySecret)
log.Printf("环境变量 OSS_ACCESS_KEY_SECRET: [%s]", os.Getenv("OSS_ACCESS_KEY_SECRET"))
log.Printf("环境变量 OSS_TEST_ACCESS_KEY_SECRET: [%s]", os.Getenv("OSS_TEST_ACCESS_KEY_SECRET"))
log.Printf("====================\n")
log.Printf("配置加载成功: %s 环境", env)
log.Printf("数据库配置: %s@%s:%d/%s", AppConfig.Database.Username, AppConfig.Database.Host, AppConfig.Database.Port, AppConfig.Database.DBName)
log.Printf("Python服务地址: %s", AppConfig.XHS.PythonServiceURL)
return nil
}
// bindEnvVariables 绑定环境变量到配置项
func bindEnvVariables() {
// Server 配置
viper.BindEnv("server.port", "SERVER_PORT")
viper.BindEnv("server.mode", "SERVER_MODE")
// Database 配置
viper.BindEnv("database.host", "DB_HOST")
viper.BindEnv("database.port", "DB_PORT")
viper.BindEnv("database.username", "DB_USERNAME")
viper.BindEnv("database.password", "DB_PASSWORD")
viper.BindEnv("database.dbname", "DB_NAME")
viper.BindEnv("database.charset", "DB_CHARSET")
// Redis 配置
viper.BindEnv("redis.host", "REDIS_HOST")
viper.BindEnv("redis.port", "REDIS_PORT")
viper.BindEnv("redis.password", "REDIS_PASSWORD")
viper.BindEnv("redis.db", "REDIS_DB")
viper.BindEnv("redis.pool_size", "REDIS_POOL_SIZE")
// JWT 配置
viper.BindEnv("jwt.secret", "JWT_SECRET")
viper.BindEnv("jwt.expire_hours", "JWT_EXPIRE_HOURS")
// Wechat 配置
viper.BindEnv("wechat.app_id", "WECHAT_APP_ID")
viper.BindEnv("wechat.app_secret", "WECHAT_APP_SECRET")
// XHS 配置
viper.BindEnv("xhs.python_service_url", "XHS_PYTHON_SERVICE_URL")
// Scheduler 配置
viper.BindEnv("scheduler.enabled", "SCHEDULER_ENABLED")
viper.BindEnv("scheduler.publish_cron", "SCHEDULER_PUBLISH_CRON")
viper.BindEnv("scheduler.max_concurrent", "SCHEDULER_MAX_CONCURRENT")
viper.BindEnv("scheduler.publish_timeout", "SCHEDULER_PUBLISH_TIMEOUT")
viper.BindEnv("scheduler.max_articles_per_user_per_run", "SCHEDULER_MAX_ARTICLES_PER_USER_PER_RUN")
viper.BindEnv("scheduler.max_failures_per_user_per_run", "SCHEDULER_MAX_FAILURES_PER_USER_PER_RUN")
viper.BindEnv("scheduler.max_daily_articles_per_user", "SCHEDULER_MAX_DAILY_ARTICLES_PER_USER")
viper.BindEnv("scheduler.max_hourly_articles_per_user", "SCHEDULER_MAX_HOURLY_ARTICLES_PER_USER")
viper.BindEnv("scheduler.proxy", "SCHEDULER_PROXY")
viper.BindEnv("scheduler.user_agent", "SCHEDULER_USER_AGENT")
viper.BindEnv("scheduler.proxy_fetch_url", "SCHEDULER_PROXY_FETCH_URL")
// OSS 配置 - 强制从配置文件读取,不使用环境变量
// viper.BindEnv("upload.oss.endpoint", "OSS_ENDPOINT")
// viper.BindEnv("upload.oss.access_key_id", "OSS_ACCESS_KEY_ID")
// viper.BindEnv("upload.oss.access_key_secret", "OSS_ACCESS_KEY_SECRET")
// viper.BindEnv("upload.oss.bucket_name", "OSS_BUCKET_NAME")
// viper.BindEnv("upload.oss.base_path", "OSS_BASE_PATH")
// viper.BindEnv("upload.oss.domain", "OSS_DOMAIN")
// Upload 配置
viper.BindEnv("upload.max_image_size", "UPLOAD_MAX_IMAGE_SIZE")
viper.BindEnv("upload.max_file_size", "UPLOAD_MAX_FILE_SIZE")
viper.BindEnv("upload.static_path", "UPLOAD_STATIC_PATH")
viper.BindEnv("upload.base_url", "UPLOAD_BASE_URL")
viper.BindEnv("upload.storage_type", "UPLOAD_STORAGE_TYPE")
// AliSms 配置
viper.BindEnv("ali_sms.access_key_id", "ALI_SMS_ACCESS_KEY_ID")
viper.BindEnv("ali_sms.access_key_secret", "ALI_SMS_ACCESS_KEY_SECRET")
viper.BindEnv("ali_sms.sign_name", "ALI_SMS_SIGN_NAME")
viper.BindEnv("ali_sms.template_code", "ALI_SMS_TEMPLATE_CODE")
}
// GetDSN 获取数据库连接字符串
func (c *DatabaseConfig) GetDSN() string {
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%t&loc=%s",
c.Username,
c.Password,
c.Host,
c.Port,
c.DBName,
c.Charset,
c.ParseTime,
c.Loc,
)
}
// GetPythonServiceURL 获取Python服务地址
func GetPythonServiceURL() string {
if AppConfig != nil && AppConfig.XHS.PythonServiceURL != "" {
return AppConfig.XHS.PythonServiceURL
}
// 默认返回本地地址
return "http://localhost:8000"
}