ForcePilot/backend/package/yuxi/channels/adapters/whatsapp/monitor.py
Kris e9b57546ea feat(whatsapp): 新增WhatsApp适配器完整功能模块
新增大量WhatsApp适配器相关代码,包括账号管理、会话处理、消息收发、验证授权、媒体处理、互动命令、审批流程、健康检测等完整功能模块,搭建基础的Baileys协议WhatsApp接入能力
2026-05-12 00:51:58 +08:00

71 lines
2.4 KiB
Python

from __future__ import annotations
import asyncio
import json
from collections.abc import Callable
from typing import Any
import aiohttp
from yuxi.utils.logging_config import logger
class WhatsAppMonitor:
def __init__(self, config: dict[str, Any] | None = None, bridge=None):
self._config = config or {}
self._bridge = bridge
self._on_raw: Callable[[dict[str, Any]], None] | None = None
self._task: asyncio.Task | None = None
def on_raw_message(self, handler: Callable[[dict[str, Any]], None]) -> None:
self._on_raw = handler
async def start(self) -> None:
if self._task and not self._task.done():
return
self._task = asyncio.create_task(self._sse_loop())
async def stop(self) -> None:
if self._task:
self._task.cancel()
try:
await self._task
except asyncio.CancelledError:
pass
self._task = None
async def _sse_loop(self) -> None:
while True:
try:
await self._connect_sse()
except asyncio.CancelledError:
break
except Exception as e:
logger.error(f"WhatsApp monitor error, reconnecting in 5s: {e}")
await asyncio.sleep(5)
async def _connect_sse(self) -> None:
url = f"{self._bridge.base_url}/api/events"
logger.info(f"Connecting to WhatsApp SSE: {url}")
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
byte_lines = []
async for chunk in resp.content.iter_any():
if chunk:
byte_lines.append(chunk)
raw_line = b"".join(byte_lines).decode("utf-8", errors="replace")
while "\n" in raw_line:
line, raw_line = raw_line.split("\n", 1)
byte_lines = [raw_line.encode("utf-8")]
if line.startswith("data: "):
data_str = line[6:].strip()
try:
data = json.loads(data_str)
if self._on_raw:
self._on_raw(data)
except json.JSONDecodeError:
continue