96 lines
3.7 KiB
Python
96 lines
3.7 KiB
Python
"""Telegram Notification Provider — 接線 TelegramGateway 到 NotificationManager
|
||
|
||
2026-04-25 修復 L2:系統執行反饋完全丟失
|
||
根本原因:執行完成後的推送通知未配置任何 provider,Telegram 曾有 Gateway 實作
|
||
但從未註冊為 NotificationProvider,導致執行失敗的卡片無法推送回 Telegram
|
||
|
||
本模組:直接複用既有 TelegramGateway.send_alert_notification(),將執行結果格式化並推送
|
||
"""
|
||
|
||
from src.core.config import settings
|
||
from src.core.logging import get_logger
|
||
from .base import (
|
||
ExecutionStatus,
|
||
NotificationMessage,
|
||
NotificationProvider,
|
||
NotificationResult,
|
||
NotificationStatus,
|
||
)
|
||
|
||
logger = get_logger("awoooi.notifications.telegram")
|
||
|
||
|
||
class TelegramWebhookProvider(NotificationProvider):
|
||
"""透過既有 TelegramGateway 發送執行結果卡片"""
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "telegram"
|
||
|
||
@property
|
||
def enabled(self) -> bool:
|
||
"""檢查 Telegram bot token 與 AwoooI SRE 戰情室是否配置。"""
|
||
return bool(settings.OPENCLAW_TG_BOT_TOKEN) and bool(settings.SRE_GROUP_CHAT_ID)
|
||
|
||
def _format(self, msg: NotificationMessage) -> str:
|
||
"""格式化執行結果為 Telegram 訊息"""
|
||
title = f"{msg.status_emoji} <b>{msg.status_text}</b>"
|
||
lines = [
|
||
title,
|
||
"━━━━━━━━━━━━━━━━━━━",
|
||
f"🎯 <code>{msg.action_title[:120]}</code>",
|
||
f"🧭 Namespace: <code>{msg.namespace}</code> | Op: <code>{msg.operation_type}</code>",
|
||
f"{msg.risk_emoji} 風險: {msg.risk_level.upper()} | Pods: {msg.affected_pods}",
|
||
f"📝 Approval: <code>{msg.approval_id[:12]}</code>",
|
||
]
|
||
if msg.duration_ms is not None:
|
||
lines.append(f"⏱️ 耗時: {msg.duration_ms}ms")
|
||
if msg.error_message:
|
||
lines.append(f"❗ 錯誤: <code>{msg.error_message[:200]}</code>")
|
||
if msg.signers:
|
||
lines.append(f"👥 簽核: {msg.signers_display}")
|
||
return "\n".join(lines)
|
||
|
||
async def send(self, message: NotificationMessage) -> NotificationResult:
|
||
"""推送執行結果到 Telegram"""
|
||
if not self.enabled:
|
||
return NotificationResult(
|
||
status=NotificationStatus.SKIPPED,
|
||
provider=self.name,
|
||
message="Telegram bot token or chat_id not configured",
|
||
)
|
||
try:
|
||
from src.services.telegram_gateway import get_telegram_gateway
|
||
|
||
gateway = get_telegram_gateway()
|
||
text = self._format(message)
|
||
resp = await gateway.send_alert_notification(text=text, parse_mode="HTML")
|
||
return NotificationResult(
|
||
status=NotificationStatus.SUCCESS,
|
||
provider=self.name,
|
||
message="Telegram notification sent",
|
||
response_data=resp if isinstance(resp, dict) else None,
|
||
)
|
||
except Exception as e:
|
||
logger.exception("telegram_notification_exception", error=str(e))
|
||
return NotificationResult(
|
||
status=NotificationStatus.FAILED,
|
||
provider=self.name,
|
||
message="Exception during send",
|
||
error=str(e)[:300],
|
||
)
|
||
|
||
async def test_connection(self) -> bool:
|
||
"""測試 Telegram 連接"""
|
||
if not self.enabled:
|
||
return False
|
||
try:
|
||
from src.services.telegram_gateway import get_telegram_gateway
|
||
|
||
gw = get_telegram_gateway()
|
||
await gw.send_alert_notification(text="🔔 AWOOOI Telegram provider 連線測試")
|
||
return True
|
||
except Exception as e:
|
||
logger.error("telegram_connection_test_failed", error=str(e))
|
||
return False
|