feat: Implement complete transform & Build & Upload FakeForwardMsg

This commit is contained in:
pk5ls20
2024-10-19 22:13:31 +08:00
parent 9c17dc1b8f
commit c9e3bbcd9f
11 changed files with 290 additions and 146 deletions

View File

@@ -34,16 +34,16 @@ export class PacketHighwaySession {
protected packer: PacketPacker;
private cachedPrepareReq: Promise<void> | 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);
}

View File

@@ -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<SendMessageElementMap[K]> | 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<keyof SendMessageElementMap>).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)
}
}
}

View File

@@ -248,7 +248,7 @@ export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
}
}
export class PacketMarkFaceElement extends IPacketMsgElement<SendMarketFaceElement> {
export class PacketMsgMarkFaceElement extends IPacketMsgElement<SendMarketFaceElement> {
emojiName: string;
emojiId: string;
emojiPackageId: number;
@@ -357,16 +357,15 @@ export class PacketMultiMsgElement extends IPacketMsgElement<SendStructLongMsgEl
resid: string;
message: PacketMsg[];
constructor(rawElement: SendStructLongMsgElement)
constructor(rawElement: SendStructLongMsgElement, message?: PacketMsg[]) {
super(rawElement);
this.resid = rawElement.structLongMsgElement.resId;
this.message = message ?? [];
}
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
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<SendStructLongMsgEl
text: `${packetMsg.senderName}: ${packetMsg.msg.map(msg => 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<typeof Elem>[] {
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'))
])
}
}]

View File

@@ -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<PacketHexStr> {
const msgBody = this.packetBuilder.buildFakeMsg(selfUid, msg);
const longMsgResultData = new NapProtoMsg(LongMsgResult).encode(
{

View File

@@ -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);
}
}