mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-06 13:05:09 +00:00
feat: partly impl UploadForwardMsg
This commit is contained in:
61
src/core/helper/packet/msg/builder.ts
Normal file
61
src/core/helper/packet/msg/builder.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import {PushMsgBody} from "@/core/proto/message/message";
|
||||
import {NapProtoEncodeStructType} from "@/core/proto/NapProto";
|
||||
import {SendMessageElement} from "@/core";
|
||||
import * as crypto from "crypto";
|
||||
import {IPacketMsgElement} from "@/core/helper/packet/msg/element";
|
||||
|
||||
export interface PacketForwardNode {
|
||||
groupId?: number
|
||||
senderId: number
|
||||
senderName: string
|
||||
time: number
|
||||
msg: IPacketMsgElement<SendMessageElement>[]
|
||||
}
|
||||
|
||||
export class PacketMsgBuilder {
|
||||
buildFakeMsg(selfUid: string, element: PacketForwardNode[]): NapProtoEncodeStructType<typeof PushMsgBody>[] {
|
||||
return element.map((node): NapProtoEncodeStructType<typeof PushMsgBody> => {
|
||||
const avatar = `https://q.qlogo.cn/headimg_dl?dst_uin=${node.senderId}&spec=640&img_type=jpg`
|
||||
return {
|
||||
responseHead: {
|
||||
fromUid: "",
|
||||
fromUin: node.senderId,
|
||||
toUid: node.groupId ? undefined : selfUid,
|
||||
forward: node.groupId ? undefined : {
|
||||
friendName: node.senderName,
|
||||
},
|
||||
grp: node.groupId ? {
|
||||
groupUin: node.groupId,
|
||||
memberName: node.senderName,
|
||||
unknown5: 2
|
||||
} : undefined,
|
||||
},
|
||||
contentHead: {
|
||||
type: node.groupId ? 82 : 9,
|
||||
subType: node.groupId ? undefined : 4,
|
||||
divSeq: node.groupId ? undefined : 4,
|
||||
msgId: crypto.randomBytes(4).readUInt32LE(0),
|
||||
sequence: crypto.randomBytes(4).readUInt32LE(0),
|
||||
timeStamp: Math.floor(Date.now() / 1000),
|
||||
field7: BigInt(1),
|
||||
field8: 0,
|
||||
field9: 0,
|
||||
forward: {
|
||||
field1: 0,
|
||||
field2: 0,
|
||||
field3: node.groupId ? 0 : 2,
|
||||
unknownBase64: avatar,
|
||||
avatar: avatar
|
||||
}
|
||||
},
|
||||
body: {
|
||||
richText: {
|
||||
elems: node.msg.map(
|
||||
(msg) => msg.buildElement() ?? []
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
117
src/core/helper/packet/msg/element.ts
Normal file
117
src/core/helper/packet/msg/element.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import {NapProtoEncodeStructType, NapProtoMsg} from "@/core/proto/NapProto";
|
||||
import {Elem, MentionExtra} from "@/core/proto/message/element";
|
||||
import {
|
||||
AtType,
|
||||
SendArkElement,
|
||||
SendFaceElement,
|
||||
SendFileElement,
|
||||
SendMessageElement,
|
||||
SendPicElement,
|
||||
SendPttElement,
|
||||
SendReplyElement,
|
||||
SendTextElement,
|
||||
SendVideoElement
|
||||
} from "@/core";
|
||||
|
||||
// raw <-> packet
|
||||
// TODO: check ob11 -> raw impl!
|
||||
// TODO: parse to raw element
|
||||
export abstract class IPacketMsgElement<T extends SendMessageElement> {
|
||||
protected constructor(rawElement: T) {
|
||||
}
|
||||
|
||||
buildContent(): Uint8Array | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem> | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgTextElement extends IPacketMsgElement<SendTextElement> {
|
||||
text: string;
|
||||
|
||||
constructor(element: SendTextElement) {
|
||||
super(element);
|
||||
console.log(JSON.stringify(element));
|
||||
this.text = element.textElement.content;
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem> {
|
||||
return {
|
||||
text: {
|
||||
str: this.text
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgAtElement extends PacketMsgTextElement {
|
||||
targetUid: string;
|
||||
atAll: boolean;
|
||||
|
||||
constructor(element: SendTextElement) {
|
||||
super(element);
|
||||
this.targetUid = element.textElement.atNtUid;
|
||||
this.atAll = element.textElement.atType === AtType.atAll
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem> {
|
||||
const res = new NapProtoMsg(MentionExtra).encode({
|
||||
type: this.atAll ? 1 : 2,
|
||||
uin: 0,
|
||||
field5: 0,
|
||||
uid: this.targetUid,
|
||||
}
|
||||
)
|
||||
return {
|
||||
text: {
|
||||
str: this.text,
|
||||
pbReserve: res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgPttElement extends IPacketMsgElement<SendPttElement> {
|
||||
constructor(element: SendPttElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgPicElement extends IPacketMsgElement<SendPicElement> {
|
||||
constructor(element: SendPicElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
||||
constructor(element: SendReplyElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
|
||||
constructor(element: SendFaceElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgFileElement extends IPacketMsgElement<SendFileElement> {
|
||||
constructor(element: SendFileElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgVideoElement extends IPacketMsgElement<SendVideoElement> {
|
||||
constructor(element: SendVideoElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketMsgLightAppElement extends IPacketMsgElement<SendArkElement> {
|
||||
constructor(element: SendArkElement) {
|
||||
super(element);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,22 @@
|
||||
import * as zlib from "node:zlib";
|
||||
import { NapProtoMsg } from "@/core/proto/NapProto";
|
||||
import { OidbSvcTrpcTcpBase } from "@/core/proto/oidb/OidbBase";
|
||||
import { OidbSvcTrpcTcp0X9067_202 } from "@/core/proto/oidb/Oidb.0x9067_202";
|
||||
import { OidbSvcTrpcTcp0X8FC_2, OidbSvcTrpcTcp0X8FC_2_Body } from "@/core/proto/oidb/Oidb.0x8FC_2";
|
||||
import { OidbSvcTrpcTcp0XFE1_2 } from "@/core/proto/oidb/Oidb.fe1_2";
|
||||
import { OidbSvcTrpcTcp0XED3_1 } from "@/core/proto/oidb/Oidb.ed3_1";
|
||||
import {LongMsgResult, SendLongMsgReq} from "@/core/proto/message/action";
|
||||
import {PacketForwardNode, PacketMsgBuilder} from "@/core/helper/packet/msg/builder";
|
||||
|
||||
export type PacketHexStr = string & { readonly hexNya: unique symbol };
|
||||
|
||||
export class PacketPacker {
|
||||
private packetBuilder: PacketMsgBuilder
|
||||
|
||||
constructor() {
|
||||
this.packetBuilder = new PacketMsgBuilder();
|
||||
}
|
||||
|
||||
private toHexStr(byteArray: Uint8Array): PacketHexStr {
|
||||
return Buffer.from(byteArray).toString('hex') as PacketHexStr;
|
||||
}
|
||||
@@ -75,4 +84,39 @@ export class PacketPacker {
|
||||
});
|
||||
return this.toHexStr(this.packOidbPacket(0xfe1, 2, oidb_0xfe1_2));
|
||||
}
|
||||
|
||||
packUploadForwardMsg(selfUid: string, msg: PacketForwardNode[], groupUin: number = 0) : PacketHexStr {
|
||||
// console.log("packUploadForwardMsg START!!!", selfUid, msg, groupUin);
|
||||
const msgBody = this.packetBuilder.buildFakeMsg(selfUid, msg);
|
||||
const longMsgResultData = new NapProtoMsg(LongMsgResult).encode(
|
||||
{
|
||||
action: {
|
||||
actionCommand: "MultiMsg",
|
||||
actionData: {
|
||||
msgBody: msgBody
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// console.log("packUploadForwardMsg LONGMSGRESULT!!!", this.toHexStr(longMsgResultData));
|
||||
const payload = zlib.gzipSync(Buffer.from(longMsgResultData));
|
||||
// console.log("packUploadForwardMsg PAYLOAD!!!", payload);
|
||||
const req = new NapProtoMsg(SendLongMsgReq).encode(
|
||||
{
|
||||
info: {
|
||||
type: groupUin === 0 ? 1 : 3,
|
||||
uid: {
|
||||
uid: groupUin === 0 ? selfUid : groupUin.toString(),
|
||||
},
|
||||
groupUin: groupUin,
|
||||
payload: payload
|
||||
},
|
||||
settings: {
|
||||
field1: 4, field2: 1, field3: 7, field4: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
// console.log("packUploadForwardMsg REQ!!!", req);
|
||||
return this.toHexStr(req);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user