52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
|
|
from app.clients.pywechat_client import ClientRegistry, OnlineStatus, registry
|
|
from app.models.event import EventType, OutboundEvent
|
|
from app.repositories.event_store import EventStore
|
|
|
|
|
|
class HeartbeatService:
|
|
def __init__(self, registry: ClientRegistry):
|
|
self.registry = registry
|
|
self.store: EventStore | None = None
|
|
|
|
def heartbeat(self, account_id: str, payload: dict) -> dict:
|
|
client = self.registry.get_or_create(account_id, payload.get("account_name"))
|
|
client.heartbeat()
|
|
if "risk_level" in payload:
|
|
client.state.risk_level = payload["risk_level"]
|
|
if "sent_count_today" in payload:
|
|
client.state.sent_count_today = payload["sent_count_today"]
|
|
|
|
event = OutboundEvent(
|
|
event_type=EventType.HEARTBEAT,
|
|
account_id=account_id,
|
|
tenant_code=payload.get("tenant_code", "default"),
|
|
data={
|
|
"login_status": client.state.login_status.value,
|
|
"online_status": client.state.online_status.value,
|
|
"risk_level": client.state.risk_level,
|
|
"sent_count_today": client.state.sent_count_today,
|
|
},
|
|
)
|
|
if self.store is not None:
|
|
self.store.save(event)
|
|
return {"success": True, "account_id": account_id}
|
|
|
|
def check_offline_accounts(self, timeout_seconds: int = 120) -> list[dict]:
|
|
now = time.time()
|
|
offline = []
|
|
for client in self.registry.list_all():
|
|
last = client.state.last_heartbeat_at
|
|
if client.state.online_status == OnlineStatus.ONLINE and (last is None or now - last > timeout_seconds):
|
|
client.state.online_status = OnlineStatus.OFFLINE
|
|
offline.append({"account_id": client.state.account_id, "last_heartbeat_at": last})
|
|
return offline
|
|
|
|
|
|
heartbeat_service = HeartbeatService(registry)
|
|
from app.repositories.event_store import event_store # noqa: E402
|
|
heartbeat_service.store = event_store
|