From e4a533e7b709fac65ea9fe658ab206d7b89dde37 Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Fri, 18 Oct 2024 04:35:23 +0800 Subject: [PATCH] feat: add more msgElement --- src/core/entities/msg.ts | 3 +- src/core/packet/highway/session.ts | 2 +- src/core/packet/msg/builder.ts | 3 +- src/core/packet/msg/element.ts | 231 +++++++++++++++++++---- src/core/packet/proto/message/element.ts | 23 ++- 5 files changed, 211 insertions(+), 51 deletions(-) diff --git a/src/core/entities/msg.ts b/src/core/entities/msg.ts index 03760e6f..d23d4a04 100644 --- a/src/core/entities/msg.ts +++ b/src/core/entities/msg.ts @@ -372,6 +372,7 @@ export interface ReplyElement { senderUin: string; senderUidStr?: string; replyMsgTime?: string; + replyMsgClientSeq?: string; } export interface SendReplyElement { @@ -391,7 +392,7 @@ export interface SendMarketFaceElement { marketFaceElement: MarketFaceElement; } -export interface SendstructLongMsgElement { +export interface SendStructLongMsgElement { elementType: ElementType.STRUCTLONGMSG; elementId: string; structLongMsgElement: StructLongMsgElement; diff --git a/src/core/packet/highway/session.ts b/src/core/packet/highway/session.ts index 3d8a0f4b..32a06974 100644 --- a/src/core/packet/highway/session.ts +++ b/src/core/packet/highway/session.ts @@ -127,7 +127,7 @@ export class PacketHighwaySession { extend ); } else { - this.logger.logError(`[Highway] get upload invalid ukey ${ukey}, don't need upload!`); + this.logger.logDebug(`[Highway] get upload invalid ukey ${ukey}, don't need upload!`); } img.msgInfo = preRespData.upload.msgInfo; // img.groupPicExt = new NapProtoMsg(CustomFace).decode(preRespData.tcpUpload.compatQMsg) diff --git a/src/core/packet/msg/builder.ts b/src/core/packet/msg/builder.ts index aa52b6a2..a3aff4f8 100644 --- a/src/core/packet/msg/builder.ts +++ b/src/core/packet/msg/builder.ts @@ -14,8 +14,7 @@ export class PacketMsgBuilder { buildFakeMsg(selfUid: string, element: PacketForwardNode[]): NapProtoEncodeStructType[] { return element.map((node): NapProtoEncodeStructType => { const avatar = `https://q.qlogo.cn/headimg_dl?dst_uin=${node.senderId}&spec=640&img_type=jpg`; - const msgElement = node.msg.map((msg) => msg.buildElement() ?? []); - // this.logger.logDebug(`NOW MSG ELEMENT: ${JSON.stringify(msgElement)}`); + const msgElement = node.msg.flatMap(msg => msg.buildElement() ?? []); return { responseHead: { fromUid: "", diff --git a/src/core/packet/msg/element.ts b/src/core/packet/msg/element.ts index d8bcbdba..f5dae1cf 100644 --- a/src/core/packet/msg/element.ts +++ b/src/core/packet/msg/element.ts @@ -1,16 +1,27 @@ import assert from "node:assert"; +import * as zlib from "node:zlib"; import {NapProtoEncodeStructType, NapProtoMsg} from "@/core/packet/proto/NapProto"; -import {CustomFace, Elem, MentionExtra, NotOnlineImage} from "@/core/packet/proto/message/element"; +import { + CustomFace, + Elem, + MarkdownData, + MentionExtra, + NotOnlineImage, + QBigFaceExtra, + QSmallFaceExtra +} from "@/core/packet/proto/message/element"; import { AtType, PicType, SendArkElement, SendFaceElement, SendFileElement, + SendMarkdownElement, SendMessageElement, SendPicElement, SendPttElement, SendReplyElement, + SendStructLongMsgElement, SendTextElement, SendVideoElement } from "@/core"; @@ -19,7 +30,8 @@ import {MsgInfo} from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq"; // raw <-> packet // TODO: check ob11 -> raw impl! // TODO: parse to raw element -export abstract class IPacketMsgElement { +// TODO: SendStructLongMsgElement +export abstract class IPacketMsgElement { protected constructor(rawElement: T) { } @@ -27,7 +39,7 @@ export abstract class IPacketMsgElement { return undefined; } - buildElement(): NapProtoEncodeStructType | undefined { + buildElement(): NapProtoEncodeStructType[] | undefined { return undefined; } } @@ -40,12 +52,12 @@ export class PacketMsgTextElement extends IPacketMsgElement { this.text = element.textElement.content; } - buildElement(): NapProtoEncodeStructType { - return { + buildElement(): NapProtoEncodeStructType[] { + return [{ text: { str: this.text } - }; + }]; } } @@ -59,20 +71,19 @@ export class PacketMsgAtElement extends PacketMsgTextElement { this.atAll = element.textElement.atType === AtType.atAll; } - buildElement(): NapProtoEncodeStructType { - const res = new NapProtoMsg(MentionExtra).encode({ - type: this.atAll ? 1 : 2, - uin: 0, - field5: 0, - uid: this.targetUid, - } - ); - return { + buildElement(): NapProtoEncodeStructType[] { + return [{ text: { str: this.text, - pbReserve: res + pbReserve: new NapProtoMsg(MentionExtra).encode({ + type: this.atAll ? 1 : 2, + uin: 0, + field5: 0, + uid: this.targetUid, + } + ) } - }; + }]; } } @@ -100,15 +111,112 @@ export class PacketMsgPicElement extends IPacketMsgElement { this.picType = element.picElement.picType; } - buildElement(): NapProtoEncodeStructType { + buildElement(): NapProtoEncodeStructType[] { assert(this.msgInfo !== null, 'msgInfo is null, expected not null'); - return { + return [{ commonElem: { serviceType: 48, pbElem: new NapProtoMsg(MsgInfo).encode(this.msgInfo), businessType: 10, } - } as NapProtoEncodeStructType + }] + } +} + +export class PacketMsgReplyElement extends IPacketMsgElement { + messageId: bigint; + messageSeq: number; + messageClientSeq: number; + targetUin: number; + targetUid: string; + time: number; + + constructor(element: SendReplyElement) { + super(element); + this.messageId = BigInt(element.replyElement.replayMsgId ?? 0); + this.messageSeq = Number(element.replyElement.replayMsgSeq ?? 0); + this.messageClientSeq = Number(element.replyElement.replyMsgClientSeq ?? 0); + this.targetUin = Number(element.replyElement.senderUin ?? 0); + this.targetUid = element.replyElement.senderUidStr ?? ''; + this.time = Number(element.replyElement.replyMsgTime ?? 0); + } + + get isGroupReply(): boolean { + return this.messageClientSeq !== 0; + } + + buildElement(): NapProtoEncodeStructType[] { + return [{ + srcMsg: { + origSeqs: [this.isGroupReply ? this.messageClientSeq : this.messageSeq], + senderUin: BigInt(this.targetUin), + time: this.time, + elems: [], // TODO: in replyElement.sourceMsgTextElems + pbReserve: { + messageId: this.messageId, + }, + toUin: BigInt(0), + } + }, { + text: this.isGroupReply ? { + str: 'nya~', + pbReserve: new NapProtoMsg(MentionExtra).encode({ + type: this.targetUin === 0 ? 1 : 2, + uin: 0, + field5: 0, + uid: String(this.targetUid), + }), + } : undefined, + }] + } +} + +export class PacketMsgFaceElement extends IPacketMsgElement { + faceId: number; + isLargeFace: boolean; + + constructor(element: SendFaceElement) { + super(element); + this.faceId = element.faceElement.faceIndex; + this.isLargeFace = element.faceElement.faceType === 3; + } + + buildElement(): NapProtoEncodeStructType[] { + if (this.isLargeFace) { + return [{ + commonElem: { + serviceType: 37, + pbElem: new NapProtoMsg(QBigFaceExtra).encode({ + aniStickerPackId: "1", + aniStickerId: "8", + faceId: this.faceId, + field4: 1, + field6: "", + preview: "", + field9: 1 + }), + businessType: 1 + } + }] + } else if (this.faceId < 260) { + return [{ + face: { + index: this.faceId + } + }]; + } else { + return [{ + commonElem: { + serviceType: 33, + pbElem: new NapProtoMsg(QSmallFaceExtra).encode({ + faceId: this.faceId, + preview: "", + preview2: "" + }), + businessType: 1 + } + }] + } } } @@ -118,33 +226,74 @@ export class PacketMsgPttElement extends IPacketMsgElement { } } - -export class PacketMsgReplyElement extends IPacketMsgElement { - constructor(element: SendReplyElement) { - super(element); - } -} - -export class PacketMsgFaceElement extends IPacketMsgElement { - constructor(element: SendFaceElement) { - super(element); - } -} - -export class PacketMsgFileElement extends IPacketMsgElement { - constructor(element: SendFileElement) { - super(element); - } -} - export class PacketMsgVideoElement extends IPacketMsgElement { constructor(element: SendVideoElement) { super(element); } } -export class PacketMsgLightAppElement extends IPacketMsgElement { - constructor(element: SendArkElement) { +export class PacketMsgFileElement extends IPacketMsgElement { + constructor(element: SendFileElement) { super(element); } } + +export class PacketMsgLightAppElement extends IPacketMsgElement { + payload: string; + + constructor(element: SendArkElement) { + super(element); + this.payload = element.arkElement.bytesData; + } + + buildElement(): NapProtoEncodeStructType[] { + return [{ + lightAppElem: { + data: Buffer.concat([ + Buffer.from([0x01]), + zlib.deflateSync(Buffer.from(this.payload, 'utf-8')) + ]) + } + }] + } +} + +// TODO: +// export class PacketMsgMarkDownElement extends IPacketMsgElement { +// content: string; +// +// constructor(element: SendMarkdownElement) { +// super(element); +// this.content = element.markdownElement.content; +// } +// +// buildElement(): NapProtoEncodeStructType[] { +// return [{ +// commonElem: { +// serviceType: 45, +// pbElem: new NapProtoMsg(MarkdownData).encode({ +// content: this.content +// }), +// businessType: 1 +// } +// }] +// } +// } +// +// export class PacketMsgLongMsgElement extends IPacketMsgElement { +// resid: string; +// +// constructor(element: SendStructLongMsgElement) { +// super(element); +// this.resid = element.structLongMsgElement.resId; +// } +// +// buildElement(): NapProtoEncodeStructType[] { +// return [{ +// generalFlags: { +// longTextResId: this.resid, +// longTextFlag: 1 +// } +// }] +// } +// } diff --git a/src/core/packet/proto/message/element.ts b/src/core/packet/proto/message/element.ts index 799b2747..4aaa3d1c 100644 --- a/src/core/packet/proto/message/element.ts +++ b/src/core/packet/proto/message/element.ts @@ -300,12 +300,19 @@ export const SrcMsg = { elems: ProtoField(5, () => Elem, false, true), type: ProtoField(6, ScalarType.INT32, true), richMsg: ProtoField(7, ScalarType.BYTES, true), - pbReserve: ProtoField(8, ScalarType.BYTES, true), + pbReserve: ProtoField(8, () => SrcMsgPbRes, true), sourceMsg: ProtoField(9, ScalarType.BYTES, true), toUin: ProtoField(10, ScalarType.UINT64, true), troopName: ProtoField(11, ScalarType.BYTES, true), }; +export const SrcMsgPbRes = { + messageId: ProtoField(3, ScalarType.UINT64), + senderUid: ProtoField(6, ScalarType.STRING, true), + receiverUid: ProtoField(7, ScalarType.STRING, true), + friendSeq: ProtoField(8, ScalarType.UINT32, true), +} + export const LightAppElem = { data: ProtoField(1, ScalarType.BYTES), msgResid: ProtoField(2, ScalarType.BYTES, true), @@ -328,12 +335,12 @@ export const MentionExtra = { uid: ProtoField(9, ScalarType.STRING, true), }; -export const QFaceExtra = { - field1: ProtoField(1, ScalarType.STRING, true), - field2: ProtoField(2, ScalarType.STRING, true), +export const QBigFaceExtra = { + AniStickerPackId: ProtoField(1, ScalarType.STRING, true), + AniStickerId: ProtoField(2, ScalarType.STRING, true), faceId: ProtoField(3, ScalarType.INT32, true), - field4: ProtoField(4, ScalarType.INT32, true), - field5: ProtoField(5, ScalarType.INT32, true), + Field4: ProtoField(4, ScalarType.INT32, true), + AniStickerType: ProtoField(5, ScalarType.INT32, true), field6: ProtoField(6, ScalarType.STRING, true), preview: ProtoField(7, ScalarType.STRING, true), field9: ProtoField(9, ScalarType.INT32, true), @@ -344,3 +351,7 @@ export const QSmallFaceExtra = { preview: ProtoField(2, ScalarType.STRING), preview2: ProtoField(3, ScalarType.STRING), }; + +export const MarkdownData = { + content: ProtoField(1, ScalarType.STRING) +}