from __future__ import annotations import time from asgiref.sync import sync_to_async from core.clients import transport from core.models import ChatSession, Message STATUS_VISIBLE_SOURCE_SERVICES = {"web", "xmpp"} def chunk_for_transport(text: str, limit: int = 3000) -> list[str]: body = str(text or "").strip() if not body: return [] if len(body) <= limit: return [body] parts = [] remaining = body while len(remaining) > limit: cut = remaining.rfind("\n\n", 0, limit) if cut < int(limit * 0.45): cut = remaining.rfind("\n", 0, limit) if cut < int(limit * 0.35): cut = limit parts.append(remaining[:cut].rstrip()) remaining = remaining[cut:].lstrip() if remaining: parts.append(remaining) return [part for part in parts if part] async def post_status_in_source(trigger_message: Message, text: str, origin_tag: str) -> bool: service = str(trigger_message.source_service or "").strip().lower() if service not in STATUS_VISIBLE_SOURCE_SERVICES: return False if service == "web": await sync_to_async(Message.objects.create)( user=trigger_message.user, session=trigger_message.session, sender_uuid="", text=text, ts=int(time.time() * 1000), custom_author="BOT", source_service="web", source_chat_id=trigger_message.source_chat_id or "", message_meta={"origin_tag": origin_tag}, ) return True # For non-web, route through transport raw API. if not str(trigger_message.source_chat_id or "").strip(): return False try: await transport.send_message_raw( service, str(trigger_message.source_chat_id or "").strip(), text=text, attachments=[], metadata={"origin_tag": origin_tag}, ) return True except Exception: return False async def post_to_channel_binding( trigger_message: Message, binding_service: str, binding_channel_identifier: str, text: str, origin_tag: str, command_slug: str, ) -> bool: service = str(binding_service or "").strip().lower() channel_identifier = str(binding_channel_identifier or "").strip() if service == "web": session = None if channel_identifier and channel_identifier == str( trigger_message.source_chat_id or "" ).strip(): session = trigger_message.session if session is None and channel_identifier: session = await sync_to_async( lambda: ChatSession.objects.filter( user=trigger_message.user, identifier__identifier=channel_identifier, ) .order_by("-last_interaction") .first() )() if session is None: session = trigger_message.session await sync_to_async(Message.objects.create)( user=trigger_message.user, session=session, sender_uuid="", text=text, ts=int(time.time() * 1000), custom_author="BOT", source_service="web", source_chat_id=channel_identifier or str(trigger_message.source_chat_id or ""), message_meta={"origin_tag": origin_tag}, ) return True try: chunks = chunk_for_transport(text, limit=3000) if not chunks: return False for chunk in chunks: ts = await transport.send_message_raw( service, channel_identifier, text=chunk, attachments=[], metadata={ "origin_tag": origin_tag, "command_slug": command_slug, }, ) if not ts: return False return True except Exception: return False