File size: 2,215 Bytes
dfe11f8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /**
* Cliente de integracion con Telegram Bot API.
*
* Responsabilidades:
* - sendMessage(chatId, text) → POST a api.telegram.org/bot<TOKEN>/sendMessage.
* - formatPriceAlert(question, yesPrice, threshold) → construye mensaje HTML
* escapando entidades del input de usuario.
* - escapeHtml(text) → escapa caracteres HTML sensibles (&, <, >, ").
* - Parse_mode: HTML (permite formato basico: <b>, <i>).
* - Si falta TELEGRAM_BOT_TOKEN o chatId, sendMessage retorna silenciosamente.
* - Errores de red se capturan y loguean como warn (no bloquean el flujo).
* - Respuestas de Telegram con ok: false se loguean como warn y no lanzan excepcion.
*
* Consumido por:
* - alerts.service.js → processAll() cuando se dispara una alerta.
*
* Seguridad:
* - El token se lee de variables de entorno (nunca hardcodeado).
* - Todo texto dinamico se escapa via escapeHtml antes de inyectarse en HTML.
*/
import { httpPost } from '../utils/httpClient.js';
import { config } from '../config.js';
import { logger } from '../utils/logger.js';
export function escapeHtml(text) {
if (typeof text !== 'string') return String(text ?? '');
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
export function formatPriceAlert(question, yesPrice, threshold) {
const safeQuestion = escapeHtml(question);
const pct = (yesPrice * 100).toFixed(1);
const thr = (threshold * 100).toFixed(1);
return `<b>Price Alert</b>\n${safeQuestion}\nYES: ${pct}% ≥ threshold ${thr}%`;
}
export async function sendMessage(chatId, text) {
if (!config.TELEGRAM_BOT_TOKEN || !chatId) return;
try {
const result = await httpPost(
`https://api.telegram.org/bot${config.TELEGRAM_BOT_TOKEN}/sendMessage`,
{ chat_id: chatId, text, parse_mode: 'HTML' },
{ retries: 1, timeout: 8_000 },
);
if (result && result.ok === false) {
logger.warn(
{ chatId, description: result.description, errorCode: result.error_code },
'telegram API returned ok=false',
);
return;
}
} catch (err) {
logger.warn({ err: err.message, chatId }, 'telegram send failed');
}
}
|