Files
ai_wht_wechat/go_backend/config/config.go
2025-12-19 22:36:48 +08:00

160 lines
5.7 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"
"log"
"os"
"github.com/spf13/viper"
)
type Config struct {
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
JWT JWTConfig `mapstructure:"jwt"`
Wechat WechatConfig `mapstructure:"wechat"`
XHS XHSConfig `mapstructure:"xhs"`
Scheduler SchedulerConfig `mapstructure:"scheduler"`
}
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 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"` // 动态获取代理的接口地址(可选)
}
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)
}
log.Printf("配置加载成功: %s 环境", env)
log.Printf("数据库配置: %s@%s:%d/%s", AppConfig.Database.Username, AppConfig.Database.Host, AppConfig.Database.Port, AppConfig.Database.DBName)
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")
// 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")
}
// 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,
)
}