feat & refactor: decouple the forwardMsg construction logic and implement the OB11 element conversion for the forward node.

This commit is contained in:
pk5ls20
2024-10-21 04:05:02 +08:00
parent e7222653fa
commit 6cb7d45464
4 changed files with 130 additions and 58 deletions

View File

@@ -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(),
}))
})))
}
}

View File

@@ -28,6 +28,7 @@ import {
} from "@/core"; } from "@/core";
import {MsgInfo} from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq"; import {MsgInfo} from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq";
import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message"; import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message";
import {ForwardMsgBuilder} from "@/common/forward-msg-builder";
// raw <-> packet // raw <-> packet
// TODO: check ob11 -> raw impl! // TODO: check ob11 -> raw impl!
@@ -282,7 +283,7 @@ export class PacketMsgMarkFaceElement extends IPacketMsgElement<SendMarketFaceEl
} }
toPreview(): string { toPreview(): string {
return this.emojiName; return `[${this.emojiName}]`;
} }
} }
@@ -324,7 +325,7 @@ export class PacketMsgLightAppElement extends IPacketMsgElement<SendArkElement>
} }
toPreview(): string { toPreview(): string {
return "[小程序]"; return "[卡片消息]";
} }
} }
@@ -349,7 +350,7 @@ export class PacketMsgMarkDownElement extends IPacketMsgElement<SendMarkdownElem
} }
toPreview(): string { toPreview(): string {
return this.content; return `[Markdown消息 ${this.content}]`;
} }
} }
@@ -363,55 +364,12 @@ export class PacketMultiMsgElement extends IPacketMsgElement<SendStructLongMsgEl
this.message = message ?? []; this.message = message ?? [];
} }
get isGroupMsg(): boolean {
return this.message.some(msg => 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<typeof Elem>[] { buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
return [{ return [{
lightAppElem: { lightAppElem: {
data: Buffer.concat([ data: Buffer.concat([
Buffer.from([0x01]), 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'))
]) ])
} }
}] }]

View File

@@ -13,7 +13,7 @@ import {ChatType, ElementType, NapCatCore, Peer, RawMessage, SendArkElement, Sen
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import {rawMsgWithSendMsg} from "@/core/packet/msg/converter"; import {rawMsgWithSendMsg} from "@/core/packet/msg/converter";
import {PacketMsg} from "@/core/packet/msg/message"; import {PacketMsg} from "@/core/packet/msg/message";
import {PacketMultiMsgElement} from "@/core/packet/msg/element"; import {ForwardMsgBuilder} from "@/common/forward-msg-builder";
export interface ReturnDataType { export interface ReturnDataType {
message_id: number; message_id: number;
@@ -126,6 +126,8 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
chatType: peer.chatType, chatType: peer.chatType,
}, (returnMsgAndResId.message)!.msgId); }, (returnMsgAndResId.message)!.msgId);
return {message_id: msgShortId!, res_id: returnMsgAndResId.res_id}; 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('发送转发消息失败'); throw Error('发送转发消息失败');
} else { } else {
@@ -143,6 +145,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
return {message_id: returnMsg!.id!}; return {message_id: returnMsg!.id!};
} }
// TODO: recursively handle forwarded nodes
private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{ private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{
message: RawMessage | null, message: RawMessage | null,
res_id?: string res_id?: string
@@ -169,14 +172,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
} }
} }
const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0); const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0);
const forwardJson = new PacketMultiMsgElement({ const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg);
elementType: ElementType.STRUCTLONGMSG,
elementId: "",
structLongMsgElement: {
xmlContent: "",
resId: resid
}
}, packetMsg).JSON;
const finallySendElements = { const finallySendElements = {
elementType: ElementType.ARK, elementType: ElementType.ARK,
elementId: "", elementId: "",
@@ -184,7 +180,12 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
bytesData: JSON.stringify(forwardJson), bytesData: JSON.stringify(forwardJson),
}, },
} as SendArkElement } 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}; return {message: returnMsg ?? null, res_id: resid};
} }

View File

@@ -35,6 +35,7 @@ import fs from 'node:fs';
import fsPromise from 'node:fs/promises'; import fsPromise from 'node:fs/promises';
import {OB11FriendAddNoticeEvent} from '@/onebot/event/notice/OB11FriendAddNoticeEvent'; import {OB11FriendAddNoticeEvent} from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
import {decodeSysMessage} from '@/core/packet/proto/old/ProfileLike'; import {decodeSysMessage} from '@/core/packet/proto/old/ProfileLike';
import {ForwardMsgBuilder} from "@/common/forward-msg-builder";
type RawToOb11Converters = { type RawToOb11Converters = {
[Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: ( [Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: (
@@ -600,7 +601,13 @@ export class OneBotMsgApi {
[OB11MessageDataType.node]: async () => undefined, [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, [OB11MessageDataType.xml]: async () => undefined,