package config import ( "os" "strconv" "time" ) // Config 应用配置 type Config struct { DatabaseURL string ListenAddr string APIKey string ReturnSecret bool MaxConcurrency int MaxTestLimit int LeaseTTL time.Duration // Telegram Bot 配置 TelegramBotToken string TelegramAdminIDs []int64 TelegramNotifyChatID string TelegramTestIntervalMin int TelegramAlertThreshold int TelegramTestURL string TelegramTestTimeoutMs int } // Load 从环境变量加载配置 func Load() *Config { cfg := &Config{ DatabaseURL: getEnv("DATABASE_URL", "postgres://postgres:postgres@localhost:5432/proxyrotator?sslmode=disable"), ListenAddr: getEnv("LISTEN_ADDR", ":8080"), APIKey: getEnv("API_KEY", ""), ReturnSecret: getEnvBool("RETURN_SECRET", true), MaxConcurrency: getEnvInt("MAX_CONCURRENCY", 200), MaxTestLimit: getEnvInt("MAX_TEST_LIMIT", 2000), LeaseTTL: getEnvDuration("LEASE_TTL", 60*time.Second), // Telegram TelegramBotToken: getEnv("TELEGRAM_BOT_TOKEN", ""), TelegramAdminIDs: getEnvInt64Slice("TELEGRAM_ADMIN_IDS", nil), TelegramNotifyChatID: getEnv("TELEGRAM_NOTIFY_CHAT_ID", ""), TelegramTestIntervalMin: getEnvInt("TELEGRAM_TEST_INTERVAL_MIN", 60), TelegramAlertThreshold: getEnvInt("TELEGRAM_ALERT_THRESHOLD", 50), TelegramTestURL: getEnv("TELEGRAM_TEST_URL", "https://httpbin.org/ip"), TelegramTestTimeoutMs: getEnvInt("TELEGRAM_TEST_TIMEOUT_MS", 5000), } return cfg } func getEnv(key, defaultValue string) string { if v := os.Getenv(key); v != "" { return v } return defaultValue } func getEnvBool(key string, defaultValue bool) bool { if v := os.Getenv(key); v != "" { b, err := strconv.ParseBool(v) if err == nil { return b } } return defaultValue } func getEnvInt(key string, defaultValue int) int { if v := os.Getenv(key); v != "" { i, err := strconv.Atoi(v) if err == nil { return i } } return defaultValue } func getEnvDuration(key string, defaultValue time.Duration) time.Duration { if v := os.Getenv(key); v != "" { d, err := time.ParseDuration(v) if err == nil { return d } } return defaultValue } func getEnvInt64Slice(key string, defaultValue []int64) []int64 { v := os.Getenv(key) if v == "" { return defaultValue } parts := splitAndTrim(v, ",") result := make([]int64, 0, len(parts)) for _, p := range parts { if p == "" { continue } i, err := strconv.ParseInt(p, 10, 64) if err == nil { result = append(result, i) } } return result } func splitAndTrim(s, sep string) []string { parts := make([]string, 0) for _, p := range stringsSplit(s, sep) { p = stringsTrim(p) if p != "" { parts = append(parts, p) } } return parts } func stringsSplit(s, sep string) []string { if s == "" { return nil } result := make([]string, 0) start := 0 for i := 0; i < len(s); i++ { if i+len(sep) <= len(s) && s[i:i+len(sep)] == sep { result = append(result, s[start:i]) start = i + len(sep) i += len(sep) - 1 } } result = append(result, s[start:]) return result } func stringsTrim(s string) string { start, end := 0, len(s) for start < end && (s[start] == ' ' || s[start] == '\t') { start++ } for end > start && (s[end-1] == ' ' || s[end-1] == '\t') { end-- } return s[start:end] }