From c9e3bbcd9f5c822b6dd07a6ff919699b0708975f Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Sat, 19 Oct 2024 22:13:31 +0800 Subject: [PATCH] feat: Implement complete transform & Build & Upload FakeForwardMsg --- src/core/apis/packet.ts | 68 +++++---- src/core/packet/highway/session.ts | 4 +- src/core/packet/msg/converter.ts | 131 ++++++++++++++++++ src/core/packet/msg/element.ts | 16 ++- src/core/packet/packer.ts | 15 +- src/core/packet/session.ts | 5 +- src/onebot/action/extends/UploadForwardMsg.ts | 69 --------- src/onebot/action/index.ts | 3 +- src/onebot/action/msg/SendMsg.ts | 106 ++++++++++---- src/onebot/action/types.ts | 2 +- src/onebot/api/msg.ts | 17 ++- 11 files changed, 290 insertions(+), 146 deletions(-) create mode 100644 src/core/packet/msg/converter.ts delete mode 100644 src/onebot/action/extends/UploadForwardMsg.ts diff --git a/src/core/apis/packet.ts b/src/core/apis/packet.ts index 04d1ad28..dfae3401 100644 --- a/src/core/apis/packet.ts +++ b/src/core/apis/packet.ts @@ -1,17 +1,18 @@ import * as os from 'os'; -import { InstanceContext, NapCatCore } from '..'; +import {ChatType, InstanceContext, NapCatCore} from '..'; import offset from '@/core/external/offset.json'; -import { PacketClient, RecvPacketData } from '@/core/packet/client'; -import { PacketSession } from "@/core/packet/session"; -import { PacketHexStr, PacketPacker } from "@/core/packet/packer"; -import { NapProtoMsg } from '@/core/packet/proto/NapProto'; -import { OidbSvcTrpcTcp0X9067_202_Rsp_Body } from '@/core/packet/proto/oidb/Oidb.0x9067_202'; -import { OidbSvcTrpcTcpBase, OidbSvcTrpcTcpBaseRsp } from '@/core/packet/proto/oidb/OidbBase'; -import { OidbSvcTrpcTcp0XFE1_2RSP } from '@/core/packet/proto/oidb/Oidb.0XFE1_2'; -import { LogWrapper } from "@/common/log"; -import { SendLongMsgResp } from "@/core/packet/proto/message/action"; -import { PacketMsg } from "@/core/packet/msg/message"; -import { OidbSvcTrpcTcp0x6D6Response } from "@/core/packet/proto/oidb/Oidb.0x6D6"; +import {PacketClient, RecvPacketData} from '@/core/packet/client'; +import {PacketSession} from "@/core/packet/session"; +import {PacketHexStr} from "@/core/packet/packer"; +import {NapProtoMsg} from '@/core/packet/proto/NapProto'; +import {OidbSvcTrpcTcp0X9067_202_Rsp_Body} from '@/core/packet/proto/oidb/Oidb.0x9067_202'; +import {OidbSvcTrpcTcpBase, OidbSvcTrpcTcpBaseRsp} from '@/core/packet/proto/oidb/OidbBase'; +import {OidbSvcTrpcTcp0XFE1_2RSP} from '@/core/packet/proto/oidb/Oidb.0XFE1_2'; +import {LogWrapper} from "@/common/log"; +import {SendLongMsgResp} from "@/core/packet/proto/message/action"; +import {PacketMsg} from "@/core/packet/msg/message"; +import {OidbSvcTrpcTcp0x6D6Response} from "@/core/packet/proto/oidb/Oidb.0x6D6"; +import {PacketMsgPicElement} from "@/core/packet/msg/element"; interface OffsetType { [key: string]: { @@ -28,14 +29,12 @@ export class NTQQPacketApi { logger: LogWrapper serverUrl: string | undefined; qqVersion: string | undefined; - packetPacker: PacketPacker; packetSession: PacketSession | undefined; constructor(context: InstanceContext, core: NapCatCore) { this.context = context; this.core = core; this.logger = core.context.logger; - this.packetPacker = new PacketPacker(this.logger); this.packetSession = undefined; const config = this.core.configLoader.configData; if (config && config.packetServer && config.packetServer.length > 0) { @@ -70,13 +69,13 @@ export class NTQQPacketApi { } async sendPokePacket(group: number, peer: number) { - const data = this.packetPacker.packPokePacket(group, peer); - await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data, false); + const data = this.packetSession?.packer.packPokePacket(group, peer); + await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data!, false); } async sendRkeyPacket() { - const packet = this.packetPacker.packRkeyPacket(); - const ret = await this.sendPacket('OidbSvcTrpcTcp.0x9067_202', packet, true); + const packet = this.packetSession?.packer.packRkeyPacket(); + const ret = await this.sendPacket('OidbSvcTrpcTcp.0x9067_202', packet!, true); if (!ret?.hex_data) return []; const body = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(Buffer.from(ret.hex_data, 'hex')).body; const retData = new NapProtoMsg(OidbSvcTrpcTcp0X9067_202_Rsp_Body).decode(body); @@ -86,8 +85,8 @@ export class NTQQPacketApi { async sendStatusPacket(uin: number): Promise<{ status: number; ext_status: number; } | undefined> { let status = 0; try { - const packet = this.packetPacker.packStatusPacket(uin); - const ret = await this.sendPacket('OidbSvcTrpcTcp.0xfe1_2', packet, true); + const packet = this.packetSession?.packer.packStatusPacket(uin); + const ret = await this.sendPacket('OidbSvcTrpcTcp.0xfe1_2', packet!, true); const data = Buffer.from(ret.hex_data, 'hex'); const ext = new NapProtoMsg(OidbSvcTrpcTcp0XFE1_2RSP).decode(new NapProtoMsg(OidbSvcTrpcTcpBase).decode(data).body).data.status.value; // ext & 0xff00 + ext >> 16 & 0xff @@ -103,20 +102,37 @@ export class NTQQPacketApi { } async sendSetSpecialTittlePacket(groupCode: string, uid: string, tittle: string) { - const data = this.packetPacker.packSetSpecialTittlePacket(groupCode, uid, tittle); - await this.sendPacket('OidbSvcTrpcTcp.0x8fc_2', data, true); + const data = this.packetSession?.packer.packSetSpecialTittlePacket(groupCode, uid, tittle); + await this.sendPacket('OidbSvcTrpcTcp.0x8fc_2', data!, true); + } + + private async uploadResources(msg: PacketMsg[], groupUin: number = 0){ + const reqList = [] + for (const m of msg){ + for (const e of m.msg){ + if (e instanceof PacketMsgPicElement){ + reqList.push(this.packetSession?.highwaySession.uploadImage({ + chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C, + peerUid: String(groupUin) ? String(groupUin) : this.core.selfInfo.uid + }, e)); + } + } + } + return Promise.all(reqList); } async sendUploadForwardMsg(msg: PacketMsg[], groupUin: number = 0) { - const data = this.packetPacker.packUploadForwardMsg(this.core.selfInfo.uid, msg, groupUin); - const ret = await this.sendPacket('trpc.group.long_msg_interface.MsgService.SsoSendLongMsg', data, true); + await this.uploadResources(msg, groupUin); + const data = await this.packetSession?.packer.packUploadForwardMsg(this.core.selfInfo.uid, msg, groupUin); + const ret = await this.sendPacket('trpc.group.long_msg_interface.MsgService.SsoSendLongMsg', data!, true); + this.logger.logDebug('sendUploadForwardMsg', ret); const resp = new NapProtoMsg(SendLongMsgResp).decode(Buffer.from(ret.hex_data, 'hex')); return resp.result.resId; } async sendGroupFileDownloadReq(groupUin: number, fileUUID: string) { - const data = this.packetPacker.packGroupFileDownloadReq(groupUin, fileUUID); - const ret = await this.sendPacket('OidbSvcTrpcTcp.0x6d6_2', data, true); + const data = this.packetSession?.packer.packGroupFileDownloadReq(groupUin, fileUUID); + const ret = await this.sendPacket('OidbSvcTrpcTcp.0x6d6_2', data!, true); const body = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(Buffer.from(ret.hex_data, 'hex')).body; const resp = new NapProtoMsg(OidbSvcTrpcTcp0x6D6Response).decode(body); if (resp.download.retCode !== 0){ diff --git a/src/core/packet/highway/session.ts b/src/core/packet/highway/session.ts index 32a06974..946c340a 100644 --- a/src/core/packet/highway/session.ts +++ b/src/core/packet/highway/session.ts @@ -34,16 +34,16 @@ export class PacketHighwaySession { protected packer: PacketPacker; private cachedPrepareReq: Promise | null = null; - constructor(logger: LogWrapper, client: PacketClient) { + constructor(logger: LogWrapper, client: PacketClient, packer: PacketPacker) { this.packetClient = client; this.logger = logger; - this.packer = new PacketPacker(logger); this.sig = { uin: this.packetClient.napCatCore.selfInfo.uin, sigSession: null, sessionKey: null, serverAddr: [], } + this.packer = packer; this.packetHighwayClient = new PacketHighwayClient(this.sig, this.logger); } diff --git a/src/core/packet/msg/converter.ts b/src/core/packet/msg/converter.ts new file mode 100644 index 00000000..3cd4b8b2 --- /dev/null +++ b/src/core/packet/msg/converter.ts @@ -0,0 +1,131 @@ +import { + MessageElement, + RawMessage, + SendArkElement, + SendFaceElement, + SendFileElement, + SendMarkdownElement, + SendMarketFaceElement, + SendPicElement, + SendPttElement, + SendReplyElement, + SendStructLongMsgElement, + SendTextElement, + SendVideoElement +} from "@/core"; +import { + IPacketMsgElement, + PacketMsgAtElement, + PacketMsgFaceElement, + PacketMsgFileElement, + PacketMsgLightAppElement, + PacketMsgMarkDownElement, + PacketMsgMarkFaceElement, + PacketMsgPicElement, + PacketMsgPttElement, + PacketMsgReplyElement, + PacketMsgTextElement, + PacketMsgVideoElement, + PacketMultiMsgElement +} from "@/core/packet/msg/element"; +import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message"; +import {LogWrapper} from "@/common/log"; + +type SendMessageElementMap = { + textElement: SendTextElement, + picElement: SendPicElement, + replyElement: SendReplyElement, + faceElement: SendFaceElement, + marketFaceElement: SendMarketFaceElement, + videoElement: SendVideoElement, + fileElement: SendFileElement, + pttElement: SendPttElement, + arkElement: SendArkElement, + markdownElement: SendMarkdownElement, + structLongMsgElement: SendStructLongMsgElement +}; + +type RawToPacketMsgConverters = { + [K in keyof SendMessageElementMap]: ( + element: SendMessageElementMap[K], + msg?: RawMessage, + elementWrapper?: MessageElement, + ) => IPacketMsgElement | null; +}; + +export type rawMsgWithSendMsg = { + senderUin: number; + senderUid?: string; + senderName: string; + groupId?: number; + time: number; + msg: PacketSendMsgElement[] +} + +export class PacketMsgConverter { + private logger: LogWrapper; + + constructor(logger: LogWrapper) { + this.logger = logger; + } + + rawMsgWithSendMsgToPacketMsg(msg: rawMsgWithSendMsg): PacketMsg { + return { + senderUid: msg.senderUid ?? '', + senderUin: msg.senderUin, + senderName: msg.senderName, + groupId: msg.groupId, + time: msg.time, + msg: msg.msg.map((element) => { + const key = (Object.keys(this.rawToPacketMsgConverters) as Array).find( + (k) => (element as any)[k] !== undefined // TODO: + ); + if (key) { + const elementData = (element as any)[key]; // TODO: + if (elementData) return this.rawToPacketMsgConverters[key](element as any) + } + return null; + }).filter((e) => e !== null) + } + } + + private rawToPacketMsgConverters: RawToPacketMsgConverters = { + textElement: (element: SendTextElement) => { + if (element.textElement.atType) { + return new PacketMsgAtElement(element) + } + return new PacketMsgTextElement(element) + }, + picElement: (element: SendPicElement) => { + return new PacketMsgPicElement(element) + }, + replyElement: (element: SendReplyElement) => { + return new PacketMsgReplyElement(element) + }, + faceElement: (element: SendFaceElement) => { + return new PacketMsgFaceElement(element) + }, + marketFaceElement: (element: SendMarketFaceElement) => { + return new PacketMsgMarkFaceElement(element) + }, + videoElement: (element: SendVideoElement) => { + return new PacketMsgVideoElement(element) + }, + fileElement: (element: SendFileElement) => { + return new PacketMsgFileElement(element) + }, + pttElement: (element: SendPttElement) => { + return new PacketMsgPttElement(element) + }, + arkElement: (element: SendArkElement) => { + return new PacketMsgLightAppElement(element) + }, + markdownElement: (element: SendMarkdownElement) => { + return new PacketMsgMarkDownElement(element) + }, + // TODO: check this logic, move it in arkElement? + structLongMsgElement: (element: SendStructLongMsgElement) => { + return new PacketMultiMsgElement(element) + } + } +} diff --git a/src/core/packet/msg/element.ts b/src/core/packet/msg/element.ts index 3aa9f936..797b4a7b 100644 --- a/src/core/packet/msg/element.ts +++ b/src/core/packet/msg/element.ts @@ -248,7 +248,7 @@ export class PacketMsgFaceElement extends IPacketMsgElement { } } -export class PacketMarkFaceElement extends IPacketMsgElement { +export class PacketMsgMarkFaceElement extends IPacketMsgElement { emojiName: string; emojiId: string; emojiPackageId: number; @@ -357,16 +357,15 @@ export class PacketMultiMsgElement extends IPacketMsgElement[] { + get JSON() { const id = crypto.randomUUID(); - const elementJson = { + return { app: "com.tencent.multimsg", config: { autosize: 1, @@ -388,20 +387,23 @@ export class PacketMultiMsgElement extends IPacketMsgElement msg.toPreview()).join('')}`, })), resid: this.resid, - source: "聊天记录", + source: "聊天记录", // TODO: summary: `查看${this.message.length}条转发消息`, uniseq: id, } }, prompt: "[聊天记录]", ver: "0.0.0.5", - view: "contact" + view: "contact", } + } + + buildElement(): NapProtoEncodeStructType[] { return [{ lightAppElem: { data: Buffer.concat([ Buffer.from([0x01]), - zlib.deflateSync(Buffer.from(JSON.stringify(elementJson), 'utf-8')) + zlib.deflateSync(Buffer.from(JSON.stringify(this.JSON), 'utf-8')) ]) } }] diff --git a/src/core/packet/packer.ts b/src/core/packet/packer.ts index be064aa0..55e57458 100644 --- a/src/core/packet/packer.ts +++ b/src/core/packet/packer.ts @@ -16,16 +16,22 @@ import {LogWrapper} from "@/common/log"; import {PacketMsg} from "@/core/packet/msg/message"; import {OidbSvcTrpcTcp0x6D6} from "@/core/packet/proto/oidb/Oidb.0x6D6"; import {OidbSvcTrpcTcp0XE37_1200} from "@/core/packet/proto/oidb/Oidb.0xE37_1200"; +import {PacketMsgConverter} from "@/core/packet/msg/converter"; +import {PacketClient} from "@/core/packet/client"; export type PacketHexStr = string & { readonly hexNya: unique symbol }; export class PacketPacker { - private readonly logger: LogWrapper; - private readonly packetBuilder: PacketMsgBuilder; + readonly logger: LogWrapper; + readonly client: PacketClient; + readonly packetBuilder: PacketMsgBuilder; + readonly packetConverter: PacketMsgConverter; - constructor(logger: LogWrapper) { + constructor(logger: LogWrapper, client: PacketClient) { this.logger = logger; + this.client = client; this.packetBuilder = new PacketMsgBuilder(logger); + this.packetConverter = new PacketMsgConverter(logger); } private toHexStr(byteArray: Uint8Array): PacketHexStr { @@ -96,8 +102,7 @@ export class PacketPacker { return this.toHexStr(this.packOidbPacket(0xfe1, 2, oidb_0xfe1_2)); } - packUploadForwardMsg(selfUid: string, msg: PacketMsg[], groupUin: number = 0): PacketHexStr { - // this.logger.logDebug("packUploadForwardMsg START!!!", selfUid, msg, groupUin); + async packUploadForwardMsg(selfUid: string, msg: PacketMsg[], groupUin: number = 0): Promise { const msgBody = this.packetBuilder.buildFakeMsg(selfUid, msg); const longMsgResultData = new NapProtoMsg(LongMsgResult).encode( { diff --git a/src/core/packet/session.ts b/src/core/packet/session.ts index 06cd5b7b..3b95c422 100644 --- a/src/core/packet/session.ts +++ b/src/core/packet/session.ts @@ -1,15 +1,18 @@ import { PacketClient } from "@/core/packet/client"; import { PacketHighwaySession } from "@/core/packet/highway/session"; import { LogWrapper } from "@/common/log"; +import {PacketPacker} from "@/core/packet/packer"; export class PacketSession { readonly logger: LogWrapper; readonly client: PacketClient; + readonly packer: PacketPacker; readonly highwaySession: PacketHighwaySession; constructor(logger: LogWrapper, client: PacketClient) { this.logger = logger; this.client = client; - this.highwaySession = new PacketHighwaySession(this.logger, this.client); + this.packer = new PacketPacker(this.logger, this.client); + this.highwaySession = new PacketHighwaySession(this.logger, this.client, this.packer); } } diff --git a/src/onebot/action/extends/UploadForwardMsg.ts b/src/onebot/action/extends/UploadForwardMsg.ts deleted file mode 100644 index 3fa1fcbc..00000000 --- a/src/onebot/action/extends/UploadForwardMsg.ts +++ /dev/null @@ -1,69 +0,0 @@ -import BaseAction from '../BaseAction'; -import {ActionName} from '../types'; -import {FromSchema, JSONSchema} from 'json-schema-to-ts'; -import {ChatType, SendTextElement} from "@/core"; -import {PacketMsgPicElement, PacketMsgTextElement} from "@/core/packet/msg/element"; - -const SchemaData = { - type: 'object', - properties: { - group_id: {type: ['number', 'string']}, - pic: {type: 'string'}, - }, - required: ['group_id', 'pic'], -} as const satisfies JSONSchema; - -type Payload = FromSchema; - -export class UploadForwardMsg extends BaseAction { - actionName = ActionName.UploadForwardMsg; - payloadSchema = SchemaData; - - async _handle(payload: Payload) { - if (!this.core.apis.PacketApi.available) { - throw new Error('PacketClient is not init'); - } - // throw new Error('Not implemented'); - const peer = { - chatType: ChatType.KCHATTYPEGROUP, - peerUid: "10001", // TODO: must be a valid group id - } - const img = await this.core.apis.FileApi.createValidSendPicElement( - { - deleteAfterSentFiles: [], - peer: peer - }, - "", // TODO: - "www", - 0, - ) - const sendImg = new PacketMsgPicElement(img); - console.log(JSON.stringify(img)); - await this.core.apis.PacketApi.packetSession?.highwaySession.uploadImage( - peer, sendImg - ) - return await this.core.apis.PacketApi.sendUploadForwardMsg([ - { - groupId: 10001, - senderId: 10001, - senderName: "qwq", - time: Math.floor(Date.now() / 1000), - msg: [new PacketMsgTextElement({ - textElement: { - content: "Love from Napcat.Packet~" - } - } as SendTextElement)] - }, - { - groupId: 10001, - senderId: 10001, - senderName: "qwq", - time: Math.floor(Date.now() / 1000), - msg: [new PacketMsgTextElement({ - textElement: { - content: "Nya~" - } - } as SendTextElement), sendImg] - }], 10001); // TODO: must be a valid group id - } -} diff --git a/src/onebot/action/index.ts b/src/onebot/action/index.ts index bef28bac..aa361e56 100644 --- a/src/onebot/action/index.ts +++ b/src/onebot/action/index.ts @@ -87,7 +87,6 @@ import { GroupPoke } from './group/GroupPoke'; import { GetUserStatus } from './extends/GetUserStatus'; import { GetRkey } from './extends/GetRkey'; import { SetSpecialTittle } from './extends/SetSpecialTittle'; -import { UploadForwardMsg } from "@/onebot/action/extends/UploadForwardMsg"; import { GetGroupShutList } from './group/GetGroupShutList'; import { GetGroupMemberList } from './group/GetGroupMemberList'; import { GetGroupFileUrl } from "@/onebot/action/file/GetGroupFileUrl"; @@ -193,7 +192,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo new GetUserStatus(obContext, core), new GetRkey(obContext, core), new SetSpecialTittle(obContext, core), - new UploadForwardMsg(obContext, core), + // new UploadForwardMsg(obContext, core), new GetGroupShutList(obContext, core), new GetGroupFileUrl(obContext, core), ]; diff --git a/src/onebot/action/msg/SendMsg.ts b/src/onebot/action/msg/SendMsg.ts index 34036653..0005b1a8 100644 --- a/src/onebot/action/msg/SendMsg.ts +++ b/src/onebot/action/msg/SendMsg.ts @@ -6,14 +6,18 @@ import { OB11PostContext, OB11PostSendMsg, } from '@/onebot/types'; -import { ActionName, BaseCheckResult } from '@/onebot/action/types'; -import { decodeCQCode } from '@/onebot/cqcode'; -import { MessageUnique } from '@/common/message-unique'; -import { ChatType, ElementType, NapCatCore, Peer, RawMessage, SendMessageElement } from '@/core'; +import {ActionName, BaseCheckResult} from '@/onebot/action/types'; +import {decodeCQCode} from '@/onebot/cqcode'; +import {MessageUnique} from '@/common/message-unique'; +import {ChatType, ElementType, NapCatCore, Peer, RawMessage, SendArkElement, SendMessageElement} from '@/core'; 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"; export interface ReturnDataType { message_id: number; + res_id?: string; } export enum ContextMode { @@ -26,7 +30,7 @@ export enum ContextMode { export function normalize(message: OB11MessageMixType, autoEscape = false): OB11MessageData[] { return typeof message === 'string' ? ( autoEscape ? - [{ type: OB11MessageDataType.text, data: { text: message } }] : + [{type: OB11MessageDataType.text, data: {text: message}}] : decodeCQCode(message) ) : Array.isArray(message) ? message : [message]; } @@ -96,10 +100,10 @@ export class SendMsg extends BaseAction { message: '转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素', }; } - return { valid: true }; + return {valid: true}; } - async _handle(payload: OB11PostSendMsg): Promise<{ message_id: number }> { + async _handle(payload: OB11PostSendMsg): Promise { this.contextMode = ContextMode.Normal; if (payload.message_type === 'group') this.contextMode = ContextMode.Group; if (payload.message_type === 'private') this.contextMode = ContextMode.Private; @@ -111,17 +115,19 @@ export class SendMsg extends BaseAction { ); if (getSpecialMsgNum(payload, OB11MessageDataType.node)) { - const returnMsg = await this.handleForwardedNodes(peer, messages as OB11MessageNode[]); - if (returnMsg) { + const packetMode = this.core.apis.PacketApi.available + const returnMsgAndResId = packetMode + ? await this.handleForwardedNodesPacket(peer, messages as OB11MessageNode[]) + : await this.handleForwardedNodes(peer, messages as OB11MessageNode[]); + if (returnMsgAndResId.message) { const msgShortId = MessageUnique.createUniqueMsgId({ guildId: '', peerUid: peer.peerUid, chatType: peer.chatType, - }, returnMsg!.msgId); - return { message_id: msgShortId! }; - } else { - throw Error('发送转发消息失败'); + }, (returnMsgAndResId.message)!.msgId); + return {message_id: msgShortId!, res_id: returnMsgAndResId.res_id}; } + throw Error('发送转发消息失败'); } else { // if (getSpecialMsgNum(payload, OB11MessageDataType.music)) { // const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic; @@ -131,13 +137,61 @@ export class SendMsg extends BaseAction { } // log("send msg:", peer, sendElements) - const { sendElements, deleteAfterSentFiles } = await this.obContext.apis.MsgApi + const {sendElements, deleteAfterSentFiles} = await this.obContext.apis.MsgApi .createSendElements(messages, peer); const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles); - return { message_id: returnMsg!.id! }; + return {message_id: returnMsg!.id!}; } - private async handleForwardedNodes(destPeer: Peer, messageNodes: OB11MessageNode[]): Promise { + private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{ + message: RawMessage | null, + res_id?: string + }> { + const logger = this.core.context.logger; + const packetMsg: PacketMsg[] = []; + for (const node of messageNodes) { + if ((node.data.id && typeof node.data.content !== "string") || !node.data.id) { + const OB11Data = normalize(node.data.content); + const {sendElements} = await this.obContext.apis.MsgApi.createSendElements(OB11Data, msgPeer); + const packetMsgElements: rawMsgWithSendMsg = { + senderUin: node.data.user_id ?? +this.core.selfInfo.uin, + senderName: node.data.nickname, + groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined, + time: Date.now(), + msg: sendElements, + } + logger.logDebug(`handleForwardedNodesPacket 开始转换 ${JSON.stringify(packetMsgElements)}`); + const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements); + logger.logDebug(`handleForwardedNodesPacket 转换为 ${JSON.stringify(transformedMsg)}`); + packetMsg.push(transformedMsg!); + } else { + logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${JSON.stringify(node)}`); + } + } + 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 finallySendElements = { + elementType: ElementType.ARK, + elementId: "", + arkElement: { + bytesData: JSON.stringify(forwardJson), + }, + } as SendArkElement + const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined) + return {message: returnMsg ?? null, res_id: resid}; + } + + private async handleForwardedNodes(destPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{ + message: RawMessage | null, + res_id?: string + }> { const selfPeer = { chatType: ChatType.KCHATTYPEC2C, peerUid: this.core.selfInfo.uid, @@ -147,7 +201,7 @@ export class SendMsg extends BaseAction { for (const messageNode of messageNodes) { const nodeId = messageNode.data.id; if (nodeId) { - //对Mgsid和OB11ID混用情况兜底 + // 对Msgid和OB11ID混用情况兜底 const nodeMsg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(nodeId)) || MessageUnique.getPeerByMsgId(nodeId); if (!nodeMsg) { logger.logError.bind(this.core.context.logger)('转发消息失败,未找到消息', nodeId); @@ -167,15 +221,15 @@ export class SendMsg extends BaseAction { } const nodeMsg = await this.handleForwardedNodes(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node)); if (nodeMsg) { - nodeMsgIds.push(nodeMsg.msgId); - MessageUnique.createUniqueMsgId(selfPeer, nodeMsg.msgId); + nodeMsgIds.push(nodeMsg.message!.msgId); + MessageUnique.createUniqueMsgId(selfPeer, nodeMsg.message!.msgId); } //完成子卡片生成跳过后续 continue; } - const { sendElements } = await this.obContext.apis.MsgApi + const {sendElements} = await this.obContext.apis.MsgApi .createSendElements(OB11Data, destPeer); - + //拆分消息 const MixElement = sendElements.filter( @@ -214,7 +268,7 @@ export class SendMsg extends BaseAction { continue; } const nodeMsg = (await this.core.apis.MsgApi.getMsgsByMsgId(nodeMsgPeer.Peer, [msgId])).msgList[0]; - srcPeer = srcPeer ?? { chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid }; + srcPeer = srcPeer ?? {chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid}; if (srcPeer.peerUid !== nodeMsg.peerUid) { needSendSelf = true; } @@ -237,10 +291,14 @@ export class SendMsg extends BaseAction { if (retMsgIds.length === 0) throw Error('转发消息失败,生成节点为空'); try { logger.logDebug('开发转发', srcPeer, destPeer, retMsgIds); - return await this.core.apis.MsgApi.multiForwardMsg(srcPeer!, destPeer, retMsgIds); + return { + message: await this.core.apis.MsgApi.multiForwardMsg(srcPeer!, destPeer, retMsgIds) + }; } catch (e) { logger.logError.bind(this.core.context.logger)('forward failed', e); - return null; + return { + message: null + }; } } diff --git a/src/onebot/action/types.ts b/src/onebot/action/types.ts index e1649376..aff90d0f 100644 --- a/src/onebot/action/types.ts +++ b/src/onebot/action/types.ts @@ -125,6 +125,6 @@ export enum ActionName { GetUserStatus = "nc_get_user_status", GetRkey = "nc_get_rkey", SetSpecialTittle = "set_group_special_title", - UploadForwardMsg = "upload_forward_msg", + // UploadForwardMsg = "upload_forward_msg", GetGroupShutList = "get_goup_shut_list", } diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index 94818004..e93a5a48 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -26,15 +26,15 @@ import { OB11MessageFileBase, OB11MessageForward, } from '@/onebot'; -import { OB11Entities } from '@/onebot/entities'; -import { EventType } from '@/onebot/event/OB11BaseEvent'; -import { encodeCQCode } from '@/onebot/cqcode'; -import { uri2local } from '@/common/file'; -import { RequestUtil } from '@/common/request'; +import {OB11Entities} from '@/onebot/entities'; +import {EventType} from '@/onebot/event/OB11BaseEvent'; +import {encodeCQCode} from '@/onebot/cqcode'; +import {uri2local} from '@/common/file'; +import {RequestUtil} from '@/common/request'; 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 {OB11FriendAddNoticeEvent} from '@/onebot/event/notice/OB11FriendAddNoticeEvent'; +import {decodeSysMessage} from '@/core/packet/proto/old/ProfileLike'; type RawToOb11Converters = { [Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: ( @@ -497,8 +497,7 @@ export class OneBotMsgApi { const uri2LocalRes = await uri2local(this.core.NapCatTempPath, thumb); if (uri2LocalRes.success) thumb = uri2LocalRes.path; } - const videoEle = await this.core.apis.FileApi.createValidSendVideoElement(context, path, fileName, thumb); - return videoEle; + return await this.core.apis.FileApi.createValidSendVideoElement(context, path, fileName, thumb); }, [OB11MessageDataType.voice]: async (sendMsg, context) =>