from __future__ import annotations import time from typing import Optional from app.clients.pywechat_client import ClientRegistry, LoginStatus, OnlineStatus, registry from app.models.event import EventType, OutboundEvent from app.repositories.event_store import EventStore class LoginService: def __init__(self, registry: ClientRegistry): self.registry = registry self.store: EventStore | None = None def start_login(self, account_id: str, account_name: Optional[str] = None, tenant_code: str = "default") -> dict: client = self.registry.get_or_create(account_id, account_name) login_id = client.start_login() self._emit_login_changed(account_id, tenant_code, LoginStatus.PENDING, client.state.login_status, client.state.qr_code_url) return { "login_id": login_id, "qr_code_url": client.state.qr_code_url, "status": client.state.login_status.value, } def get_status(self, account_id: str) -> dict: client = self.registry.get(account_id) if client is None: return {"found": False, "account_id": account_id} state = client.get_state() return { "found": True, "account_id": state.account_id, "account_name": state.account_name, "login_status": state.login_status.value, "online_status": state.online_status.value, "last_heartbeat_at": state.last_heartbeat_at, "risk_level": state.risk_level, "sent_count_today": state.sent_count_today, } def confirm_login(self, account_id: str, tenant_code: str = "default") -> dict: client = self.registry.get(account_id) if client is None: return {"success": False, "error": "account not found"} previous_login = client.state.login_status previous_online = client.state.online_status client.set_login_status(LoginStatus.SUCCESS) self._emit_login_changed(account_id, tenant_code, previous_login, client.state.login_status) self._emit_online_changed(account_id, tenant_code, previous_online, client.state.online_status) return {"success": True, "status": client.state.login_status.value} def expire_login(self, account_id: str, tenant_code: str = "default") -> dict: client = self.registry.get(account_id) if client is None: return {"success": False, "error": "account not found"} previous = client.state.login_status client.set_login_status(LoginStatus.EXPIRED) self._emit_login_changed(account_id, tenant_code, previous, client.state.login_status) return {"success": True, "status": client.state.login_status.value} def _emit_login_changed(self, account_id: str, tenant_code: str, previous: LoginStatus, current: LoginStatus, qr_code_url: Optional[str] = None) -> None: event = OutboundEvent( event_type=EventType.LOGIN_STATUS_CHANGED, account_id=account_id, tenant_code=tenant_code, data={ "previous": previous.value, "current": current.value, "qr_code_url": qr_code_url, }, ) if self.store is not None: self.store.save(event) def _emit_online_changed(self, account_id: str, tenant_code: str, previous: OnlineStatus, current: OnlineStatus) -> None: event = OutboundEvent( event_type=EventType.ONLINE_STATUS_CHANGED, account_id=account_id, tenant_code=tenant_code, data={ "previous": previous.value, "current": current.value, }, ) if self.store is not None: self.store.save(event) login_service = LoginService(registry) from app.repositories.event_store import event_store # noqa: E402 login_service.store = event_store