130 lines
4.0 KiB
Python
130 lines
4.0 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", "signal", "whatsapp"}
|
|
|
|
|
|
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
|