实现了完整的Flock渠道接入能力,包含消息收发、Webhook事件监听、账号配置、安全校验、媒体文件处理等功能,支持私聊和群组聊天,适配ForcePilot插件规范。
148 lines
4.2 KiB
Python
148 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
from yuxi.channel.message.models import (
|
|
GroupContext,
|
|
MessageType,
|
|
PeerInfo,
|
|
UnifiedMessage,
|
|
)
|
|
from yuxi.channel.routing.models import PeerKind
|
|
|
|
from .constants import PREFIX_GROUP
|
|
from .types import (
|
|
FlockChatType,
|
|
FlockEvent,
|
|
FlockEventType,
|
|
InboundFlockMessage,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def parse_event_listener(body: dict) -> FlockEvent:
|
|
name = body.get("name", "")
|
|
event_data = body.get("event", {})
|
|
chat = event_data.get("chat", "")
|
|
message = event_data.get("message", {})
|
|
|
|
return FlockEvent(
|
|
name=name,
|
|
chat=chat,
|
|
message=message,
|
|
event=event_data,
|
|
)
|
|
|
|
|
|
def parse_outgoing_webhook(body: dict) -> InboundFlockMessage:
|
|
user_id = body.get("userId", "")
|
|
channel_id = body.get("channelId", "")
|
|
text = body.get("text", "")
|
|
timestamp = int(body.get("timestamp", 0))
|
|
|
|
chat_type = FlockChatType.GROUP if channel_id.startswith(PREFIX_GROUP) else FlockChatType.DIRECT
|
|
|
|
return InboundFlockMessage(
|
|
message_id=f"outgoing_{user_id}_{timestamp}",
|
|
event_type=FlockEventType.OUTGOING_WEBHOOK,
|
|
from_user=user_id,
|
|
to=channel_id or user_id,
|
|
chat_type=chat_type,
|
|
text=text,
|
|
timestamp=timestamp,
|
|
raw_payload=body,
|
|
)
|
|
|
|
|
|
def flock_event_to_inbound(event: FlockEvent) -> InboundFlockMessage:
|
|
msg = event.message
|
|
message_id = msg.get("uid", "")
|
|
from_user = msg.get("from", "")
|
|
to = msg.get("to", "")
|
|
text = msg.get("text", "")
|
|
flockml = msg.get("flockml", "")
|
|
timestamp = int(msg.get("timestamp", 0))
|
|
thread_id = msg.get("threadId")
|
|
mentions = msg.get("mentions", [])
|
|
attachments = msg.get("attachments", [])
|
|
|
|
chat_type = FlockChatType.GROUP if to.startswith(PREFIX_GROUP) else FlockChatType.DIRECT
|
|
|
|
event_type_map = {
|
|
"chat.receiveMessage": FlockEventType.MESSAGE_RECEIVE,
|
|
"client.slashCommand": FlockEventType.SLASH_COMMAND,
|
|
"client.chatAction": FlockEventType.CHAT_ACTION,
|
|
"app.install": FlockEventType.APP_INSTALL,
|
|
"app.uninstall": FlockEventType.APP_UNINSTALL,
|
|
}
|
|
event_type = event_type_map.get(event.name, FlockEventType.MESSAGE_RECEIVE)
|
|
|
|
return InboundFlockMessage(
|
|
message_id=message_id,
|
|
event_type=event_type,
|
|
from_user=from_user,
|
|
to=to,
|
|
chat_type=chat_type,
|
|
text=text,
|
|
flockml=flockml,
|
|
timestamp=timestamp,
|
|
thread_id=thread_id,
|
|
mentions=mentions,
|
|
attachments=attachments,
|
|
raw_payload={"name": event.name, "event": event.event},
|
|
)
|
|
|
|
|
|
def inbound_to_unified(msg: InboundFlockMessage, account_id: str) -> UnifiedMessage:
|
|
from .utils import strip_flock_prefix
|
|
|
|
display_name = strip_flock_prefix(msg.from_user)
|
|
|
|
sender = PeerInfo(
|
|
kind=PeerKind.DIRECT if msg.chat_type == FlockChatType.DIRECT else PeerKind.GROUP,
|
|
id=msg.from_user,
|
|
display_name=display_name,
|
|
)
|
|
|
|
group = None
|
|
if msg.chat_type == FlockChatType.GROUP:
|
|
group = GroupContext(
|
|
id=msg.to,
|
|
thread_id=msg.thread_id,
|
|
)
|
|
|
|
bot_mentioned = False
|
|
if msg.mentions:
|
|
bot_mentioned = True
|
|
|
|
message_type = MessageType.TEXT
|
|
media_urls: list[str] = []
|
|
if msg.attachments:
|
|
message_type = MessageType.FILE
|
|
for att in msg.attachments:
|
|
if isinstance(att, dict):
|
|
src = att.get("src", "") or (att.get("views", {}).get("image", {}).get("original", {}).get("src", ""))
|
|
if src:
|
|
media_urls.append(src)
|
|
|
|
ts = datetime.fromtimestamp(msg.timestamp / 1000.0) if msg.timestamp else datetime.now()
|
|
|
|
return UnifiedMessage(
|
|
msg_id=msg.message_id,
|
|
channel_type="flock",
|
|
account_id=account_id,
|
|
content=msg.text,
|
|
sender=sender,
|
|
message_type=message_type,
|
|
media_urls=media_urls,
|
|
group=group,
|
|
timestamp=ts,
|
|
raw_payload=msg.raw_payload,
|
|
message_thread_id=msg.thread_id,
|
|
was_mentioned=len(msg.mentions) > 0,
|
|
explicitly_mentioned_bot=bot_mentioned,
|
|
mentioned_user_ids=list(msg.mentions),
|
|
)
|