新增大量WhatsApp适配器相关代码,包括账号管理、会话处理、消息收发、验证授权、媒体处理、互动命令、审批流程、健康检测等完整功能模块,搭建基础的Baileys协议WhatsApp接入能力
70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from collections.abc import Awaitable, Callable
|
|
|
|
from yuxi.utils.logging_config import logger
|
|
|
|
|
|
class HeartbeatManager:
|
|
MAX_BACKOFF = 300.0
|
|
|
|
def __init__(self, bridge, interval: float = 30.0):
|
|
self._bridge = bridge
|
|
self._interval = interval
|
|
self._task: asyncio.Task | None = None
|
|
self._on_unhealthy: Callable[[str], Awaitable[None]] | None = None
|
|
self._consecutive_failures = 0
|
|
self._stopping = False
|
|
|
|
def on_unhealthy(self, handler: Callable[[str], Awaitable[None]]) -> None:
|
|
self._on_unhealthy = handler
|
|
|
|
async def start(self) -> None:
|
|
self._stopping = False
|
|
if self._task and not self._task.done():
|
|
return
|
|
self._task = asyncio.create_task(self._loop())
|
|
|
|
async def stop(self) -> None:
|
|
self._stopping = True
|
|
if self._task:
|
|
self._task.cancel()
|
|
try:
|
|
await self._task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
self._task = None
|
|
|
|
def _backoff_seconds(self) -> float:
|
|
if self._consecutive_failures == 0:
|
|
return self._interval
|
|
return min(self._interval * (2 ** (self._consecutive_failures - 1)), self.MAX_BACKOFF)
|
|
|
|
async def _loop(self) -> None:
|
|
while True:
|
|
try:
|
|
delay = self._backoff_seconds()
|
|
await asyncio.sleep(delay)
|
|
if self._stopping:
|
|
break
|
|
health = await self._bridge.health_check()
|
|
if health.status == "unhealthy":
|
|
self._consecutive_failures += 1
|
|
logger.warning(
|
|
f"Heartbeat detected unhealthy bridge "
|
|
f"(failures: {self._consecutive_failures}, backoff: {self._backoff_seconds():.0f}s): "
|
|
f"{health.last_error}"
|
|
)
|
|
if self._consecutive_failures >= 3 and self._on_unhealthy:
|
|
await self._on_unhealthy(health.last_error or "unknown")
|
|
else:
|
|
self._consecutive_failures = 0
|
|
except asyncio.CancelledError:
|
|
break
|
|
except Exception as e:
|
|
self._consecutive_failures += 1
|
|
logger.error(f"Heartbeat error (failures: {self._consecutive_failures}): {e}")
|
|
if self._consecutive_failures >= 3 and self._on_unhealthy:
|
|
await self._on_unhealthy(str(e))
|