Files
wx_service/config/config.go
T
nepiedg 1b8ff310eb Add media proxy feature for resource downloading
- Introduced a new API endpoint `GET /api/v1/video/proxy` to facilitate media resource downloads, allowing users to bypass domain restrictions imposed by WeChat.
- Updated configuration to include proxy settings such as `SHORT_VIDEO_PROXY_ENABLED`, `SHORT_VIDEO_PROXY_ALLOWED_DOMAINS`, `SHORT_VIDEO_PROXY_MAX_SIZE_MB`, and `SHORT_VIDEO_PROXY_TIMEOUT_SECONDS`.
- Enhanced the `ShortVideoConfig` struct to accommodate new proxy-related fields.
- Improved error handling for proxy requests, including checks for allowed domains and file size limits.
- Updated documentation to reflect the new proxy functionality and its configuration options, ensuring clarity for users and developers.
2026-02-06 11:28:02 +00:00

235 lines
6.6 KiB
Go
Executable File

package config
import (
"log"
"os"
"strconv"
"strings"
"time"
"github.com/joho/godotenv"
)
type Config struct {
Server ServerConfig
Database DatabaseConfig
JWT JWTConfig
ShortVideo ShortVideoConfig
AI AIConfig
Admin AdminConfig
Qiniu QiniuConfig
WeChatOA WeChatOfficialConfig
Redis RedisConfig
}
type ServerConfig struct {
Port string
Mode string
}
type DatabaseConfig struct {
Default DatabaseInstanceConfig
Additional map[string]DatabaseInstanceConfig
}
type DatabaseInstanceConfig struct {
Host string
Port string
User string
Password string
DBName string
}
type JWTConfig struct {
Secret string
Expire int
}
type ShortVideoConfig struct {
APIKey string
FreeDailyQuota int
RequestTimeout time.Duration
// 代理相关配置
ProxyEnabled bool // 是否启用媒体代理
ProxyAllowedDomains []string // 允许代理的域名白名单(为空表示允许所有)
ProxyMaxSize int64 // 代理文件最大大小(字节),0 表示不限制
ProxyTimeout time.Duration // 代理请求超时时间
}
// AIConfig 用于“AI 建议/问答”等能力的通用配置(OpenAI-compatible)。
type AIConfig struct {
BaseURL string
APIKey string
Model string
RequestTimeout time.Duration
}
// AdminConfig 用于简单的后台/运维接口鉴权(如生成兑换码)。
type AdminConfig struct {
Token string
}
// QiniuConfig 用于七牛云(Kodo)直传相关配置。
// 前端通常会向后端请求 upload token,然后直传文件到七牛。
type QiniuConfig struct {
AccessKey string
SecretKey string
Bucket string
UploadURL string
CDNDomain string
KeyPrefix string
TokenExpireSeconds int
}
// WeChatOfficialConfig 用于微信公众号网页授权(OAuth2)相关接口。
type WeChatOfficialConfig struct {
AppID string
AppSecret string
RequestTimeout time.Duration
}
// RedisConfig 用于可选的 Redis 缓存(例如缓存 session_key -> user,减少 DB 查询)。
type RedisConfig struct {
Addr string
Password string
DB int
KeyPrefix string
SessionTTLSeconds int
}
var AppConfig *Config
func LoadConfig() {
// 加载 .env 文件
if err := godotenv.Load(); err != nil {
log.Println("未找到 .env 文件,使用环境变量")
}
defaultDB := DatabaseInstanceConfig{
Host: getEnv("DB_HOST", "localhost"),
Port: getEnv("DB_PORT", "3306"),
User: getEnv("DB_USER", "root"),
Password: getEnv("DB_PASSWORD", ""),
DBName: getEnv("DB_NAME", "wx_service"),
}
AppConfig = &Config{
Server: ServerConfig{
Port: getEnv("SERVER_PORT", "8080"),
Mode: getEnv("GIN_MODE", "debug"),
},
Database: DatabaseConfig{
Default: defaultDB,
Additional: loadAdditionalDBConfigs(defaultDB),
},
JWT: JWTConfig{
Secret: getEnv("JWT_SECRET", "your-secret-key"),
Expire: 86400, // 24小时
},
ShortVideo: ShortVideoConfig{
APIKey: getEnv("SHORT_VIDEO_API_KEY", ""),
FreeDailyQuota: getEnvAsInt("SHORT_VIDEO_FREE_QUOTA", 20),
RequestTimeout: time.Duration(getEnvAsInt("SHORT_VIDEO_TIMEOUT_SECONDS", 5)) * time.Second,
ProxyEnabled: getEnvAsBool("SHORT_VIDEO_PROXY_ENABLED", true),
ProxyAllowedDomains: getEnvAsStringSlice("SHORT_VIDEO_PROXY_ALLOWED_DOMAINS", nil),
ProxyMaxSize: int64(getEnvAsInt("SHORT_VIDEO_PROXY_MAX_SIZE_MB", 100)) * 1024 * 1024,
ProxyTimeout: time.Duration(getEnvAsInt("SHORT_VIDEO_PROXY_TIMEOUT_SECONDS", 60)) * time.Second,
},
AI: AIConfig{
BaseURL: getEnv("AI_BASE_URL", "https://api.openai.com/v1"),
APIKey: getEnv("AI_API_KEY", ""),
Model: getEnv("AI_MODEL", "gpt-4o-mini"),
RequestTimeout: time.Duration(getEnvAsInt("AI_TIMEOUT_SECONDS", 15)) * time.Second,
},
Admin: AdminConfig{
Token: getEnv("ADMIN_API_TOKEN", ""),
},
Qiniu: QiniuConfig{
AccessKey: getEnv("QINIU_ACCESS_KEY", ""),
SecretKey: getEnv("QINIU_SECRET_KEY", ""),
Bucket: getEnv("QINIU_BUCKET", ""),
UploadURL: getEnv("QINIU_UPLOAD_URL", "https://upload.qiniup.com"),
CDNDomain: getEnv("QINIU_CDN_DOMAIN", ""),
KeyPrefix: getEnv("QINIU_KEY_PREFIX", "uploads/"),
TokenExpireSeconds: getEnvAsInt("QINIU_TOKEN_EXPIRE_SECONDS", 300),
},
WeChatOA: WeChatOfficialConfig{
AppID: getEnv("WECHAT_OA_APP_ID", ""),
AppSecret: getEnv("WECHAT_OA_APP_SECRET", ""),
RequestTimeout: time.Duration(getEnvAsInt("WECHAT_OA_TIMEOUT_SECONDS", 5)) * time.Second,
},
Redis: RedisConfig{
Addr: getEnv("REDIS_ADDR", ""),
Password: getEnv("REDIS_PASSWORD", ""),
DB: getEnvAsInt("REDIS_DB", 0),
KeyPrefix: getEnv("REDIS_KEY_PREFIX", "wx_service:"),
SessionTTLSeconds: getEnvAsInt("REDIS_SESSION_TTL_SECONDS", 86400),
},
}
}
func loadAdditionalDBConfigs(defaultCfg DatabaseInstanceConfig) map[string]DatabaseInstanceConfig {
instances := strings.Split(getEnv("DB_INSTANCES", ""), ",")
result := make(map[string]DatabaseInstanceConfig)
for _, rawName := range instances {
name := strings.TrimSpace(rawName)
if name == "" {
continue
}
upperName := strings.ToUpper(name)
prefix := "DB_" + upperName + "_"
result[strings.ToLower(name)] = DatabaseInstanceConfig{
Host: getEnv(prefix+"HOST", defaultCfg.Host),
Port: getEnv(prefix+"PORT", defaultCfg.Port),
User: getEnv(prefix+"USER", defaultCfg.User),
Password: getEnv(prefix+"PASSWORD", defaultCfg.Password),
DBName: getEnv(prefix+"NAME", defaultCfg.DBName),
}
}
if len(result) == 0 {
return nil
}
return result
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func getEnvAsInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
if v, err := strconv.Atoi(value); err == nil {
return v
}
}
return defaultValue
}
func getEnvAsBool(key string, defaultValue bool) bool {
if value := os.Getenv(key); value != "" {
v := strings.ToLower(value)
return v == "true" || v == "1" || v == "yes"
}
return defaultValue
}
func getEnvAsStringSlice(key string, defaultValue []string) []string {
if value := os.Getenv(key); value != "" {
parts := strings.Split(value, ",")
result := make([]string, 0, len(parts))
for _, part := range parts {
trimmed := strings.TrimSpace(part)
if trimmed != "" {
result = append(result, trimmed)
}
}
if len(result) > 0 {
return result
}
}
return defaultValue
}