mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-21 09:36:35 +00:00
feat: build & upload file
This commit is contained in:
parent
5cca8457e7
commit
9f8f938c47
@ -12,7 +12,12 @@ 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, PacketMsgPttElement, PacketMsgVideoElement } from "@/core/packet/msg/element";
|
||||
import {
|
||||
PacketMsgFileElement,
|
||||
PacketMsgPicElement,
|
||||
PacketMsgPttElement,
|
||||
PacketMsgVideoElement
|
||||
} from "@/core/packet/msg/element";
|
||||
|
||||
|
||||
interface OffsetType {
|
||||
@ -134,6 +139,12 @@ export class NTQQPacketApi {
|
||||
peerUid: groupUin ? String(groupUin) : this.core.selfInfo.uid
|
||||
}, e));
|
||||
}
|
||||
if (e instanceof PacketMsgFileElement){
|
||||
reqList.push(this.packetSession?.highwaySession.uploadFile({
|
||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
||||
peerUid: groupUin ? String(groupUin) : this.core.selfInfo.uid
|
||||
}, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.all(reqList); // TODO: use promise.allSettled
|
||||
|
@ -8,10 +8,17 @@ import { HttpConn0x6ff_501Response } from "@/core/packet/proto/action/action";
|
||||
import { PacketHighwayClient } from "@/core/packet/highway/client";
|
||||
import { NTV2RichMediaResp } from "@/core/packet/proto/oidb/common/Ntv2.RichMediaResp";
|
||||
import { OidbSvcTrpcTcpBaseRsp } from "@/core/packet/proto/oidb/OidbBase";
|
||||
import { PacketMsgPicElement, PacketMsgPttElement, PacketMsgVideoElement } from "@/core/packet/msg/element";
|
||||
import { NTV2RichMediaHighwayExt } from "@/core/packet/proto/highway/highway";
|
||||
import {
|
||||
PacketMsgFileElement,
|
||||
PacketMsgPicElement,
|
||||
PacketMsgPttElement,
|
||||
PacketMsgVideoElement
|
||||
} from "@/core/packet/msg/element";
|
||||
import { FileUploadExt, NTV2RichMediaHighwayExt } from "@/core/packet/proto/highway/highway";
|
||||
import { int32ip2str, oidbIpv4s2HighwayIpv4s } from "@/core/packet/highway/utils";
|
||||
import { calculateSha1StreamBytes } from "@/core/packet/utils/crypto/hash";
|
||||
import { calculateSha1, calculateSha1StreamBytes, computeMd5AndLengthWithLimit } from "@/core/packet/utils/crypto/hash";
|
||||
import { OidbSvcTrpcTcp0x6D6Response } from "@/core/packet/proto/oidb/Oidb.0x6D6";
|
||||
import { OidbSvcTrpcTcp0XE37_800Response, OidbSvcTrpcTcp0XE37Response } from "@/core/packet/proto/oidb/Oidb.0XE37_800";
|
||||
|
||||
export const BlockSize = 1024 * 1024;
|
||||
|
||||
@ -22,6 +29,7 @@ interface HighwayServerAddr {
|
||||
|
||||
export interface PacketHighwaySig {
|
||||
uin: string;
|
||||
uid: string;
|
||||
sigSession: Uint8Array | null
|
||||
sessionKey: Uint8Array | null
|
||||
serverAddr: HighwayServerAddr[]
|
||||
@ -40,6 +48,7 @@ export class PacketHighwaySession {
|
||||
this.logger = logger;
|
||||
this.sig = {
|
||||
uin: this.packetClient.napCatCore.selfInfo.uin,
|
||||
uid: this.packetClient.napCatCore.selfInfo.uid,
|
||||
sigSession: null,
|
||||
sessionKey: null,
|
||||
serverAddr: [],
|
||||
@ -117,6 +126,17 @@ export class PacketHighwaySession {
|
||||
}
|
||||
}
|
||||
|
||||
async uploadFile(peer: Peer, file: PacketMsgFileElement): Promise<void> {
|
||||
await this.checkAvailable();
|
||||
if (peer.chatType === ChatType.KCHATTYPEGROUP) {
|
||||
await this.uploadGroupFileReq(Number(peer.peerUid), file);
|
||||
} else if (peer.chatType === ChatType.KCHATTYPEC2C) {
|
||||
await this.uploadC2CFileReq(peer.peerUid, file);
|
||||
} else {
|
||||
throw new Error(`[Highway] unsupported chatType: ${peer.chatType}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async uploadGroupImageReq(groupUin: number, img: PacketMsgPicElement): Promise<void> {
|
||||
const preReq = await this.packer.packUploadGroupImgReq(groupUin, img);
|
||||
const preRespRaw = await this.packetClient.sendPacket('OidbSvcTrpcTcp.0x11c4_100', preReq, true);
|
||||
@ -400,4 +420,142 @@ export class PacketHighwaySession {
|
||||
}
|
||||
ptt.msgInfo = preRespData.upload.msgInfo;
|
||||
}
|
||||
|
||||
private async uploadGroupFileReq(groupUin: number, file: PacketMsgFileElement): Promise<void> {
|
||||
file.isGroupFile = true;
|
||||
file.fileMd5 = await computeMd5AndLengthWithLimit(file.filePath);
|
||||
file.fileSha1 = await calculateSha1(file.filePath);
|
||||
const preReq = await this.packer.packUploadGroupFileReq(groupUin, file);
|
||||
const preRespRaw = await this.packetClient.sendPacket('OidbSvcTrpcTcp.0x6d6_0', preReq, true);
|
||||
const preResp = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(
|
||||
Buffer.from(preRespRaw.hex_data, 'hex')
|
||||
);
|
||||
const preRespData = new NapProtoMsg(OidbSvcTrpcTcp0x6D6Response).decode(preResp.body);
|
||||
if (!preRespData?.upload?.boolFileExist) {
|
||||
this.logger.logDebug(`[Highway] uploadGroupFileReq file not exist, need upload!`);
|
||||
const ext = new NapProtoMsg(FileUploadExt).encode({
|
||||
unknown1: 100,
|
||||
unknown2: 1,
|
||||
entry: {
|
||||
busiBuff: {
|
||||
senderUin: BigInt(this.sig.uin),
|
||||
receiverUin: BigInt(groupUin),
|
||||
groupCode: BigInt(groupUin),
|
||||
},
|
||||
fileEntry: {
|
||||
fileSize: BigInt(file.fileSize),
|
||||
md5: file.fileMd5,
|
||||
md5S2: file.fileMd5,
|
||||
checkKey: preRespData.upload.checkKey,
|
||||
fileId: preRespData.upload.fileId,
|
||||
uploadKey: preRespData.upload.fileKey,
|
||||
},
|
||||
clientInfo: {
|
||||
clientType: 3,
|
||||
appId: "100",
|
||||
terminalType: 3,
|
||||
clientVer: "1.1.1",
|
||||
unknown: 4
|
||||
},
|
||||
fileNameInfo: {
|
||||
fileName: file.fileName
|
||||
},
|
||||
host: {
|
||||
hosts: [
|
||||
{
|
||||
url: {
|
||||
host: preRespData.upload.uploadIp,
|
||||
unknown: 1,
|
||||
},
|
||||
port: preRespData.upload.uploadPort,
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
unknown200: 0,
|
||||
})
|
||||
await this.packetHighwayClient.upload(
|
||||
71,
|
||||
fs.createReadStream(file.filePath, {highWaterMark: BlockSize}),
|
||||
file.fileSize,
|
||||
file.fileMd5,
|
||||
ext
|
||||
);
|
||||
} else {
|
||||
this.logger.logDebug(`[Highway] uploadGroupFileReq file exist, don't need upload!`);
|
||||
}
|
||||
file.fileUuid = preRespData.upload.fileId;
|
||||
}
|
||||
|
||||
private async uploadC2CFileReq(peerUid: string, file: PacketMsgFileElement): Promise<void> {
|
||||
file.isGroupFile = false;
|
||||
file.fileMd5 = await computeMd5AndLengthWithLimit(file.filePath);
|
||||
file.fileSha1 = await calculateSha1(file.filePath);
|
||||
const preReq = await this.packer.packUploadC2CFileReq(this.sig.uid, peerUid, file);
|
||||
const preRespRaw = await this.packetClient.sendPacket('OidbSvcTrpcTcp.0xe37_1700', preReq, true);
|
||||
const preResp = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(
|
||||
Buffer.from(preRespRaw.hex_data, 'hex')
|
||||
);
|
||||
console.log("OidbSvcTrpcTcp.0xe37_1700", preRespRaw);
|
||||
const preRespData = new NapProtoMsg(OidbSvcTrpcTcp0XE37Response).decode(preResp.body);
|
||||
if (!preRespData.upload?.boolFileExist) {
|
||||
this.logger.logDebug(`[Highway] uploadC2CFileReq file not exist, need upload!`);
|
||||
const ext = new NapProtoMsg(FileUploadExt).encode({
|
||||
unknown1: 100,
|
||||
unknown2: 1,
|
||||
entry: {
|
||||
busiBuff: {
|
||||
senderUin: BigInt(this.sig.uin),
|
||||
},
|
||||
fileEntry: {
|
||||
fileSize: BigInt(file.fileSize),
|
||||
md5: file.fileMd5,
|
||||
md5S2: file.fileMd5,
|
||||
checkKey: file.fileSha1,
|
||||
fileId: preRespData.upload?.uuid,
|
||||
uploadKey: preRespData.upload?.mediaPlatformUploadKey,
|
||||
},
|
||||
clientInfo: {
|
||||
clientType: 3,
|
||||
appId: "100",
|
||||
terminalType: 3,
|
||||
clientVer: "1.1.1",
|
||||
unknown: 4
|
||||
},
|
||||
fileNameInfo: {
|
||||
fileName: file.fileName
|
||||
},
|
||||
host: {
|
||||
hosts: [
|
||||
{
|
||||
url: {
|
||||
host: preRespData.upload?.uploadIp,
|
||||
unknown: 1,
|
||||
},
|
||||
port: preRespData.upload?.uploadPort,
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
unknown200: 1,
|
||||
unknown3: 0
|
||||
})
|
||||
await this.packetHighwayClient.upload(
|
||||
95,
|
||||
fs.createReadStream(file.filePath, {highWaterMark: BlockSize}),
|
||||
file.fileSize,
|
||||
file.fileMd5,
|
||||
ext
|
||||
);
|
||||
}
|
||||
file.fileUuid = preRespData.upload?.uuid;
|
||||
file.fileHash = preRespData.upload?.fileAddon;
|
||||
const FetchExistFileReq = this.packer.packOfflineFileDownloadReq(file.fileUuid!, file.fileHash!, this.sig.uid, peerUid);
|
||||
const resp = await this.packetClient.sendPacket('OidbSvcTrpcTcp.0xe37_800', FetchExistFileReq, true);
|
||||
console.log("OidbSvcTrpcTcp.0xe37_800", resp);
|
||||
const oidb_resp = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(Buffer.from(resp.hex_data, 'hex'));
|
||||
file._e37_800_rsp = new NapProtoMsg(OidbSvcTrpcTcp0XE37_800Response).decode(oidb_resp.body);
|
||||
file._private_send_uid = this.sig.uid;
|
||||
file._private_recv_uid = peerUid;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import * as crypto from "crypto";
|
||||
import { PushMsgBody } from "@/core/packet/proto/message/message";
|
||||
import { NapProtoEncodeStructType } from "@/core/packet/proto/NapProto";
|
||||
import { LogWrapper } from "@/common/log";
|
||||
import { PacketMsg } from "@/core/packet/msg/message";
|
||||
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message";
|
||||
import { IPacketMsgElement } from "@/core/packet/msg/element";
|
||||
|
||||
export class PacketMsgBuilder {
|
||||
private logger: LogWrapper;
|
||||
@ -14,6 +15,9 @@ export class PacketMsgBuilder {
|
||||
buildFakeMsg(selfUid: string, element: PacketMsg[]): NapProtoEncodeStructType<typeof PushMsgBody>[] {
|
||||
return element.map((node): NapProtoEncodeStructType<typeof PushMsgBody> => {
|
||||
const avatar = `https://q.qlogo.cn/headimg_dl?dst_uin=${node.senderUin}&spec=640&img_type=jpg`;
|
||||
const msgContent = node.msg.reduceRight((acc: undefined | Uint8Array, msg: IPacketMsgElement<PacketSendMsgElement>) => {
|
||||
return acc !== undefined ? acc : msg.buildContent();
|
||||
}, undefined);
|
||||
const msgElement = node.msg.flatMap(msg => msg.buildElement() ?? []);
|
||||
return {
|
||||
responseHead: {
|
||||
@ -50,7 +54,8 @@ export class PacketMsgBuilder {
|
||||
body: {
|
||||
richText: {
|
||||
elems: msgElement
|
||||
}
|
||||
},
|
||||
msgContent: msgContent,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -28,6 +28,8 @@ import {
|
||||
import {MsgInfo} from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq";
|
||||
import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message";
|
||||
import {ForwardMsgBuilder} from "@/common/forward-msg-builder";
|
||||
import { FileExtra, GroupFileExtra } from "@/core/packet/proto/message/component";
|
||||
import { OidbSvcTrpcTcp0XE37_800Response } from "@/core/packet/proto/oidb/Oidb.0XE37_800";
|
||||
|
||||
// raw <-> packet
|
||||
// TODO: SendStructLongMsgElement
|
||||
@ -39,8 +41,8 @@ export abstract class IPacketMsgElement<T extends PacketSendMsgElement> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] | undefined {
|
||||
return undefined;
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
toPreview(): string {
|
||||
@ -351,8 +353,85 @@ export class PacketMsgPttElement extends IPacketMsgElement<SendPttElement> {
|
||||
}
|
||||
|
||||
export class PacketMsgFileElement extends IPacketMsgElement<SendFileElement> {
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
fileSize: number;
|
||||
fileSha1?: Uint8Array;
|
||||
fileMd5?: Uint8Array;
|
||||
fileUuid?: string;
|
||||
fileHash?: string;
|
||||
isGroupFile?: boolean;
|
||||
_private_send_uid?: string;
|
||||
_private_recv_uid?: string;
|
||||
_e37_800_rsp?: NapProtoEncodeStructType<typeof OidbSvcTrpcTcp0XE37_800Response>
|
||||
|
||||
constructor(element: SendFileElement) {
|
||||
super(element);
|
||||
this.fileName = element.fileElement.fileName;
|
||||
this.filePath = element.fileElement.filePath;
|
||||
this.fileSize = +element.fileElement.fileSize;
|
||||
}
|
||||
|
||||
buildContent(): Uint8Array | undefined {
|
||||
if (this.isGroupFile) return undefined;
|
||||
return new NapProtoMsg(FileExtra).encode({
|
||||
file: {
|
||||
fileType: 0,
|
||||
fileUuid: this.fileUuid,
|
||||
fileMd5: this.fileMd5,
|
||||
fileName: this.fileName,
|
||||
fileSize: BigInt(this.fileSize),
|
||||
subcmd: 1,
|
||||
dangerEvel: 0,
|
||||
expireTime: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60,
|
||||
fileHash: this.fileHash,
|
||||
},
|
||||
field6: {
|
||||
field2: {
|
||||
field1: this._e37_800_rsp?.body?.field30?.field110,
|
||||
fileUuid: this.fileUuid,
|
||||
fileName: this.fileName,
|
||||
field6: this._e37_800_rsp?.body?.field30?.field3,
|
||||
field7: this._e37_800_rsp?.body?.field30?.field101,
|
||||
field8: this._e37_800_rsp?.body?.field30?.field100,
|
||||
timestamp1: this._e37_800_rsp?.body?.field30?.timestamp1,
|
||||
fileHash: this.fileHash,
|
||||
selfUid: this._private_send_uid,
|
||||
destUid: this._private_recv_uid,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
||||
if (!this.isGroupFile) return [];
|
||||
const lb = Buffer.alloc(2);
|
||||
const transElemVal = new NapProtoMsg(GroupFileExtra).encode({
|
||||
field1: 6,
|
||||
fileName: this.fileName,
|
||||
inner: {
|
||||
info: {
|
||||
busId: 102,
|
||||
fileId: this.fileUuid,
|
||||
fileSize: BigInt(this.fileSize),
|
||||
fileName: this.fileName,
|
||||
fileSha: this.fileSha1,
|
||||
extInfoString: "",
|
||||
fileMd5: this.fileMd5,
|
||||
}
|
||||
}
|
||||
})
|
||||
lb.writeUInt16BE(transElemVal.length);
|
||||
return [{
|
||||
transElem: {
|
||||
elemType: 24,
|
||||
elemValue: Buffer.concat([Buffer.from([0x01]), lb, transElemVal]) // TLV
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
toPreview(): string {
|
||||
return `[文件]${this.fileName}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as zlib from "node:zlib";
|
||||
import * as crypto from "node:crypto";
|
||||
import { calculateSha1 } from "@/core/packet/utils/crypto/hash";
|
||||
import { calculateSha1, computeMd5AndLengthWithLimit } from "@/core/packet/utils/crypto/hash";
|
||||
import { NapProtoMsg } from "@/core/packet/proto/NapProto";
|
||||
import { OidbSvcTrpcTcpBase } from "@/core/packet/proto/oidb/OidbBase";
|
||||
import { OidbSvcTrpcTcp0X9067_202 } from "@/core/packet/proto/oidb/Oidb.0x9067_202";
|
||||
@ -11,13 +11,20 @@ import { NTV2RichMediaReq } from "@/core/packet/proto/oidb/common/Ntv2.RichMedia
|
||||
import { HttpConn0x6ff_501 } from "@/core/packet/proto/action/action";
|
||||
import { LongMsgResult, SendLongMsgReq } from "@/core/packet/proto/message/action";
|
||||
import { PacketMsgBuilder } from "@/core/packet/msg/builder";
|
||||
import { PacketMsgPicElement, PacketMsgPttElement, PacketMsgVideoElement } from "@/core/packet/msg/element";
|
||||
import {
|
||||
PacketMsgFileElement,
|
||||
PacketMsgPicElement,
|
||||
PacketMsgPttElement,
|
||||
PacketMsgVideoElement
|
||||
} from "@/core/packet/msg/element";
|
||||
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";
|
||||
import { OidbSvcTrpcTcp0XE37_1700 } from "@/core/packet/proto/oidb/Oidb.0xE37_1700";
|
||||
import { OidbSvcTrpcTcp0XE37_800 } from "@/core/packet/proto/oidb/Oidb.0XE37_800";
|
||||
|
||||
export type PacketHexStr = string & { readonly hexNya: unique symbol };
|
||||
|
||||
@ -596,6 +603,65 @@ export class PacketPacker {
|
||||
return this.toHexStr(this.packOidbPacket(0x126D, 100, req, true, false));
|
||||
}
|
||||
|
||||
async packUploadGroupFileReq(groupUin: number, file: PacketMsgFileElement): Promise<PacketHexStr> {
|
||||
const body = new NapProtoMsg(OidbSvcTrpcTcp0x6D6).encode({
|
||||
file: {
|
||||
groupUin: groupUin,
|
||||
appId: 4,
|
||||
busId: 102,
|
||||
entrance: 6,
|
||||
targetDirectory: '/', // TODO:
|
||||
fileName: file.fileName,
|
||||
localDirectory: `/${file.fileName}`,
|
||||
fileSize: BigInt(file.fileSize),
|
||||
fileMd5: file.fileMd5,
|
||||
fileSha1: await calculateSha1(file.filePath),
|
||||
fileSha3: Buffer.alloc(0),
|
||||
field15: true
|
||||
}
|
||||
});
|
||||
return this.toHexStr(this.packOidbPacket(0x6D6, 0, body, true, false));
|
||||
}
|
||||
|
||||
async packUploadC2CFileReq(selfUid: string, peerUid: string, file: PacketMsgFileElement): Promise<PacketHexStr> {
|
||||
const body = new NapProtoMsg(OidbSvcTrpcTcp0XE37_1700).encode({
|
||||
command: 1700,
|
||||
seq: 0,
|
||||
upload: {
|
||||
senderUid: selfUid,
|
||||
receiverUid: peerUid,
|
||||
fileSize: file.fileSize,
|
||||
fileName: file.fileName,
|
||||
md510MCheckSum: await computeMd5AndLengthWithLimit(file.filePath, 10*1024*1024),
|
||||
sha1CheckSum: file.fileSha1,
|
||||
localPath: "/",
|
||||
md5CheckSum: file.fileMd5,
|
||||
sha3CheckSum: Buffer.alloc(0)
|
||||
},
|
||||
businessId: 3,
|
||||
clientType: 1,
|
||||
flagSupportMediaPlatform: 1
|
||||
})
|
||||
return this.toHexStr(this.packOidbPacket(0xE37, 1700, body, false, false));
|
||||
}
|
||||
|
||||
packOfflineFileDownloadReq(fileUUID: string, fileHash: string, senderUid: string, receiverUid: string): PacketHexStr {
|
||||
const req = this.packOidbPacket(0xE37, 800, new NapProtoMsg(OidbSvcTrpcTcp0XE37_800).encode({
|
||||
subCommand: 800,
|
||||
field2: 0,
|
||||
body: {
|
||||
senderUid: senderUid,
|
||||
receiverUid: receiverUid,
|
||||
fileUuid: fileUUID,
|
||||
fileHash: fileHash,
|
||||
},
|
||||
field101: 3,
|
||||
field102: 1,
|
||||
field200: 1,
|
||||
}), false, false);
|
||||
return this.toHexStr(req);
|
||||
}
|
||||
|
||||
packGroupFileDownloadReq(groupUin: number, fileUUID: string): PacketHexStr {
|
||||
return this.toHexStr(
|
||||
this.packOidbPacket(0x6D6, 2, new NapProtoMsg(OidbSvcTrpcTcp0x6D6).encode({
|
||||
|
@ -113,8 +113,26 @@ export const Permission = {
|
||||
|
||||
export const FileExtra = {
|
||||
file: ProtoField(1, () => NotOnlineFile),
|
||||
field6: ProtoField(6, () => PrivateFileExtra),
|
||||
};
|
||||
|
||||
export const PrivateFileExtra = {
|
||||
field2: ProtoField(2, () => PrivateFileExtraField2),
|
||||
}
|
||||
|
||||
export const PrivateFileExtraField2 = {
|
||||
field1: ProtoField(1, ScalarType.UINT32),
|
||||
fileUuid: ProtoField(4, ScalarType.STRING),
|
||||
fileName: ProtoField(5, ScalarType.STRING),
|
||||
field6: ProtoField(6, ScalarType.UINT32),
|
||||
field7: ProtoField(7, ScalarType.BYTES),
|
||||
field8: ProtoField(8, ScalarType.BYTES),
|
||||
timestamp1: ProtoField(9, ScalarType.UINT32),
|
||||
fileHash: ProtoField(14, ScalarType.STRING),
|
||||
selfUid: ProtoField(15, ScalarType.STRING),
|
||||
destUid: ProtoField(16, ScalarType.STRING),
|
||||
}
|
||||
|
||||
export const GroupFileExtra = {
|
||||
field1: ProtoField(1, ScalarType.UINT32),
|
||||
fileName: ProtoField(2, ScalarType.STRING),
|
||||
@ -132,8 +150,9 @@ export const GroupFileExtraInfo = {
|
||||
fileSize: ProtoField(3, ScalarType.UINT64),
|
||||
fileName: ProtoField(4, ScalarType.STRING),
|
||||
field5: ProtoField(5, ScalarType.UINT32),
|
||||
field7: ProtoField(7, ScalarType.STRING),
|
||||
fileMd5: ProtoField(8, ScalarType.STRING),
|
||||
fileSha: ProtoField(6, ScalarType.BYTES),
|
||||
extInfoString: ProtoField(7, ScalarType.STRING),
|
||||
fileMd5: ProtoField(8, ScalarType.BYTES),
|
||||
};
|
||||
|
||||
export const ImageExtraUrl = {
|
||||
|
62
src/core/packet/proto/oidb/Oidb.0XE37_800.ts
Normal file
62
src/core/packet/proto/oidb/Oidb.0XE37_800.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { ScalarType } from "@protobuf-ts/runtime";
|
||||
import { ProtoField } from "../NapProto";
|
||||
import {OidbSvcTrpcTcp0XE37_800_1200Metadata} from "@/core/packet/proto/oidb/Oidb.0xE37_1200";
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_800 = {
|
||||
subCommand: ProtoField(1, ScalarType.UINT32),
|
||||
field2: ProtoField(2, ScalarType.INT32),
|
||||
body: ProtoField(10, () => OidbSvcTrpcTcp0XE37_800Body, true),
|
||||
field101: ProtoField(101, ScalarType.INT32),
|
||||
field102: ProtoField(102, ScalarType.INT32),
|
||||
field200: ProtoField(200, ScalarType.INT32)
|
||||
};
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_800Body = {
|
||||
senderUid: ProtoField(10, ScalarType.STRING, true),
|
||||
receiverUid: ProtoField(20, ScalarType.STRING, true),
|
||||
fileUuid: ProtoField(30, ScalarType.STRING, true),
|
||||
fileHash: ProtoField(40, ScalarType.STRING, true)
|
||||
};
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37Response = {
|
||||
command: ProtoField(1, ScalarType.UINT32),
|
||||
seq: ProtoField(2, ScalarType.INT32),
|
||||
upload: ProtoField(19, () => ApplyUploadRespV3, true),
|
||||
businessId: ProtoField(101, ScalarType.INT32),
|
||||
clientType: ProtoField(102, ScalarType.INT32),
|
||||
flagSupportMediaPlatform: ProtoField(200, ScalarType.INT32)
|
||||
};
|
||||
|
||||
export const ApplyUploadRespV3 = {
|
||||
retCode: ProtoField(10, ScalarType.INT32),
|
||||
retMsg: ProtoField(20, ScalarType.STRING, true),
|
||||
totalSpace: ProtoField(30, ScalarType.INT64),
|
||||
usedSpace: ProtoField(40, ScalarType.INT64),
|
||||
uploadedSize: ProtoField(50, ScalarType.INT64),
|
||||
uploadIp: ProtoField(60, ScalarType.STRING, true),
|
||||
uploadDomain: ProtoField(70, ScalarType.STRING, true),
|
||||
uploadPort: ProtoField(80, ScalarType.UINT32),
|
||||
uuid: ProtoField(90, ScalarType.STRING, true),
|
||||
uploadKey: ProtoField(100, ScalarType.BYTES, true),
|
||||
boolFileExist: ProtoField(110, ScalarType.BOOL),
|
||||
packSize: ProtoField(120, ScalarType.INT32),
|
||||
uploadIpList: ProtoField(130, ScalarType.STRING, false, true), // repeated
|
||||
uploadHttpsPort: ProtoField(140, ScalarType.INT32),
|
||||
uploadHttpsDomain: ProtoField(150, ScalarType.STRING, true),
|
||||
uploadDns: ProtoField(160, ScalarType.STRING, true),
|
||||
uploadLanip: ProtoField(170, ScalarType.STRING, true),
|
||||
fileAddon: ProtoField(200, ScalarType.STRING, true),
|
||||
mediaPlatformUploadKey: ProtoField(220, ScalarType.BYTES, true)
|
||||
};
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_800Response = {
|
||||
command: ProtoField(1, ScalarType.UINT32, true),
|
||||
subCommand: ProtoField(2, ScalarType.UINT32, true),
|
||||
body: ProtoField(10, () => OidbSvcTrpcTcp0XE37_800ResponseBody, true),
|
||||
field50: ProtoField(50, ScalarType.UINT32, true),
|
||||
};
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_800ResponseBody = {
|
||||
field10: ProtoField(10, ScalarType.UINT32, true),
|
||||
field30: ProtoField(30, () => OidbSvcTrpcTcp0XE37_800_1200Metadata, true),
|
||||
}
|
@ -30,7 +30,7 @@ export const OidbSvcTrpcTcp0XE37_1200ResponseBody = {
|
||||
field10: ProtoField(10, ScalarType.UINT32, true),
|
||||
state: ProtoField(20, ScalarType.STRING, true),
|
||||
result: ProtoField(30, () => OidbSvcTrpcTcp0XE37_1200Result, true),
|
||||
metadata: ProtoField(40, () => OidbSvcTrpcTcp0XE37_1200Metadata, true),
|
||||
metadata: ProtoField(40, () => OidbSvcTrpcTcp0XE37_800_1200Metadata, true),
|
||||
};
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_1200Result = {
|
||||
@ -43,7 +43,7 @@ export const OidbSvcTrpcTcp0XE37_1200Result = {
|
||||
extra: ProtoField(120, ScalarType.BYTES, true),
|
||||
};
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_1200Metadata = {
|
||||
export const OidbSvcTrpcTcp0XE37_800_1200Metadata = {
|
||||
uin: ProtoField(1, ScalarType.UINT32, true),
|
||||
field2: ProtoField(2, ScalarType.UINT32, true),
|
||||
field3: ProtoField(3, ScalarType.UINT32, true),
|
||||
|
23
src/core/packet/proto/oidb/Oidb.0xE37_1700.ts
Normal file
23
src/core/packet/proto/oidb/Oidb.0xE37_1700.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ScalarType } from "@protobuf-ts/runtime";
|
||||
import { ProtoField } from "../NapProto";
|
||||
|
||||
export const OidbSvcTrpcTcp0XE37_1700 = {
|
||||
command: ProtoField(1, ScalarType.UINT32, true),
|
||||
seq: ProtoField(2, ScalarType.INT32, true),
|
||||
upload: ProtoField(19, () => ApplyUploadReqV3, true),
|
||||
businessId: ProtoField(101, ScalarType.INT32, true),
|
||||
clientType: ProtoField(102, ScalarType.INT32, true),
|
||||
flagSupportMediaPlatform: ProtoField(200, ScalarType.INT32, true),
|
||||
}
|
||||
|
||||
export const ApplyUploadReqV3 = {
|
||||
senderUid: ProtoField(10, ScalarType.STRING, true),
|
||||
receiverUid: ProtoField(20, ScalarType.STRING, true),
|
||||
fileSize: ProtoField(30, ScalarType.UINT32, true),
|
||||
fileName: ProtoField(40, ScalarType.STRING, true),
|
||||
md510MCheckSum: ProtoField(50, ScalarType.BYTES, true),
|
||||
sha1CheckSum: ProtoField(60, ScalarType.BYTES, true),
|
||||
localPath: ProtoField(70, ScalarType.STRING, true),
|
||||
md5CheckSum: ProtoField(110, ScalarType.BYTES, true),
|
||||
sha3CheckSum: ProtoField(120, ScalarType.BYTES, true),
|
||||
}
|
@ -11,11 +11,23 @@ function sha1Stream(readable: stream.Readable) {
|
||||
}) as Promise<Buffer>;
|
||||
}
|
||||
|
||||
function md5Stream(readable: stream.Readable) {
|
||||
return new Promise((resolve, reject) => {
|
||||
readable.on('error', reject);
|
||||
readable.pipe(crypto.createHash('md5').on('error', reject).on('data', resolve));
|
||||
}) as Promise<Buffer>;
|
||||
}
|
||||
|
||||
export function calculateSha1(filePath: string): Promise<Buffer> {
|
||||
const readable = fs.createReadStream(filePath);
|
||||
return sha1Stream(readable);
|
||||
}
|
||||
|
||||
export function computeMd5AndLengthWithLimit(filePath: string, limit?: number): Promise<Buffer> {
|
||||
const readStream = fs.createReadStream(filePath, limit ? { start: 0, end: limit - 1 } : {});
|
||||
return md5Stream(readStream);
|
||||
}
|
||||
|
||||
export function calculateSha1StreamBytes(filePath: string): Promise<Buffer[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const readable = fs.createReadStream(filePath);
|
||||
|
Loading…
x
Reference in New Issue
Block a user