From 397c2cf5f015d2e0950f492a1b8df37fcd4b737f Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Mon, 14 Oct 2024 17:51:21 +0800 Subject: [PATCH] refactor: further decoupling of `Packet` and `Core` parts --- src/core/apis/file.ts | 2 +- src/core/apis/packet.ts | 47 ++++++------------- src/core/packet/client.ts | 36 ++++++++++++-- src/core/packet/session.ts | 15 ++++++ src/onebot/action/extends/GetRkey.ts | 2 +- src/onebot/action/extends/GetUserStatus.ts | 2 +- src/onebot/action/extends/SetSpecialTittle.ts | 2 +- src/onebot/action/extends/UploadForwardMsg.ts | 2 +- src/onebot/action/group/GroupPoke.ts | 2 +- 9 files changed, 68 insertions(+), 42 deletions(-) create mode 100644 src/core/packet/session.ts diff --git a/src/core/apis/file.ts b/src/core/apis/file.ts index c0457727..d3d30655 100644 --- a/src/core/apis/file.ts +++ b/src/core/apis/file.ts @@ -377,7 +377,7 @@ export class NTQQFileApi { online_rkey: false }; try { - if (this.core.apis.PacketApi.packetClient?.available) { + if (this.core.apis.PacketApi.available) { if ((!this.packetRkey || this.packetRkey[0].time > Date.now() / 1000)) { this.packetRkey = await this.core.apis.PacketApi.sendRkeyPacket(); } diff --git a/src/core/apis/packet.ts b/src/core/apis/packet.ts index 080503a6..8776c051 100644 --- a/src/core/apis/packet.ts +++ b/src/core/apis/packet.ts @@ -1,14 +1,13 @@ import * as os from 'os'; -import * as crypto from 'crypto'; import {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.fe1_2'; - import {PacketForwardNode} from "@/core/packet/msg/entity/forward"; interface OffsetType { @@ -25,23 +24,29 @@ export class NTQQPacketApi { core: NapCatCore; serverUrl: string | undefined; qqVersion: string | undefined; - isInit: boolean = false; packetPacker: PacketPacker; - packetClient: PacketClient | undefined; + packetSession: PacketSession | undefined; constructor(context: InstanceContext, core: NapCatCore) { this.context = context; this.core = core; this.packetPacker = new PacketPacker(); + this.packetSession = undefined; let config = this.core.configLoader.configData; if (config && config.packetServer && config.packetServer.length > 0) { let serverUrl = this.core.configLoader.configData.packetServer ?? '127.0.0.1:8086'; this.InitSendPacket(serverUrl, this.context.basicInfoWrapper.getFullQQVesion()) .then() .catch(this.core.context.logger.logError.bind(this.core.context.logger)); + } else { + this.core.context.logger.logWarn('PacketServer is not set, will not init NapCat.Packet!'); } } + get available(): boolean { + return this.packetSession?.client.available ?? false; + } + async InitSendPacket(serverUrl: string, qqversion: string) { this.serverUrl = serverUrl; this.qqVersion = qqversion; @@ -49,40 +54,18 @@ export class NTQQPacketApi { let table = offsetTable[qqversion + '-' + os.arch()]; if (!table) return false; let url = 'ws://' + this.serverUrl + '/ws'; - this.packetClient = new PacketClient(url, this.core.context.logger); - await this.packetClient.connect(); - await this.packetClient.init(process.pid, table.recv, table.send); - this.isInit = true; - return this.isInit; - } - - randText(len: number) { - let text = ''; - let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < len; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - return text; + this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core)); + await this.packetSession.client.connect(); + await this.packetSession.client.init(process.pid, table.recv, table.send); + return true; } async sendPacket(cmd: string, data: PacketHexStr, rsp = false): Promise { - // wtfk tx - // 校验失败和异常 可能返回undefined - return new Promise((resolve, reject) => { - if (!this.isInit || !this.packetClient?.available) { - this.core.context.logger.logError('PacketClient is not init'); - return undefined; - } - let md5 = crypto.createHash('md5').update(data).digest('hex'); - let trace_id = (this.randText(4) + md5 + data).slice(0, data.length / 2); - this.packetClient?.sendCommand(cmd, data, trace_id, rsp, 5000, async () => { - await this.core.context.session.getMsgService().sendSsoCmdReqByContend(cmd, trace_id); - }).then((res) => resolve(res)).catch((e) => reject(e)); - }); + return this.packetSession!.client!.sendPacket(cmd, data, rsp); } async sendPokePacket(group: number, peer: number) { - let data = this.core.apis.PacketApi.packetPacker.packPokePacket(group, peer); + let data = this.packetPacker.packPokePacket(group, peer); let ret = await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data, false); //console.log('ret: ', ret); } diff --git a/src/core/packet/client.ts b/src/core/packet/client.ts index 50370ea7..88164cef 100644 --- a/src/core/packet/client.ts +++ b/src/core/packet/client.ts @@ -1,7 +1,9 @@ import {LogWrapper} from "@/common/log"; import {LRUCache} from "@/common/lru-cache"; import WebSocket, {Data} from "ws"; -import {createHash} from "crypto"; +import crypto, {createHash} from "crypto"; +import {NapCatCore} from "@/core"; +import {PacketHexStr} from "@/core/packet/packer"; export interface RecvPacket { type: string, // 仅recv @@ -22,17 +24,28 @@ export class PacketClient { private maxReconnectAttempts: number = 5; private cb = new LRUCache Promise>(500); // trace_id-type callback private readonly clientUrl: string = ''; + private readonly napCatCore: NapCatCore private readonly logger: LogWrapper; - constructor(url: string, logger: LogWrapper) { + constructor(url: string, core: NapCatCore) { this.clientUrl = url; - this.logger = logger; + this.napCatCore = core; + this.logger = core.context.logger; } get available(): boolean { return this.isConnected && this.websocket !== undefined; } + private randText(len: number) { + let text = ''; + let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < len; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + } + connect(): Promise { return new Promise((resolve, reject) => { this.logger.log.bind(this.logger)(`Attempting to connect to ${this.clientUrl}`); @@ -91,7 +104,6 @@ export class PacketClient { if (!this.isConnected || !this.websocket) { throw new Error("WebSocket is not connected"); } - const initMessage = { action: 'init', pid: pid, @@ -147,4 +159,20 @@ export class PacketClient { this.logger.logError.bind(this.logger)(`Error parsing message: ${error}`); } } + + async sendPacket(cmd: string, data: PacketHexStr, rsp = false): Promise { + // wtfk tx + // 校验失败和异常 可能返回undefined + return new Promise((resolve, reject) => { + if (!this.available) { + this.logger.logError('NapCat.Packet is not init'); + return undefined; + } + let md5 = crypto.createHash('md5').update(data).digest('hex'); + let trace_id = (this.randText(4) + md5 + data).slice(0, data.length / 2); + this.sendCommand(cmd, data, trace_id, rsp, 5000, async () => { + await this.napCatCore.context.session.getMsgService().sendSsoCmdReqByContend(cmd, trace_id); + }).then((res) => resolve(res)).catch((e) => reject(e)); + }); + } } diff --git a/src/core/packet/session.ts b/src/core/packet/session.ts new file mode 100644 index 00000000..30ce588d --- /dev/null +++ b/src/core/packet/session.ts @@ -0,0 +1,15 @@ +import {PacketClient} from "@/core/packet/client"; +import {PacketHighwayClient} from "@/core/packet/highway/highwayClient"; +import {LogWrapper} from "@/common/log"; + +export class PacketSession { + readonly logger: LogWrapper; + readonly client: PacketClient; + private highwayClient: PacketHighwayClient + + constructor(logger: LogWrapper, client: PacketClient) { + this.logger = logger; + this.client = client; + this.highwayClient = new PacketHighwayClient(this.logger, this.client); + } +} diff --git a/src/onebot/action/extends/GetRkey.ts b/src/onebot/action/extends/GetRkey.ts index 0f18d166..0f6eb0db 100644 --- a/src/onebot/action/extends/GetRkey.ts +++ b/src/onebot/action/extends/GetRkey.ts @@ -15,7 +15,7 @@ export class GetRkey extends BaseAction> { payloadSchema = SchemaData; async _handle(payload: Payload) { - if (!this.core.apis.PacketApi.packetClient?.available) { + if (!this.core.apis.PacketApi.available) { throw new Error('PacketClient is not init'); } return await this.core.apis.PacketApi.sendRkeyPacket(); diff --git a/src/onebot/action/extends/GetUserStatus.ts b/src/onebot/action/extends/GetUserStatus.ts index 435a08cb..0f1f3353 100644 --- a/src/onebot/action/extends/GetUserStatus.ts +++ b/src/onebot/action/extends/GetUserStatus.ts @@ -17,7 +17,7 @@ export class GetUserStatus extends BaseAction { payloadSchema = SchemaData; async _handle(payload: Payload) { - if (!this.core.apis.PacketApi.packetClient?.available) { + if (!this.core.apis.PacketApi.available) { throw new Error('PacketClient is not init'); } let uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); diff --git a/src/onebot/action/extends/UploadForwardMsg.ts b/src/onebot/action/extends/UploadForwardMsg.ts index e0d5625d..dd8bcab2 100644 --- a/src/onebot/action/extends/UploadForwardMsg.ts +++ b/src/onebot/action/extends/UploadForwardMsg.ts @@ -20,7 +20,7 @@ export class UploadForwardMsg extends BaseAction { payloadSchema = SchemaData; async _handle(payload: Payload) { - if (!this.core.apis.PacketApi.packetClient?.available) { + if (!this.core.apis.PacketApi.available) { throw new Error('PacketClient is not init'); } throw new Error('Not implemented'); diff --git a/src/onebot/action/group/GroupPoke.ts b/src/onebot/action/group/GroupPoke.ts index dbc1d158..eb2812b0 100644 --- a/src/onebot/action/group/GroupPoke.ts +++ b/src/onebot/action/group/GroupPoke.ts @@ -18,7 +18,7 @@ export class GroupPoke extends BaseAction { payloadSchema = SchemaData; async _handle(payload: Payload) { - if (!this.core.apis.PacketApi.packetClient?.available) { + if (!this.core.apis.PacketApi.available) { throw new Error('PacketClient is not init'); } await this.core.apis.PacketApi.sendPokePacket(+payload.group_id, +payload.user_id);