package config import ( "fmt" "os" "strconv" "strings" ) // См. официальную схему env: https://docs.rw/docs/install/subscription-page/bundled // REMNAWAVE_PANEL_URL + REMNAWAVE_API_TOKEN (+ опционально CADDY_AUTH_API_TOKEN) type Config struct { BotToken string BotDebug bool TelegramAdminID int64 RemnawaveName string RemnawavePanelURL string RemnawaveAPIToken string CaddyAuthAPIToken string RemnawaveSubscription string DatabaseURL string DefaultUserDays int TrialUserDays int DefaultExternalSquadUUID string DefaultInternalSquadUUIDs []string } func Load() (*Config, error) { token := strings.TrimSpace(os.Getenv("BOT_TOKEN")) if token == "" { return nil, fmt.Errorf("BOT_TOKEN не задан") } adminID, err := strconv.ParseInt(strings.TrimSpace(os.Getenv("TELEGRAM_ADMIN_ID")), 10, 64) if err != nil || adminID <= 0 { return nil, fmt.Errorf("TELEGRAM_ADMIN_ID не задан или неверный") } panelURL := strings.TrimRight(strings.TrimSpace(os.Getenv("REMNAWAVE_PANEL_URL")), "/") if panelURL == "" { return nil, fmt.Errorf("REMNAWAVE_PANEL_URL не задан (URL панели, см. https://docs.rw/docs/install/subscription-page/bundled)") } if !strings.HasPrefix(panelURL, "http://") && !strings.HasPrefix(panelURL, "https://") { return nil, fmt.Errorf("REMNAWAVE_PANEL_URL должен быть с http:// или https:// (как в документации Remnawave)") } apiToken := strings.TrimSpace(os.Getenv("REMNAWAVE_API_TOKEN")) if apiToken == "" { return nil, fmt.Errorf("REMNAWAVE_API_TOKEN не задан (Remnawave Settings → API Tokens)") } name := strings.TrimSpace(os.Getenv("REMNAWAVE_PANEL_NAME")) if name == "" { name = "Панель 1" } caddy := strings.TrimSpace(os.Getenv("CADDY_AUTH_API_TOKEN")) if caddy == "" { caddy = strings.TrimSpace(os.Getenv("REMNAWAVE_CADDY_TOKEN")) // устаревшее имя } subURL := strings.TrimRight(strings.TrimSpace(os.Getenv("REMNAWAVE_SUBSCRIPTION_URL")), "/") if subURL != "" && !strings.HasPrefix(subURL, "http://") && !strings.HasPrefix(subURL, "https://") { return nil, fmt.Errorf("REMNAWAVE_SUBSCRIPTION_URL должен начинаться с http:// или https://") } dbURL := strings.TrimSpace(os.Getenv("DATABASE_URL")) if dbURL == "" { return nil, fmt.Errorf("DATABASE_URL не задан") } days := 1 if v := strings.TrimSpace(os.Getenv("DEFAULT_USER_DAYS")); v != "" { if d, err := strconv.Atoi(v); err == nil && d > 0 { days = d } } trialDays := days if v := strings.TrimSpace(os.Getenv("TRIAL_USER_DAYS")); v != "" { if d, err := strconv.Atoi(v); err == nil && d > 0 { trialDays = d } } var internalSquads []string if v := strings.TrimSpace(os.Getenv("DEFAULT_INTERNAL_SQUAD_UUIDS")); v != "" { for _, part := range strings.Split(v, ",") { part = strings.TrimSpace(part) if part != "" { internalSquads = append(internalSquads, part) } } } return &Config{ BotToken: token, BotDebug: strings.EqualFold(strings.TrimSpace(os.Getenv("BOT_DEBUG")), "true"), TelegramAdminID: adminID, RemnawaveName: name, RemnawavePanelURL: panelURL, RemnawaveAPIToken: apiToken, CaddyAuthAPIToken: caddy, RemnawaveSubscription: subURL, DatabaseURL: dbURL, DefaultUserDays: days, TrialUserDays: trialDays, DefaultExternalSquadUUID: strings.TrimSpace(os.Getenv("DEFAULT_EXTERNAL_SQUAD_UUID")), DefaultInternalSquadUUIDs: internalSquads, }, nil }