from __future__ import annotations import uuid from typing import Optional from app.clients.pywechat_client import ClientRegistry, OnlineStatus, registry from app.models.event import EventType, OutboundEvent from app.repositories.event_store import EventStore, event_store class SendService: def __init__(self, registry: ClientRegistry, store: EventStore): self.registry = registry self.store = store def send_text( self, account_id: str, conversation_id: str, text: str, record_id: str, tenant_code: str = "default", ) -> dict: client = self.registry.get(account_id) if client is None: return self._fail(account_id, record_id, tenant_code, conversation_id, f"account {account_id} not registered") if client.state.online_status != OnlineStatus.ONLINE: return self._fail(account_id, record_id, tenant_code, conversation_id, "account not online") if client.state.risk_level >= 80: return self._fail( account_id, record_id, tenant_code, conversation_id, "account risk level too high", error_code="RISK_CONTROL_BLOCKED", ) message_id = f"mock-msg-{uuid.uuid4().hex[:16]}" channel_result = client.send_text(conversation_id, text) self._emit_send_result(account_id, record_id, tenant_code, conversation_id, True, message_id, channel_result) return {"accepted": True, "message_id": message_id} def send_image( self, account_id: str, conversation_id: str, image_url: str, record_id: str, tenant_code: str = "default", ) -> dict: client = self.registry.get(account_id) if client is None: return self._fail(account_id, record_id, tenant_code, conversation_id, f"account {account_id} not registered") if client.state.online_status != OnlineStatus.ONLINE: return self._fail(account_id, record_id, tenant_code, conversation_id, "account not online") message_id = f"mock-img-{image_url.split('/')[-1]}" self._emit_send_result( account_id, record_id, tenant_code, conversation_id, True, message_id, {"image_url": image_url}, ) return {"accepted": True, "message_id": message_id} def _fail( self, account_id: str, record_id: str, tenant_code: str, conversation_id: str, error: str, error_code: str = "SEND_FAILED", ) -> dict: self._emit_send_result( account_id, record_id, tenant_code, conversation_id, False, None, {"error": error, "error_code": error_code}, ) return {"accepted": False, "error": error} def _emit_send_result( self, account_id: str, record_id: str, tenant_code: str, conversation_id: str, success: bool, message_id: Optional[str], channel_result: dict, ) -> None: event = OutboundEvent( event_type=EventType.SEND_RESULT, account_id=account_id, tenant_code=tenant_code, data={ "record_id": record_id, "conversation_id": conversation_id, "success": success, "message_id": message_id, "channel_result": channel_result, "error": channel_result.get("error"), }, ) self.store.save(event) send_service = SendService(registry, event_store)