From 6cb7d4546459cf4b5a68c49382bb2db9113b1756 Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Mon, 21 Oct 2024 04:05:02 +0800 Subject: [PATCH] feat & refactor: decouple the `forwardMsg` construction logic and implement the OB11 element conversion for the forward node. --- src/common/forward-msg-builder.ts | 106 ++++++++++++++++++++++++++++++ src/core/packet/msg/element.ts | 52 ++------------- src/onebot/action/msg/SendMsg.ts | 21 +++--- src/onebot/api/msg.ts | 9 ++- 4 files changed, 130 insertions(+), 58 deletions(-) create mode 100644 src/common/forward-msg-builder.ts diff --git a/src/common/forward-msg-builder.ts b/src/common/forward-msg-builder.ts new file mode 100644 index 00000000..aa165b1f --- /dev/null +++ b/src/common/forward-msg-builder.ts @@ -0,0 +1,106 @@ +import {PacketMsg} from "@/core/packet/msg/message"; +import * as crypto from "node:crypto"; + +interface ForwardMsgJson { + app: string + config: ForwardMsgJsonConfig, + desc: string, + extra: ForwardMsgJsonExtra, + meta: ForwardMsgJsonMeta, + prompt: string, + ver: string, + view: string +} + +interface ForwardMsgJsonConfig { + autosize: number, + forward: number, + round: number, + type: string, + width: number +} + +interface ForwardMsgJsonExtra { + filename: string, + tsum: number, +} + +interface ForwardMsgJsonMeta { + detail: ForwardMsgJsonMetaDetail +} + +interface ForwardMsgJsonMetaDetail { + news: { + text: string + }[], + resid: string, + source: string, + summary: string, + uniseq: string +} + +interface ForwardAdaptMsg { + senderName?: string; + isGroupMsg?: boolean; + msg?: ForwardAdaptMsgElement[]; +} + +interface ForwardAdaptMsgElement { + preview?: string; +} + +export class ForwardMsgBuilder { + private static build(resId: string, msg: ForwardAdaptMsg[]): ForwardMsgJson { + const id = crypto.randomUUID(); + const isGroupMsg = msg.some(m => m.isGroupMsg); + return { + app: "com.tencent.multimsg", + config: { + autosize: 1, + forward: 1, + round: 1, + type: "normal", + width: 300 + }, + desc: "[聊天记录]", + extra: { + filename: id, + tsum: msg.length, + }, + meta: { + detail: { + news: msg.length === 0 ? [{ + text: "Nya~ This message is send from NapCat.Packet!", + }] : msg.map(m => ({ + text: `${m.senderName}: ${m.msg?.map(msg => msg.preview).join('')}`, + })), + resid: resId, + source: isGroupMsg ? "群聊的聊天记录" : + msg.length + ? Array.from(new Set(msg.map(m => m.senderName))) + .join('和') + '的聊天记录' + : '聊天记录', + summary: `查看${msg.length}条转发消息`, + uniseq: id, + } + }, + prompt: "[聊天记录]", + ver: "0.0.0.5", + view: "contact", + } + } + + static fromResId(resId: string): ForwardMsgJson { + return this.build(resId, []) + } + + static fromPacketMsg(resId: string, packetMsg: PacketMsg[]): ForwardMsgJson { + return this.build(resId, packetMsg.map(msg => ({ + senderName: msg.senderName, + isGroupMsg: msg.groupId !== undefined, + msg: msg.msg.map(m => ({ + preview: m.toPreview(), + })) + }))) + } +} diff --git a/src/core/packet/msg/element.ts b/src/core/packet/msg/element.ts index 158b215a..32e87268 100644 --- a/src/core/packet/msg/element.ts +++ b/src/core/packet/msg/element.ts @@ -28,6 +28,7 @@ import { } from "@/core"; import {MsgInfo} from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq"; import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message"; +import {ForwardMsgBuilder} from "@/common/forward-msg-builder"; // raw <-> packet // TODO: check ob11 -> raw impl! @@ -282,7 +283,7 @@ export class PacketMsgMarkFaceElement extends IPacketMsgElement } toPreview(): string { - return "[小程序]"; + return "[卡片消息]"; } } @@ -349,7 +350,7 @@ export class PacketMsgMarkDownElement extends IPacketMsgElement msg.groupId !== undefined); - } - - get JSON() { - const id = crypto.randomUUID(); - return { - app: "com.tencent.multimsg", - config: { - autosize: 1, - forward: 1, - round: 1, - type: "normal", - width: 300 - }, - desc: "[聊天记录]", - extra: { - filename: id, - tsum: this.message.length, - }, - meta: { - detail: { - news: this.message.length === 0 ? [{ - text: "[Nya~ This message is send from NapCat.Packet!]", - }] : this.message.map(packetMsg => ({ - text: `${packetMsg.senderName}: ${packetMsg.msg.map(msg => msg.toPreview()).join('')}`, - })), - resid: this.resid, - source: this.isGroupMsg ? "群聊的聊天记录" : - this.message.length - ? Array.from(new Set(this.message.map(msg => msg.senderName))) - .join('和') + '的聊天记录' - : '聊天记录', - summary: `查看${this.message.length}条转发消息`, - uniseq: id, - } - }, - prompt: "[聊天记录]", - ver: "0.0.0.5", - view: "contact", - } - } - buildElement(): NapProtoEncodeStructType[] { return [{ lightAppElem: { data: Buffer.concat([ Buffer.from([0x01]), - zlib.deflateSync(Buffer.from(JSON.stringify(this.JSON), 'utf-8')) + zlib.deflateSync(Buffer.from(JSON.stringify(ForwardMsgBuilder.fromPacketMsg(this.resid, this.message)), 'utf-8')) ]) } }] diff --git a/src/onebot/action/msg/SendMsg.ts b/src/onebot/action/msg/SendMsg.ts index 0005b1a8..d0efa0df 100644 --- a/src/onebot/action/msg/SendMsg.ts +++ b/src/onebot/action/msg/SendMsg.ts @@ -13,7 +13,7 @@ import {ChatType, ElementType, NapCatCore, Peer, RawMessage, SendArkElement, Sen import BaseAction from '../BaseAction'; import {rawMsgWithSendMsg} from "@/core/packet/msg/converter"; import {PacketMsg} from "@/core/packet/msg/message"; -import {PacketMultiMsgElement} from "@/core/packet/msg/element"; +import {ForwardMsgBuilder} from "@/common/forward-msg-builder"; export interface ReturnDataType { message_id: number; @@ -126,6 +126,8 @@ export class SendMsg extends BaseAction { chatType: peer.chatType, }, (returnMsgAndResId.message)!.msgId); return {message_id: msgShortId!, res_id: returnMsgAndResId.res_id}; + } else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) { + throw Error(`发送转发消息(res_id:${returnMsgAndResId.res_id} 失败`); } throw Error('发送转发消息失败'); } else { @@ -143,6 +145,7 @@ export class SendMsg extends BaseAction { return {message_id: returnMsg!.id!}; } + // TODO: recursively handle forwarded nodes private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{ message: RawMessage | null, res_id?: string @@ -169,14 +172,7 @@ export class SendMsg extends BaseAction { } } const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0); - const forwardJson = new PacketMultiMsgElement({ - elementType: ElementType.STRUCTLONGMSG, - elementId: "", - structLongMsgElement: { - xmlContent: "", - resId: resid - } - }, packetMsg).JSON; + const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg); const finallySendElements = { elementType: ElementType.ARK, elementId: "", @@ -184,7 +180,12 @@ export class SendMsg extends BaseAction { bytesData: JSON.stringify(forwardJson), }, } as SendArkElement - const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined) + let returnMsg: RawMessage | undefined; + try { + returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined) + } catch (e) { + logger.logWarn("发送伪造合并转发消息失败!", e); + } return {message: returnMsg ?? null, res_id: resid}; } diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index e93a5a48..d1e2179e 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -35,6 +35,7 @@ import fs from 'node:fs'; import fsPromise from 'node:fs/promises'; import {OB11FriendAddNoticeEvent} from '@/onebot/event/notice/OB11FriendAddNoticeEvent'; import {decodeSysMessage} from '@/core/packet/proto/old/ProfileLike'; +import {ForwardMsgBuilder} from "@/common/forward-msg-builder"; type RawToOb11Converters = { [Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: ( @@ -600,7 +601,13 @@ export class OneBotMsgApi { [OB11MessageDataType.node]: async () => undefined, - [OB11MessageDataType.forward]: async () => undefined, + [OB11MessageDataType.forward]: async ({ data }, context) => { + const jsonData = ForwardMsgBuilder.fromResId(data.id) + return this.ob11ToRawConverters.json({ + data: { data: JSON.stringify(jsonData) }, + type: OB11MessageDataType.json + }, context); + }, [OB11MessageDataType.xml]: async () => undefined,