diff --git a/src/core/packet/client/baseClient.ts b/src/core/packet/client/baseClient.ts index 5516550a..4a8fab29 100644 --- a/src/core/packet/client/baseClient.ts +++ b/src/core/packet/client/baseClient.ts @@ -1,8 +1,9 @@ import { LRUCache } from "@/common/lru-cache"; import crypto, { createHash } from "crypto"; -import { PacketContext } from "@/core/packet/context/packetContext"; import { OidbPacket, PacketHexStr } from "@/core/packet/transformer/base"; import { LogStack } from "@/core/packet/context/clientContext"; +import { NapCoreContext } from "@/core/packet/context/napCoreContext"; +import { PacketLogger } from "@/core/packet/context/loggerContext"; export interface RecvPacket { type: string, // 仅recv @@ -27,13 +28,15 @@ function randText(len: number): string { export abstract class IPacketClient { - protected readonly context: PacketContext; + protected readonly napcore: NapCoreContext; + protected readonly logger: PacketLogger; protected readonly cb = new LRUCache Promise>(500); // trace_id-type callback logStack: LogStack; available: boolean = false; - protected constructor(context: PacketContext, logStack: LogStack) { - this.context = context; + protected constructor(napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) { + this.napcore = napCore; + this.logger = logger; this.logStack = logStack; } @@ -81,7 +84,7 @@ export abstract class IPacketClient { const md5 = crypto.createHash('md5').update(data).digest('hex'); const trace_id = (randText(4) + md5 + data).slice(0, data.length / 2); return this.sendCommand(cmd, data, trace_id, rsp, 20000, async () => { - await this.context.napcore.sendSsoCmdReqByContend(cmd, trace_id); + await this.napcore.sendSsoCmdReqByContend(cmd, trace_id); }); } diff --git a/src/core/packet/client/nativeClient.ts b/src/core/packet/client/nativeClient.ts index c4d8bd8d..da03b5a5 100644 --- a/src/core/packet/client/nativeClient.ts +++ b/src/core/packet/client/nativeClient.ts @@ -5,8 +5,9 @@ import fs from "fs"; import { IPacketClient } from "@/core/packet/client/baseClient"; import { constants } from "node:os"; import { LRUCache } from "@/common/lru-cache"; -import { PacketContext } from "@/core/packet/context/packetContext"; import { LogStack } from "@/core/packet/context/clientContext"; +import { NapCoreContext } from "@/core/packet/context/napCoreContext"; +import { PacketLogger } from "@/core/packet/context/loggerContext"; // 0 send 1 recv export interface NativePacketExportType { @@ -19,8 +20,8 @@ export class NativePacketClient extends IPacketClient { private readonly MoeHooExport: { exports: NativePacketExportType } = { exports: {} }; private readonly sendEvent = new LRUCache(500); // seq->trace_id - constructor(context: PacketContext, logStack: LogStack) { - super(context, logStack); + constructor(napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) { + super(napCore, logger, logStack); } check(): boolean { diff --git a/src/core/packet/client/wsClient.ts b/src/core/packet/client/wsClient.ts index 8d195e9a..c744f84e 100644 --- a/src/core/packet/client/wsClient.ts +++ b/src/core/packet/client/wsClient.ts @@ -1,7 +1,8 @@ import { Data, WebSocket, ErrorEvent } from "ws"; import { IPacketClient, RecvPacket } from "@/core/packet/client/baseClient"; -import { PacketContext } from "@/core/packet/context/packetContext"; import { LogStack } from "@/core/packet/context/clientContext"; +import { NapCoreContext } from "@/core/packet/context/napCoreContext"; +import { PacketLogger } from "@/core/packet/context/loggerContext"; export class WsPacketClient extends IPacketClient { private websocket: WebSocket | null = null; @@ -13,15 +14,15 @@ export class WsPacketClient extends IPacketClient { private isInitialized: boolean = false; private initPayload: { pid: number, recv: string, send: string } | null = null; - constructor(context: PacketContext, logStack: LogStack) { - super(context, logStack); - this.clientUrl = this.context.napcore.config.packetServer - ? this.clientUrlWrap(this.context.napcore.config.packetServer) + constructor(napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) { + super(napCore, logger, logStack); + this.clientUrl = this.napcore.config.packetServer + ? this.clientUrlWrap(this.napcore.config.packetServer) : this.clientUrlWrap('127.0.0.1:8083'); } check(): boolean { - if (!this.context.napcore.config.packetServer) { + if (!this.napcore.config.packetServer) { this.logStack.pushLogWarn(`wsPacketClient 未配置服务器地址`); return false; } @@ -67,7 +68,7 @@ export class WsPacketClient extends IPacketClient { this.websocket.onopen = () => { this.available = true; this.reconnectAttempts = 0; - this.context.logger.info(`wsPacketClient 已连接到 ${this.clientUrl}`); + this.logger.info(`wsPacketClient 已连接到 ${this.clientUrl}`); if (!this.isInitialized && this.initPayload) { this.websocket!.send(JSON.stringify({ action: 'init', @@ -79,15 +80,15 @@ export class WsPacketClient extends IPacketClient { }; this.websocket.onclose = () => { this.available = false; - this.context.logger.warn(`WebSocket 连接关闭,尝试重连...`); + this.logger.warn(`WebSocket 连接关闭,尝试重连...`); reject(new Error('WebSocket 连接关闭')); }; this.websocket.onmessage = (event) => this.handleMessage(event.data).catch(err => { - this.context.logger.error(`处理消息时出错: ${err}`); + this.logger.error(`处理消息时出错: ${err}`); }); this.websocket.onerror = (event: ErrorEvent) => { this.available = false; - this.context.logger.error(`WebSocket 出错: ${event.message}`); + this.logger.error(`WebSocket 出错: ${event.message}`); this.websocket?.close(); reject(new Error(`WebSocket 出错: ${event.message}`)); }; @@ -106,7 +107,7 @@ export class WsPacketClient extends IPacketClient { const event = this.cb.get(`${trace_id_md5}${action}`); if (event) await event(json.data); } catch (error) { - this.context.logger.error(`解析ws消息时出错: ${(error as Error).message}`); + this.logger.error(`解析ws消息时出错: ${(error as Error).message}`); } } } diff --git a/src/core/packet/clientSession.ts b/src/core/packet/clientSession.ts index f0932cfb..3faea314 100644 --- a/src/core/packet/clientSession.ts +++ b/src/core/packet/clientSession.ts @@ -23,9 +23,7 @@ export class PacketClientSession { get operation() { return this.context.operation; } - get client() { - return this.context.client; - } + // TODO: global message element adapter (? get msgConverter() { return this.context.msgConverter; diff --git a/src/core/packet/context/clientContext.ts b/src/core/packet/context/clientContext.ts index 1b060b82..168a9abc 100644 --- a/src/core/packet/context/clientContext.ts +++ b/src/core/packet/context/clientContext.ts @@ -1,17 +1,17 @@ -import { PacketContext } from "@/core/packet/context/packetContext"; import { IPacketClient } from "@/core/packet/client/baseClient"; import { NativePacketClient } from "@/core/packet/client/nativeClient"; import { WsPacketClient } from "@/core/packet/client/wsClient"; import { OidbPacket } from "@/core/packet/transformer/base"; import { PacketLogger } from "@/core/packet/context/loggerContext"; +import { NapCoreContext } from "@/core/packet/context/napCoreContext"; type clientPriority = { - [key: number]: (context: PacketContext, logStack: LogStack) => IPacketClient; + [key: number]: (napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) => IPacketClient; } const clientPriority: clientPriority = { - 10: (context: PacketContext, logStack: LogStack) => new NativePacketClient(context, logStack), - 1: (context: PacketContext, logStack: LogStack) => new WsPacketClient(context, logStack), + 10: (napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) => new NativePacketClient(napCore, logger, logStack), + 1: (napCore: NapCoreContext, logger: PacketLogger, logStack: LogStack) => new WsPacketClient(napCore, logger, logStack), }; export class LogStack { @@ -51,13 +51,15 @@ export class LogStack { } export class PacketClientContext { - private readonly context: PacketContext; + private readonly napCore: NapCoreContext; + private readonly logger: PacketLogger; private readonly logStack: LogStack; private readonly _client: IPacketClient; - constructor(context: PacketContext) { - this.context = context; - this.logStack = new LogStack(context.logger); + constructor(napCore: NapCoreContext, logger: PacketLogger) { + this.napCore = napCore; + this.logger = logger; + this.logStack = new LogStack(logger); this._client = this.newClient(); } @@ -79,23 +81,23 @@ export class PacketClientContext { } private newClient(): IPacketClient { - const prefer = this.context.napcore.config.packetBackend; + const prefer = this.napCore.config.packetBackend; let client: IPacketClient | null; switch (prefer) { case "native": - this.context.logger.info("使用指定的 NativePacketClient 作为后端"); - client = new NativePacketClient(this.context, this.logStack); + this.logger.info("使用指定的 NativePacketClient 作为后端"); + client = new NativePacketClient(this.napCore, this.logger, this.logStack); break; case "frida": - this.context.logger.info("[Core] [Packet] 使用指定的 FridaPacketClient 作为后端"); - client = new WsPacketClient(this.context, this.logStack); + this.logger.info("[Core] [Packet] 使用指定的 FridaPacketClient 作为后端"); + client = new WsPacketClient(this.napCore, this.logger, this.logStack); break; case "auto": case undefined: client = this.judgeClient(); break; default: - this.context.logger.error(`未知的PacketBackend ${prefer},请检查配置文件!`); + this.logger.error(`未知的PacketBackend ${prefer},请检查配置文件!`); client = null; } if (!client?.check()) { @@ -110,7 +112,7 @@ export class PacketClientContext { private judgeClient(): IPacketClient { const sortedClients = Object.entries(clientPriority) .map(([priority, clientFactory]) => { - const client = clientFactory(this.context, this.logStack); + const client = clientFactory(this.napCore, this.logger, this.logStack); const score = +priority * +client.check(); return { client, score }; }) @@ -120,7 +122,7 @@ export class PacketClientContext { if (!selectedClient) { throw new Error("[Core] [Packet] 无可用的后端,NapCat.Packet将不会加载!"); } - this.context.logger.info(`自动选择 ${selectedClient.constructor.name} 作为后端`); + this.logger.info(`自动选择 ${selectedClient.constructor.name} 作为后端`); return selectedClient; } } diff --git a/src/core/packet/context/loggerContext.ts b/src/core/packet/context/loggerContext.ts index 3d6d35da..8c855f8f 100644 --- a/src/core/packet/context/loggerContext.ts +++ b/src/core/packet/context/loggerContext.ts @@ -1,12 +1,12 @@ import { LogLevel, LogWrapper } from "@/common/log"; -import { PacketContext } from "@/core/packet/context/packetContext"; +import { NapCoreContext } from "@/core/packet/context/napCoreContext"; // TODO: check bind? export class PacketLogger { private readonly napLogger: LogWrapper; - constructor(context: PacketContext) { - this.napLogger = context.napcore.logger; + constructor(napcore: NapCoreContext) { + this.napLogger = napcore.logger; } private _log(level: LogLevel, ...msg: any[]): void { diff --git a/src/core/packet/context/operationContext.ts b/src/core/packet/context/operationContext.ts index a9e34b13..2626ac2f 100644 --- a/src/core/packet/context/operationContext.ts +++ b/src/core/packet/context/operationContext.ts @@ -13,6 +13,7 @@ import { MiniAppRawData, MiniAppReqParams } from "@/core/packet/entities/miniApp import { AIVoiceChatType } from "@/core/packet/entities/aiChat"; import { NapProtoDecodeStructType, NapProtoEncodeStructType } from "@napneko/nap-proto-core"; import { IndexNode, MsgInfo } from "@/core/packet/transformer/proto"; +import { OidbPacket } from "@/core/packet/transformer/base"; export class PacketOperationContext { private readonly context: PacketContext; @@ -20,6 +21,10 @@ export class PacketOperationContext { this.context = context; } + async sendPacket(pkt: OidbPacket, rsp?: T): Promise { + return await this.context.client.sendOidbPacket(pkt, rsp); + } + async GroupPoke(groupUin: number, uin: number) { const req = trans.SendPoke.build(uin, groupUin); await this.context.client.sendOidbPacket(req); diff --git a/src/core/packet/context/packetContext.ts b/src/core/packet/context/packetContext.ts index 51804fae..b5484e5d 100644 --- a/src/core/packet/context/packetContext.ts +++ b/src/core/packet/context/packetContext.ts @@ -7,19 +7,19 @@ import { PacketOperationContext } from "@/core/packet/context/operationContext"; import { PacketMsgConverter } from "@/core/packet/message/converter"; export class PacketContext { + readonly msgConverter: PacketMsgConverter; readonly napcore: NapCoreContext; readonly logger: PacketLogger; readonly client: PacketClientContext; readonly highway: PacketHighwayContext; - readonly msgConverter: PacketMsgConverter; readonly operation: PacketOperationContext; constructor(core: NapCatCore) { - this.napcore = new NapCoreContext(core); - this.logger = new PacketLogger(this); - this.client = new PacketClientContext(this); - this.highway = new PacketHighwayContext(this); this.msgConverter = new PacketMsgConverter(); + this.napcore = new NapCoreContext(core); + this.logger = new PacketLogger(this.napcore); + this.client = new PacketClientContext(this.napcore, this.logger); + this.highway = new PacketHighwayContext(this.napcore, this.logger, this.client); this.operation = new PacketOperationContext(this); } } diff --git a/src/core/packet/highway/highwayContext.ts b/src/core/packet/highway/highwayContext.ts index 96da373e..2fdd6f52 100644 --- a/src/core/packet/highway/highwayContext.ts +++ b/src/core/packet/highway/highwayContext.ts @@ -1,5 +1,4 @@ import { PacketHighwayClient } from "@/core/packet/highway/client"; -import { PacketContext } from "@/core/packet/context/packetContext"; import { PacketLogger } from "@/core/packet/context/loggerContext"; import FetchSessionKey from "@/core/packet/transformer/highway/FetchSessionKey"; import { int32ip2str, oidbIpv4s2HighwayIpv4s } from "@/core/packet/highway/utils"; @@ -16,6 +15,8 @@ import { NapProtoMsg } from "@napneko/nap-proto-core"; import * as proto from "@/core/packet/transformer/proto"; import * as trans from "@/core/packet/transformer"; import fs from "fs"; +import { NapCoreContext } from "@/core/packet/context/napCoreContext"; +import { PacketClientContext } from "@/core/packet/context/clientContext"; export const BlockSize = 1024 * 1024; @@ -33,23 +34,25 @@ export interface PacketHighwaySig { } export class PacketHighwayContext { - private readonly context: PacketContext; + private readonly napcore: NapCoreContext; + private readonly client: PacketClientContext; protected sig: PacketHighwaySig; protected logger: PacketLogger; protected hwClient: PacketHighwayClient; private cachedPrepareReq: Promise | null = null; - constructor(context: PacketContext) { - this.context = context; + constructor(napcore: NapCoreContext, logger: PacketLogger, client: PacketClientContext) { + this.napcore = napcore; + this.client = client; this.sig = { - uin: String(context.napcore.basicInfo.uin), - uid: context.napcore.basicInfo.uid, + uin: String(this.napcore.basicInfo.uin), + uid: this.napcore.basicInfo.uid, sigSession: null, sessionKey: null, serverAddr: [], }; - this.logger = context.logger; - this.hwClient = new PacketHighwayClient(this.sig, context.logger); + this.logger = logger; + this.hwClient = new PacketHighwayClient(this.sig, this.logger); } private async checkAvailable() { @@ -66,7 +69,7 @@ export class PacketHighwayContext { private async prepareUpload(): Promise { this.logger.debug('[Highway] on prepareUpload!'); const packet = FetchSessionKey.build(); - const req = await this.context.client.sendOidbPacket(packet, true); + const req = await this.client.sendOidbPacket(packet, true); const rsp = FetchSessionKey.parse(req); this.sig.sigSession = rsp.httpConn.sigSession; this.sig.sessionKey = rsp.httpConn.sessionKey; @@ -136,7 +139,7 @@ export class PacketHighwayContext { private async uploadGroupImage(groupUin: number, img: PacketMsgPicElement): Promise { img.sha1 = Buffer.from(await calculateSha1(img.path)).toString('hex'); const req = UploadGroupImage.build(groupUin, img); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = UploadGroupImage.parse(resp); const ukey = preRespData.upload.uKey; if (ukey && ukey != "") { @@ -173,7 +176,7 @@ export class PacketHighwayContext { private async uploadC2CImage(peerUid: string, img: PacketMsgPicElement): Promise { img.sha1 = Buffer.from(await calculateSha1(img.path)).toString('hex'); const req = trans.UploadPrivateImage.build(peerUid, img); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadPrivateImage.parse(resp); const ukey = preRespData.upload.uKey; if (ukey && ukey != "") { @@ -211,7 +214,7 @@ export class PacketHighwayContext { video.fileSha1 = Buffer.from(await calculateSha1(video.filePath)).toString('hex'); video.thumbSha1 = Buffer.from(await calculateSha1(video.thumbPath)).toString('hex'); const req = trans.UploadGroupVideo.build(groupUin, video); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadGroupVideo.parse(resp); const ukey = preRespData.upload.uKey; if (ukey && ukey != "") { @@ -276,7 +279,7 @@ export class PacketHighwayContext { video.fileSha1 = Buffer.from(await calculateSha1(video.filePath)).toString('hex'); video.thumbSha1 = Buffer.from(await calculateSha1(video.thumbPath)).toString('hex'); const req = trans.UploadPrivateVideo.build(peerUid, video); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadPrivateVideo.parse(resp); const ukey = preRespData.upload.uKey; if (ukey && ukey != "") { @@ -339,7 +342,7 @@ export class PacketHighwayContext { private async uploadGroupPtt(groupUin: number, ptt: PacketMsgPttElement): Promise { ptt.fileSha1 = Buffer.from(await calculateSha1(ptt.filePath)).toString('hex'); const req = trans.UploadGroupPtt.build(groupUin, ptt); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadGroupPtt.parse(resp); const ukey = preRespData.upload.uKey; if (ukey && ukey != "") { @@ -375,7 +378,7 @@ export class PacketHighwayContext { private async uploadC2CPtt(peerUid: string, ptt: PacketMsgPttElement): Promise { ptt.fileSha1 = Buffer.from(await calculateSha1(ptt.filePath)).toString('hex'); const req = trans.UploadPrivatePtt.build(peerUid, ptt); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadPrivatePtt.parse(resp); const ukey = preRespData.upload.uKey; if (ukey && ukey != "") { @@ -413,7 +416,7 @@ export class PacketHighwayContext { file.fileMd5 = await computeMd5AndLengthWithLimit(file.filePath); file.fileSha1 = await calculateSha1(file.filePath); const req = trans.UploadGroupFile.build(groupUin, file); - const resp = await this.context.client.sendOidbPacket(req, true); + const resp = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadGroupFile.parse(resp); if (!preRespData?.upload?.boolFileExist) { this.logger.debug(`[Highway] uploadGroupFileReq file not exist, need upload!`); @@ -476,7 +479,7 @@ export class PacketHighwayContext { file.fileMd5 = await computeMd5AndLengthWithLimit(file.filePath); file.fileSha1 = await calculateSha1(file.filePath); const req = await trans.UploadPrivateFile.build(this.sig.uid, peerUid, file); - const res = await this.context.client.sendOidbPacket(req, true); + const res = await this.client.sendOidbPacket(req, true); const preRespData = trans.UploadPrivateFile.parse(res); if (!preRespData.upload?.boolFileExist) { this.logger.debug(`[Highway] uploadC2CFileReq file not exist, need upload!`); @@ -531,7 +534,7 @@ export class PacketHighwayContext { file.fileUuid = preRespData.upload?.uuid; file.fileHash = preRespData.upload?.fileAddon; const fileExistReq = trans.DownloadOfflineFile.build(file.fileUuid!, file.fileHash!, this.sig.uid, peerUid); - const fileExistRes = await this.context.client.sendOidbPacket(fileExistReq, true); + const fileExistRes = await this.client.sendOidbPacket(fileExistReq, true); file._e37_800_rsp = trans.DownloadOfflineFile.parse(fileExistRes); file._private_send_uid = this.sig.uid; file._private_recv_uid = peerUid; diff --git a/src/onebot/action/extends/SendPacket.ts b/src/onebot/action/extends/SendPacket.ts index 4925bf34..cf077e2e 100644 --- a/src/onebot/action/extends/SendPacket.ts +++ b/src/onebot/action/extends/SendPacket.ts @@ -15,7 +15,7 @@ export class SendPacket extends GetPacketStatusDepends { actionName = ActionName.SendPacket; async _handle(payload: Payload) { const rsp = typeof payload.rsp === 'boolean' ? payload.rsp : payload.rsp === 'true'; - const data = await this.core.apis.PacketApi.pkt.client.sendOidbPacket({ cmd: payload.cmd, data: payload.data as any }, rsp); + const data = await this.core.apis.PacketApi.pkt.operation.sendPacket({ cmd: payload.cmd, data: payload.data as any }, rsp); return typeof data === 'object' ? data.toString('hex') : undefined; } }