3590df28db
New platform/telegram connector (own container, bot token only there): - go-telegram/bot long-poll loop: /start deep-links + Mini App launch button. - gRPC API pkg/proto/telegram/v1 (Telegram service): ValidateInitData, Notify (renders a localized message + deep-link button), SendToUser/SendToGameChannel (admin, wired in Stage 10). Generic methods are platform-agnostic (external_id). - Bot API base override for Telegram's test environment; Dockerfile + compose (VPN sidecar, no public ingress); README. Gateway: - initData validation relocated from the gateway into the connector; the gateway calls ValidateInitData over gRPC (GATEWAY_CONNECTOR_ADDR), drops the bot token, and deletes internal/auth. - Out-of-app push: runPushPump routes events whose recipient has no live in-app stream to connector.Notify, gated by /internal/push-target + the in-app-only flag (race-free de-dup); HasSubscribers added to the push hub. Backend: - Migration 00007 accounts.notifications_in_app_only (default true) + jetgen. - ProvisionTelegram seeds a new account's language/display name from the launch fields; IdentityExternalID reverse lookup; /internal/push-target handler. UI: - Telegram Mini App launch: detect initData, apply themeParams, authTelegram, route the deep-link start_param (g/i/f); /telegram/ guard redirects outside Telegram. Vite relative base + telegram-web-app.js. In-app-only profile toggle; share-to-Telegram link for a friend code. Vitest + Playwright coverage. Wire/docs/CI: fbs Profile/UpdateProfileRequest gain notifications_in_app_only (Go + TS); go.work uses ./platform/telegram; go-unit.yaml covers it; PLAN, ARCHITECTURE, FUNCTIONAL (+ru), UI_DESIGN, READMEs updated.
73 lines
2.6 KiB
Go
73 lines
2.6 KiB
Go
// Package config loads the Telegram connector's environment configuration.
|
|
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Config is the Telegram connector's runtime configuration, read from the
|
|
// environment. The bot token lives only in this process (ARCHITECTURE.md §12).
|
|
type Config struct {
|
|
// BotToken is the Telegram Bot API token (TELEGRAM_BOT_TOKEN, required). It
|
|
// both authenticates the Bot API client and is the HMAC secret for Mini App
|
|
// initData validation.
|
|
BotToken string
|
|
// GRPCAddr is the listen address of the connector gRPC server that gateway and
|
|
// backend call (TELEGRAM_GRPC_ADDR, default :9091).
|
|
GRPCAddr string
|
|
// MiniAppURL is the HTTPS origin of the Mini App registered with BotFather; it
|
|
// is the base of every launch button, to which a deep-link adds a startapp
|
|
// query parameter (TELEGRAM_MINIAPP_URL, required).
|
|
MiniAppURL string
|
|
// APIBaseURL overrides the Bot API host (TELEGRAM_API_BASE_URL, optional;
|
|
// default https://api.telegram.org) — used for a local mock or a self-hosted
|
|
// Bot API server.
|
|
APIBaseURL string
|
|
// TestEnv routes the Bot API client to Telegram's test environment
|
|
// (.../bot<token>/test/METHOD) (TELEGRAM_TEST_ENV=true, default false).
|
|
TestEnv bool
|
|
// GameChannelID is the chat id of the bot's game channel for SendToGameChannel
|
|
// (TELEGRAM_GAME_CHANNEL_ID, optional; 0 disables channel posts).
|
|
GameChannelID int64
|
|
// LogLevel is the zap log level (TELEGRAM_LOG_LEVEL, default info).
|
|
LogLevel string
|
|
}
|
|
|
|
// Load reads the connector configuration from the environment, applying defaults
|
|
// and validating the required fields.
|
|
func Load() (Config, error) {
|
|
cfg := Config{
|
|
BotToken: os.Getenv("TELEGRAM_BOT_TOKEN"),
|
|
GRPCAddr: envOr("TELEGRAM_GRPC_ADDR", ":9091"),
|
|
MiniAppURL: os.Getenv("TELEGRAM_MINIAPP_URL"),
|
|
APIBaseURL: os.Getenv("TELEGRAM_API_BASE_URL"),
|
|
TestEnv: os.Getenv("TELEGRAM_TEST_ENV") == "true",
|
|
LogLevel: envOr("TELEGRAM_LOG_LEVEL", "info"),
|
|
}
|
|
if cfg.BotToken == "" {
|
|
return Config{}, fmt.Errorf("config: TELEGRAM_BOT_TOKEN is required")
|
|
}
|
|
if cfg.MiniAppURL == "" {
|
|
return Config{}, fmt.Errorf("config: TELEGRAM_MINIAPP_URL is required")
|
|
}
|
|
if v := strings.TrimSpace(os.Getenv("TELEGRAM_GAME_CHANNEL_ID")); v != "" {
|
|
id, err := strconv.ParseInt(v, 10, 64)
|
|
if err != nil {
|
|
return Config{}, fmt.Errorf("config: TELEGRAM_GAME_CHANNEL_ID %q: %w", v, err)
|
|
}
|
|
cfg.GameChannelID = id
|
|
}
|
|
return cfg, nil
|
|
}
|
|
|
|
// envOr returns the environment value for key, or def when it is unset or empty.
|
|
func envOr(key, def string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|