新增 Twitter 和 Viber 两个渠道扩展。 Twitter 渠道扩展功能模块: - auth: OAuth 认证管理 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - streaming: 流式消息处理 - pairing: 用户配对与绑定 - security: 安全校验 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - tweets: 推文管理 - social: 社交互动 - reactions: 表情反应 - media: 媒体资源处理 Viber 渠道扩展功能模块: - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - streaming: 流式消息处理 - pairing: 用户配对与绑定 - security: 安全校验 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - rate_limiter: 速率限制 - media: 媒体资源处理
171 lines
5.2 KiB
Python
171 lines
5.2 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import UTC, datetime
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def convert_dm_event_to_unified(event: dict, account_id: str) -> dict | None:
|
|
event_id = str(event.get("id", ""))
|
|
event_type = event.get("event_type", "")
|
|
if event_type != "MessageCreate":
|
|
return None
|
|
|
|
text = event.get("text", "")
|
|
sender_id = str(event.get("sender_id", ""))
|
|
conversation_id = str(event.get("dm_conversation_id", ""))
|
|
|
|
participant_ids = event.get("participant_ids", [])
|
|
chat_type = "direct" if len(participant_ids) <= 2 else "group"
|
|
|
|
attachments = event.get("attachments", [])
|
|
media_urls: list[str] = []
|
|
attachment_media_id = None
|
|
attachment_type = None
|
|
if attachments:
|
|
att = attachments[0]
|
|
attachment_media_id = att.get("media_key", "")
|
|
attachment_type = att.get("type", "")
|
|
if attachment_media_id:
|
|
media_urls.append(attachment_media_id)
|
|
|
|
created_at = event.get("created_at", "")
|
|
timestamp = None
|
|
if created_at:
|
|
try:
|
|
timestamp = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
|
|
except ValueError:
|
|
pass
|
|
|
|
referenced_tweets = event.get("referenced_tweets", [])
|
|
reply_to_id = None
|
|
for ref in referenced_tweets:
|
|
if ref.get("type") == "replied_to":
|
|
reply_to_id = str(ref.get("id", ""))
|
|
break
|
|
|
|
return {
|
|
"msg_id": f"tw:{event_id}",
|
|
"channel_type": "twitter",
|
|
"account_id": account_id,
|
|
"content": text,
|
|
"message_type": (
|
|
"IMAGE"
|
|
if attachment_type == "photo"
|
|
else ("VIDEO" if attachment_type == "video" else "TEXT")
|
|
),
|
|
"media_urls": media_urls,
|
|
"sender": {
|
|
"id": sender_id,
|
|
"display_name": f"twitter:{sender_id}",
|
|
"kind": "DIRECT" if chat_type == "direct" else "GROUP",
|
|
},
|
|
"group": (
|
|
{
|
|
"id": conversation_id,
|
|
"kind": chat_type,
|
|
}
|
|
if chat_type == "group"
|
|
else None
|
|
),
|
|
"timestamp": timestamp,
|
|
"reply_to_id": reply_to_id,
|
|
"thread_id": None,
|
|
"raw_payload": event,
|
|
}
|
|
|
|
|
|
def convert_group_event_to_unified(event: dict, account_id: str) -> dict | None:
|
|
event_type = event.get("event_type", "")
|
|
if event_type not in ("ParticipantsJoin", "ParticipantsLeave"):
|
|
return None
|
|
|
|
event_id = str(event.get("id", ""))
|
|
conversation_id = str(event.get("dm_conversation_id", ""))
|
|
participant_ids = [str(pid) for pid in event.get("participant_ids", [])]
|
|
|
|
action = "joined" if event_type == "ParticipantsJoin" else "left"
|
|
description = f"Users {action} the group DM"
|
|
|
|
created_at = event.get("created_at", "")
|
|
timestamp = None
|
|
if created_at:
|
|
try:
|
|
timestamp = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
|
|
except ValueError:
|
|
pass
|
|
|
|
return {
|
|
"msg_id": f"tw:{event_id}",
|
|
"channel_type": "twitter",
|
|
"account_id": account_id,
|
|
"content": description,
|
|
"message_type": "EVENT",
|
|
"media_urls": [],
|
|
"sender": {
|
|
"id": participant_ids[0] if participant_ids else "",
|
|
"display_name": f"twitter:{participant_ids[0]}" if participant_ids else "",
|
|
"kind": "GROUP",
|
|
},
|
|
"group": {"id": conversation_id, "kind": "group"},
|
|
"timestamp": timestamp,
|
|
"reply_to_id": None,
|
|
"thread_id": None,
|
|
"raw_payload": event,
|
|
"metadata": {
|
|
"event_type": event_type,
|
|
"participant_ids": participant_ids,
|
|
},
|
|
}
|
|
|
|
|
|
def convert_webhook_event_to_unified(
|
|
dm_event: dict, for_user_id: str, account_id: str
|
|
) -> dict | None:
|
|
event_type = dm_event.get("type", "")
|
|
if event_type != "message_create":
|
|
return None
|
|
|
|
event_id = str(dm_event.get("id", ""))
|
|
msg_data = dm_event.get("message_create", {})
|
|
sender_id = str(msg_data.get("sender_id", ""))
|
|
message_data = msg_data.get("message_data", {})
|
|
text = message_data.get("text", "")
|
|
|
|
attachment = message_data.get("attachment", {})
|
|
media_urls: list[str] = []
|
|
if attachment.get("type") == "media":
|
|
media = attachment.get("media", {})
|
|
media_url = media.get("media_url_https", "")
|
|
if media_url:
|
|
media_urls.append(media_url)
|
|
|
|
created_timestamp = dm_event.get("created_timestamp", "")
|
|
timestamp = None
|
|
if created_timestamp:
|
|
try:
|
|
ts = int(created_timestamp) / 1000
|
|
timestamp = datetime.fromtimestamp(ts, tz=UTC)
|
|
except (ValueError, OSError):
|
|
pass
|
|
|
|
return {
|
|
"msg_id": f"tw:{event_id}",
|
|
"channel_type": "twitter",
|
|
"account_id": account_id,
|
|
"content": text,
|
|
"message_type": "IMAGE" if media_urls else "TEXT",
|
|
"media_urls": media_urls,
|
|
"sender": {
|
|
"id": sender_id,
|
|
"display_name": f"twitter:{sender_id}",
|
|
"kind": "DIRECT",
|
|
},
|
|
"group": None,
|
|
"timestamp": timestamp,
|
|
"reply_to_id": None,
|
|
"thread_id": None,
|
|
"raw_payload": dm_event,
|
|
}
|