From d1fc6798dc57229d9ae7d53265c64eb76f89b243 Mon Sep 17 00:00:00 2001 From: vjrj Date: Mon, 13 Jul 2026 18:49:52 +0200 Subject: [PATCH] =?UTF-8?q?Fase=201c:=20canal=20Telegram=20(telegram-worke?= =?UTF-8?q?r)=20=E2=80=94=20codigo=20migrado,=20inerte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Envio de alertas Telegram desde el servicio (docs/legacy-telegram.md): por alerta, texto Markdown (content + firelink i18n) + ubicacion, como node-red. - types: canal 'telegram', notif.type 'telegram', campo telegramNotified - telegram/message.ts: buildTelegramMessages (firelink es/en/gl + location) - telegram/client.ts: cliente Bot API (fetch), interpretResponse (429 retry_after, 403 blocked) - telegram/rate.ts: throttle por chat (1 msg/s) + computeWaitMs puro - handlers.processTelegramJob: idempotencia (notification_sends canal telegram), modos dry-run/shadow/canary/full, throttle, 429->retry, bloqueo->sub inactiva - poller/queue/index: canal telegram integrado; worker con rate limiter global BullMQ (25/s por bot); cliente por idioma (es/gl->ES, en->EN) - config: bloque telegram (tokens es/en, server, globalPerSec, perChatMinMs) 85 tests en verde, typecheck y build OK. Sin TELEGRAM_TOKEN_* configurados el worker no se activa (todo inerte). Falta: extraer tokens de bot de flows_cred + rollout con el usuario. Los flujos conversacionales de los bots siguen en node-red. --- .env.example | 8 +++ README.md | 5 +- docs/legacy-telegram.md | 57 +++++++++++++++++ src/config.ts | 31 +++++++++ src/handlers.ts | 91 +++++++++++++++++++++++++- src/index.ts | 27 +++++++- src/poller.ts | 15 +++-- src/queue.ts | 2 + src/telegram/client.ts | 47 ++++++++++++++ src/telegram/message.ts | 35 ++++++++++ src/telegram/rate.ts | 26 ++++++++ src/types.ts | 10 ++- test/poller.test.ts | 2 +- test/telegram.test.ts | 137 ++++++++++++++++++++++++++++++++++++++++ 14 files changed, 479 insertions(+), 14 deletions(-) create mode 100644 docs/legacy-telegram.md create mode 100644 src/telegram/client.ts create mode 100644 src/telegram/message.ts create mode 100644 src/telegram/rate.ts create mode 100644 test/telegram.test.ts diff --git a/.env.example b/.env.example index bec2925..33f18b1 100644 --- a/.env.example +++ b/.env.example @@ -47,6 +47,14 @@ MATCHER_AUDIENCE=web,mobile # tipos de suscripción que generan notifs aquí (t MATCHER_POLL_MS=30000 # cada cuánto sondea activefires (Mongo 3.2, sin change streams) MATCHER_BATCH=2000 # máx fuegos por ciclo +# --- Telegram (fase 1c: envío de alertas por los bots) --- +# Añade 'telegram' a OWNED_CHANNELS y MATCHER_AUDIENCE para activarlo. +TELEGRAM_TOKEN_ES= # SECRETO: token del bot ES (extraer de flows_cred de node-red) +TELEGRAM_TOKEN_EN= # SECRETO: token del bot EN +TELEGRAM_SERVER= # host para el firelink (por defecto = host de ROOT_URL) +TELEGRAM_GLOBAL_PER_SEC=25 # límite global msg/s por bot (Telegram permite ~30) +TELEGRAM_PER_CHAT_MS=1000 # mínimo ms entre mensajes al mismo chat (~1 msg/s) + # --- Enlaces / mapas --- ROOT_URL=https://fuegos.comunes.org/ GMAPS_KEY= # Meteor.settings.gmaps.key diff --git a/README.md b/README.md index 9a1fcde..b4970cf 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,9 @@ sistema) + Redis local. En fase 3 pasa a Docker Compose. - [x] **1b**: matcher geoespacial (content i18n, geolib, `sealed` vía Iron — compatible con la web —, dedupe 500 m), ingesta por polling, modos `shadow`/`full`, comparador de shadow. Tests en verde. +- [x] **1c**: telegram-worker (texto + ubicación, firelink, rate limiting + global 25/s + 1/s por chat, 429/bloqueo, idempotencia). Tests en verde. + **Código migrado; sin tokens configurados → inerte.** - [ ] **1a full**: envío masivo FCM (~8176 users) — con el usuario, vigilando. - [ ] **1b**: rollout `shadow` ≥3 días → comparar → cutover node-red → `full`. -- [ ] **1c**: envío Telegram. +- [ ] **1c**: extraer tokens de bot → rollout `shadow`/canary → cutover node-red. diff --git a/docs/legacy-telegram.md b/docs/legacy-telegram.md new file mode 100644 index 0000000..bd09a9d --- /dev/null +++ b/docs/legacy-telegram.md @@ -0,0 +1,57 @@ +# Envío Telegram viejo (fase 1c — caracterización) + +> Fuente: `todos-contra-el-fuego/telegram-bot/flows.json` (nodos "calc distances", +> "send location", senders `telegram sender`), locales node-red. + +## Qué envía node-red por cada alerta de fuego a un chat suscrito + +**Dos mensajes** al `chatId` de la suscripción (subs `type: 'telegram'`): + +1. **Texto** (`type: "message"`, `parse_mode: "Markdown"`): + `content` + salto de línea + `firelink`. + - `content` = la misma cadena `kmnasa`/`kmvecinal` del matching + (ver `legacy-matching.md` §3; lleva `🔥` y el `км` cirílico). + - `firelink` (i18n): `[