Files
GIA/core/commands/delivery.py

126 lines
3.9 KiB
Python

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