Files
Nexus/server/infrastructure/telegram/__init__.py
T

112 lines
3.6 KiB
Python
Raw Normal View History

"""Nexus — Telegram Bot Notification Module
Sends alerts/recovery/system messages via Telegram Bot API.
"""
import logging
import httpx
from datetime import datetime, timezone
from server.config import settings
logger = logging.getLogger("nexus.telegram")
# Bot API base URL
TELEGRAM_API_BASE = "https://api.telegram.org"
2026-05-22 08:19:56 +08:00
# Reusable httpx client — avoids TCP connection churn during alert storms
_http_client: httpx.AsyncClient | None = None
async def _get_client() -> httpx.AsyncClient:
global _http_client
if _http_client is None or _http_client.is_closed:
_http_client = httpx.AsyncClient(timeout=10.0)
return _http_client
async def close_client():
"""Close the shared httpx client — call during app shutdown"""
global _http_client
if _http_client and not _http_client.is_closed:
await _http_client.aclose()
_http_client = None
async def send_telegram(message: str) -> bool:
"""Send a Telegram message via Bot API.
Returns True if sent successfully, False if skipped or failed.
Silently skips if TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID is not configured.
"""
if not settings.TELEGRAM_BOT_TOKEN or not settings.TELEGRAM_CHAT_ID:
return False # Not configured — silent skip
try:
2026-05-22 08:19:56 +08:00
client = await _get_client()
resp = await client.post(
f"{TELEGRAM_API_BASE}/bot{settings.TELEGRAM_BOT_TOKEN}/sendMessage",
json={
"chat_id": settings.TELEGRAM_CHAT_ID,
"text": message,
"parse_mode": "HTML",
},
)
if resp.status_code == 200:
logger.info(f"Telegram sent: {message[:50]}...")
return True
else:
logger.error(f"Telegram API error: {resp.status_code} {resp.text[:100]}")
return False
except Exception as e:
logger.error(f"Telegram send failed: {e}")
return False
async def send_telegram_alert(server_name: str, alert_type: str, value: float) -> bool:
"""Send server alert notification"""
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
return await send_telegram(
f"🔴 <b>告警</b>\n"
f"服务器 <b>{server_name}</b> {alert_type} 使用率 <b>{value:.1f}%</b>\n"
f"时间: {now}"
)
async def send_telegram_recovery(server_name: str, metric: str, value: float) -> bool:
"""Send server recovery notification"""
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
return await send_telegram(
f"🟢 <b>恢复</b>\n"
f"服务器 <b>{server_name}</b> {metric} 已恢复正常 ({value:.1f}%)\n"
f"时间: {now}"
)
async def send_telegram_system_alert(message: str) -> bool:
"""Send system-level alert (Python crash, Redis disconnect, etc.)"""
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
return await send_telegram(
f"⚠️ <b>系统告警</b>\n"
f"{message}\n"
f"时间: {now}"
)
async def send_telegram_restart_success() -> bool:
"""Notify that Python backend has successfully restarted"""
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
return await send_telegram(
f"🟢 <b>Nexus后端已恢复</b>\n"
f"Python服务自动重启成功\n"
f"时间: {now}"
)
async def send_telegram_restart_failed() -> bool:
"""Notify that Python backend restart failed — needs human intervention"""
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
return await send_telegram(
f"🔴 <b>Nexus后端重启失败!</b>\n"
f"请人工介入检查\n"
f"时间: {now}"
)