From 3a3eaeec7c5ca67405476ae5be07341fba9cfbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Fri, 30 Jan 2026 18:47:45 +0800 Subject: [PATCH] Add UploadForwardMsgV2 support for multi-message forwarding Introduces UploadForwardMsgV2 transformer and integrates it into the message sending flow to support forwarding multiple messages with custom action commands. Updates related interfaces and logic to handle UUIDs and nested forwarded messages, improving flexibility and extensibility for message forwarding operations. --- .../napcat-core/helper/forward-msg-builder.ts | 26 ++++++---- .../packet/context/operationContext.ts | 13 ++++- .../transformer/message/UploadForwardMsgV2.ts | 51 +++++++++++++++++++ .../packet/transformer/message/index.ts | 1 + packages/napcat-onebot/action/msg/SendMsg.ts | 25 ++++++++- 5 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 packages/napcat-core/packet/transformer/message/UploadForwardMsgV2.ts diff --git a/packages/napcat-core/helper/forward-msg-builder.ts b/packages/napcat-core/helper/forward-msg-builder.ts index 9d5ced1d..6857df8d 100644 --- a/packages/napcat-core/helper/forward-msg-builder.ts +++ b/packages/napcat-core/helper/forward-msg-builder.ts @@ -2,14 +2,14 @@ import * as crypto from 'node:crypto'; import { PacketMsg } from '@/napcat-core/packet/message/message'; interface ForwardMsgJson { - app: string + app: string; config: ForwardMsgJsonConfig, desc: string, extra: ForwardMsgJsonExtra, meta: ForwardMsgJsonMeta, prompt: string, ver: string, - view: string + view: string; } interface ForwardMsgJsonConfig { @@ -17,7 +17,7 @@ interface ForwardMsgJsonConfig { forward: number, round: number, type: string, - width: number + width: number; } interface ForwardMsgJsonExtra { @@ -26,17 +26,17 @@ interface ForwardMsgJsonExtra { } interface ForwardMsgJsonMeta { - detail: ForwardMsgJsonMetaDetail + detail: ForwardMsgJsonMetaDetail; } interface ForwardMsgJsonMetaDetail { news: { - text: string + text: string; }[], resid: string, source: string, summary: string, - uniseq: string + uniseq: string; } interface ForwardAdaptMsg { @@ -50,8 +50,8 @@ interface ForwardAdaptMsgElement { } export class ForwardMsgBuilder { - private static build (resId: string, msg: ForwardAdaptMsg[], source?: string, news?: ForwardMsgJsonMetaDetail['news'], summary?: string, prompt?: string): ForwardMsgJson { - const id = crypto.randomUUID(); + private static build (resId: string, msg: ForwardAdaptMsg[], source?: string, news?: ForwardMsgJsonMetaDetail['news'], summary?: string, prompt?: string, uuid?: string): ForwardMsgJson { + const id = uuid ?? crypto.randomUUID(); const isGroupMsg = msg.some(m => m.isGroupMsg); if (!source) { source = msg.length === 0 ? '聊天记录' : (isGroupMsg ? '群聊的聊天记录' : msg.map(m => m.senderName).filter((v, i, a) => a.indexOf(v) === i).slice(0, 4).join('和') + '的聊天记录'); @@ -104,13 +104,19 @@ export class ForwardMsgBuilder { return this.build(resId, []); } - static fromPacketMsg (resId: string, packetMsg: PacketMsg[], source?: string, news?: ForwardMsgJsonMetaDetail['news'], summary?: string, prompt?: string): ForwardMsgJson { + static fromPacketMsg (resId: string, packetMsg: PacketMsg[], source?: string, news?: ForwardMsgJsonMetaDetail['news'], summary?: string, prompt?: string, uuid?: string): ForwardMsgJson { return this.build(resId, packetMsg.map(msg => ({ senderName: msg.senderName, isGroupMsg: msg.groupId !== undefined, msg: msg.msg.map(m => ({ preview: m.valid ? m.toPreview() : '[该消息类型暂不支持查看]', })), - })), source, news, summary, prompt); + })), + source, + news, + summary, + prompt, + uuid, + ); } } diff --git a/packages/napcat-core/packet/context/operationContext.ts b/packages/napcat-core/packet/context/operationContext.ts index b1312687..df5e250a 100644 --- a/packages/napcat-core/packet/context/operationContext.ts +++ b/packages/napcat-core/packet/context/operationContext.ts @@ -18,6 +18,7 @@ import { OidbPacket } from '@/napcat-core/packet/transformer/base'; import { ImageOcrResult } from '@/napcat-core/packet/entities/ocrResult'; import { gunzipSync } from 'zlib'; import { PacketMsgConverter } from '@/napcat-core/packet/message/converter'; +import { UploadForwardMsgParams } from '@/napcat-core/packet/transformer/message/UploadForwardMsgV2'; export class PacketOperationContext { private readonly context: PacketContext; @@ -26,7 +27,7 @@ export class PacketOperationContext { this.context = context; } - async sendPacket(pkt: OidbPacket, rsp?: T): Promise { + async sendPacket (pkt: OidbPacket, rsp?: T): Promise { return await this.context.client.sendOidbPacket(pkt, rsp); } @@ -224,7 +225,15 @@ export class PacketOperationContext { const res = trans.UploadForwardMsg.parse(resp); return res.result.resId; } - + async UploadForwardMsgV2 (msg: UploadForwardMsgParams[], groupUin: number = 0) { + //await this.SendPreprocess(msg, groupUin); + // 遍历上传资源 + await Promise.allSettled(msg.map(async (item) => { return await this.SendPreprocess(item.actionMsg, groupUin); })); + const req = trans.UploadForwardMsgV2.build(this.context.napcore.basicInfo.uid, msg, groupUin); + const resp = await this.context.client.sendOidbPacket(req, true); + const res = trans.UploadForwardMsg.parse(resp); + return res.result.resId; + } async MoveGroupFile ( groupUin: number, fileUUID: string, diff --git a/packages/napcat-core/packet/transformer/message/UploadForwardMsgV2.ts b/packages/napcat-core/packet/transformer/message/UploadForwardMsgV2.ts new file mode 100644 index 00000000..72348d34 --- /dev/null +++ b/packages/napcat-core/packet/transformer/message/UploadForwardMsgV2.ts @@ -0,0 +1,51 @@ +import zlib from 'node:zlib'; +import * as proto from '@/napcat-core/packet/transformer/proto'; +import { NapProtoMsg } from 'napcat-protobuf'; +import { OidbPacket, PacketBufBuilder, PacketTransformer } from '@/napcat-core/packet/transformer/base'; +import { PacketMsg } from '@/napcat-core/packet/message/message'; + +export interface UploadForwardMsgParams { + actionCommand: string; + actionMsg: PacketMsg[]; +} +class UploadForwardMsgV2 extends PacketTransformer { + build (selfUid: string, msg: UploadForwardMsgParams[], groupUin: number = 0): OidbPacket { + const reqdata = msg.map((item) => ({ + actionCommand: item.actionCommand, + actionData: { + msgBody: this.msgBuilder.buildFakeMsg(selfUid, item.actionMsg), + } + })); + const longMsgResultData = new NapProtoMsg(proto.LongMsgResult).encode( + { + action: reqdata, + } + ); + const payload = zlib.gzipSync(Buffer.from(longMsgResultData)); + const req = new NapProtoMsg(proto.SendLongMsgReq).encode( + { + info: { + type: groupUin === 0 ? 1 : 3, + uid: { + uid: groupUin === 0 ? selfUid : groupUin.toString(), + }, + groupUin, + payload, + }, + settings: { + field1: 4, field2: 1, field3: 7, field4: 0, + }, + } + ); + return { + cmd: 'trpc.group.long_msg_interface.MsgService.SsoSendLongMsg', + data: PacketBufBuilder(req), + }; + } + + parse (data: Buffer) { + return new NapProtoMsg(proto.SendLongMsgResp).decode(data); + } +} + +export default new UploadForwardMsgV2(); diff --git a/packages/napcat-core/packet/transformer/message/index.ts b/packages/napcat-core/packet/transformer/message/index.ts index 78e757c8..d471b316 100644 --- a/packages/napcat-core/packet/transformer/message/index.ts +++ b/packages/napcat-core/packet/transformer/message/index.ts @@ -2,3 +2,4 @@ export { default as UploadForwardMsg } from './UploadForwardMsg'; export { default as FetchGroupMessage } from './FetchGroupMessage'; export { default as FetchC2CMessage } from './FetchC2CMessage'; export { default as DownloadForwardMsg } from './DownloadForwardMsg'; +export { default as UploadForwardMsgV2 } from './UploadForwardMsgV2'; \ No newline at end of file diff --git a/packages/napcat-onebot/action/msg/SendMsg.ts b/packages/napcat-onebot/action/msg/SendMsg.ts index 2eaef166..ec3aef27 100644 --- a/packages/napcat-onebot/action/msg/SendMsg.ts +++ b/packages/napcat-onebot/action/msg/SendMsg.ts @@ -17,6 +17,7 @@ import { rawMsgWithSendMsg } from 'napcat-core/packet/message/converter'; import { Static, Type } from '@sinclair/typebox'; import { MsgActionsExamples } from '@/napcat-onebot/action/msg/examples'; import { OB11MessageMixTypeSchema } from '@/napcat-onebot/types/message'; +import { UploadForwardMsgParams } from '@/napcat-core/packet/transformer/message/UploadForwardMsgV2'; export const SendMsgPayloadSchema = Type.Object({ message_type: Type.Optional(Type.Union([Type.Literal('private'), Type.Literal('group')], { description: '消息类型 (private/group)' })), @@ -211,10 +212,13 @@ export class SendMsgBase extends OneBotAction { }, dp: number = 0): Promise<{ finallySendElements: SendArkElement, res_id?: string, + uuid?: string, + packetMsg: PacketMsg[], deleteAfterSentFiles: string[], } | null> { const packetMsg: PacketMsg[] = []; const delFiles: string[] = []; + const innerMsg: Array<{ uuid: string, packetMsg: PacketMsg[]; }> = new Array(); for (const node of messageNodes) { if (dp >= 3) { this.core.context.logger.logWarn('转发消息深度超过3层,将停止解析!'); @@ -232,6 +236,10 @@ export class SendMsgBase extends OneBotAction { }, dp + 1); sendElements = uploadReturnData?.finallySendElements ? [uploadReturnData.finallySendElements] : []; delFiles.push(...(uploadReturnData?.deleteAfterSentFiles || [])); + if (uploadReturnData?.uuid) { + innerMsg.push({ uuid: uploadReturnData.uuid, packetMsg: uploadReturnData.packetMsg }); + } + } else { const sendElementsCreateReturn = await this.obContext.apis.MsgApi.createSendElements(OB11Data, msgPeer); sendElements = sendElementsCreateReturn.sendElements; @@ -273,8 +281,19 @@ export class SendMsgBase extends OneBotAction { this.core.context.logger.logWarn('handleForwardedNodesPacket 元素为空!'); return null; } - const resid = await this.core.apis.PacketApi.pkt.operation.UploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0); - const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg, source, news, summary, prompt); + const uploadMsgData: UploadForwardMsgParams[] = [{ + actionCommand: 'MultiMsg', + actionMsg: packetMsg, + }]; + innerMsg.forEach(({ uuid, packetMsg: msg }) => { + uploadMsgData.push({ + actionCommand: uuid, + actionMsg: msg, + }); + }); + const resid = await this.core.apis.PacketApi.pkt.operation.UploadForwardMsgV2(uploadMsgData, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0); + const uuid = crypto.randomUUID(); + const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg, source, news, summary, prompt, uuid); return { deleteAfterSentFiles: delFiles, finallySendElements: { @@ -285,6 +304,8 @@ export class SendMsgBase extends OneBotAction { }, } as SendArkElement, res_id: resid, + uuid: uuid, + packetMsg: packetMsg, }; }