mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-21 09:36:35 +00:00
feat: errorStack
This commit is contained in:
parent
f07941685b
commit
75866b435e
@ -148,6 +148,7 @@ export class LogWrapper {
|
||||
} else if (this.consoleLogEnabled) {
|
||||
this.logger.log(level, message);
|
||||
} else if (this.fileLogEnabled) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
this.logger.log(level, message.replace(/\x1B[@-_][0-?]*[ -/]*[@-~]/g, ''));
|
||||
}
|
||||
}
|
||||
@ -226,7 +227,7 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
?
|
||||
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
|
||||
`未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})`
|
||||
}]`;
|
||||
}]`;
|
||||
}
|
||||
|
||||
if (element.picElement) {
|
||||
@ -277,4 +278,4 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
}
|
||||
|
||||
return tokens.join(' ');
|
||||
}
|
||||
}
|
||||
|
@ -19,34 +19,46 @@ export class NTQQPacketApi {
|
||||
core: NapCatCore;
|
||||
logger: LogWrapper;
|
||||
qqVersion: string | undefined;
|
||||
pkt: PacketClientSession;
|
||||
pkt!: PacketClientSession;
|
||||
errStack: string[] = [];
|
||||
|
||||
constructor(context: InstanceContext, core: NapCatCore) {
|
||||
this.context = context;
|
||||
this.core = core;
|
||||
this.logger = core.context.logger;
|
||||
this.pkt = new PacketClientSession(core);
|
||||
this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
||||
.then()
|
||||
.catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||
.catch((err) => {
|
||||
this.logger.logError.bind(this.core.context.logger);
|
||||
this.errStack.push(err);
|
||||
});
|
||||
}
|
||||
|
||||
get available(): boolean {
|
||||
return this.pkt?.available;
|
||||
return this.pkt?.available ?? false;
|
||||
}
|
||||
|
||||
get clientLogStack() {
|
||||
return this.pkt?.clientLogStack + '\n' + this.errStack.join('\n');
|
||||
}
|
||||
|
||||
async InitSendPacket(qqVer: string) {
|
||||
this.qqVersion = qqVer;
|
||||
const table = typedOffset[qqVer + '-' + os.arch()];
|
||||
if (!table) {
|
||||
this.logger.logError(`[Core] [Packet] PacketBackend 不支持当前QQ版本架构:${qqVer}-${os.arch()},
|
||||
请参照 https://github.com/NapNeko/NapCatQQ/releases/tag/v${napCatVersion} 配置正确的QQ版本!`);
|
||||
const err = `[Core] [Packet] PacketBackend 不支持当前QQ版本架构:${qqVer}-${os.arch()},
|
||||
请参照 https://github.com/NapNeko/NapCatQQ/releases/tag/v${napCatVersion} 配置正确的QQ版本!`;
|
||||
this.logger.logError(err);
|
||||
this.errStack.push(err);
|
||||
return false;
|
||||
}
|
||||
if (this.core.configLoader.configData.packetBackend === 'disable') {
|
||||
this.logger.logWarn('[Core] [Packet] 已禁用PacketBackend,NapCat.Packet将不会加载!');
|
||||
const err = '[Core] [Packet] 已禁用PacketBackend,NapCat.Packet将不会加载!';
|
||||
this.logger.logError(err);
|
||||
this.errStack.push(err);
|
||||
return false;
|
||||
}
|
||||
this.pkt = new PacketClientSession(this.core);
|
||||
await this.pkt.init(process.pid, table.recv, table.send);
|
||||
return true;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ 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";
|
||||
|
||||
export interface RecvPacket {
|
||||
type: string, // 仅recv
|
||||
@ -24,13 +25,16 @@ function randText(len: number): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
export abstract class IPacketClient {
|
||||
protected readonly context: PacketContext;
|
||||
protected readonly cb = new LRUCache<string, (json: RecvPacketData) => Promise<void>>(500); // trace_id-type callback
|
||||
logStack: LogStack;
|
||||
available: boolean = false;
|
||||
|
||||
protected constructor(context: PacketContext) {
|
||||
protected constructor(context: PacketContext, logStack: LogStack) {
|
||||
this.context = context;
|
||||
this.logStack = logStack;
|
||||
}
|
||||
|
||||
abstract check(): boolean;
|
||||
|
@ -6,6 +6,7 @@ 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";
|
||||
|
||||
// 0 send 1 recv
|
||||
export interface NativePacketExportType {
|
||||
@ -18,19 +19,19 @@ export class NativePacketClient extends IPacketClient {
|
||||
private MoeHooExport: { exports: NativePacketExportType } = { exports: {} };
|
||||
private sendEvent = new LRUCache<number, string>(500); // seq->trace_id
|
||||
|
||||
constructor(context: PacketContext) {
|
||||
super(context);
|
||||
constructor(context: PacketContext, logStack: LogStack) {
|
||||
super(context, logStack);
|
||||
}
|
||||
|
||||
check(): boolean {
|
||||
const platform = process.platform + '.' + process.arch;
|
||||
if (!this.supportedPlatforms.includes(platform)) {
|
||||
this.context.logger.warn(`不支持的平台: ${platform}`);
|
||||
this.logStack.pushLogWarn(`NativePacketClient: 不支持的平台: ${platform}`);
|
||||
return false;
|
||||
}
|
||||
const moehoo_path = path.join(dirname(fileURLToPath(import.meta.url)), './moehoo/MoeHoo.' + platform + '.node');
|
||||
if (!fs.existsSync(moehoo_path)) {
|
||||
this.context.logger.warn(`[Core] [Packet:Native] 缺失运行时文件: ${moehoo_path}`);
|
||||
this.logStack.pushLogWarn(`NativePacketClient: 缺失运行时文件: ${moehoo_path}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Data, WebSocket } from "ws";
|
||||
import { IPacketClient, RecvPacket } from "@/core/packet/client/baseClient";
|
||||
import { PacketContext } from "@/core/packet/context/packetContext";
|
||||
import { LogStack } from "@/core/packet/context/clientContext";
|
||||
|
||||
export class wsPacketClient extends IPacketClient {
|
||||
private websocket: WebSocket | null = null;
|
||||
@ -12,8 +13,8 @@ export class wsPacketClient extends IPacketClient {
|
||||
private isInitialized: boolean = false;
|
||||
private initPayload: { pid: number, recv: string, send: string } | null = null;
|
||||
|
||||
constructor(context: PacketContext) {
|
||||
super(context);
|
||||
constructor(context: PacketContext, logStack: LogStack) {
|
||||
super(context, logStack);
|
||||
this.clientUrl = this.context.napcore.config.packetServer
|
||||
? this.clientUrlWrap(this.context.napcore.config.packetServer)
|
||||
: this.clientUrlWrap('127.0.0.1:8083');
|
||||
@ -21,7 +22,7 @@ export class wsPacketClient extends IPacketClient {
|
||||
|
||||
check(): boolean {
|
||||
if (!this.context.napcore.config.packetServer) {
|
||||
this.context.logger.warn(`wsPacketClient 未配置服务器地址`);
|
||||
this.logStack.pushLogWarn(`wsPacketClient 未配置服务器地址`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -41,7 +42,7 @@ export class wsPacketClient extends IPacketClient {
|
||||
trace_id
|
||||
}));
|
||||
} else {
|
||||
this.context.logger.warn(`WebSocket 未连接,无法发送命令: ${cmd}`);
|
||||
this.logStack.pushLogWarn(`WebSocket 未连接,无法发送命令: ${cmd}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,11 +53,11 @@ export class wsPacketClient extends IPacketClient {
|
||||
return;
|
||||
} catch (error) {
|
||||
this.reconnectAttempts++;
|
||||
this.context.logger.warn(`第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次尝试重连失败!`);
|
||||
this.logStack.pushLogWarn(`第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次尝试重连失败!`);
|
||||
await this.delay(5000);
|
||||
}
|
||||
}
|
||||
this.context.logger.error(`wsPacketClient 在 ${this.clientUrl} 达到最大重连次数 (${this.maxReconnectAttempts})!`);
|
||||
this.logStack.pushLogError(`wsPacketClient 在 ${this.clientUrl} 达到最大重连次数 (${this.maxReconnectAttempts})!`);
|
||||
throw new Error(`无法连接到 WebSocket 服务器:${this.clientUrl}`);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,10 @@ export class PacketClientSession {
|
||||
return this.context.client.init(pid, recv, send);
|
||||
}
|
||||
|
||||
get clientLogStack() {
|
||||
return this.context.client.clientLogStack;
|
||||
}
|
||||
|
||||
get available() {
|
||||
return this.context.client.available;
|
||||
}
|
||||
|
@ -3,22 +3,61 @@ 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";
|
||||
|
||||
type clientPriority = {
|
||||
[key: number]: (context: PacketContext) => IPacketClient;
|
||||
[key: number]: (context: PacketContext, logStack: LogStack) => IPacketClient;
|
||||
}
|
||||
|
||||
const clientPriority: clientPriority = {
|
||||
10: (context: PacketContext) => new NativePacketClient(context),
|
||||
1: (context: PacketContext) => new wsPacketClient(context),
|
||||
10: (context: PacketContext, logStack: LogStack) => new NativePacketClient(context, logStack),
|
||||
1: (context: PacketContext, logStack: LogStack) => new wsPacketClient(context, logStack),
|
||||
};
|
||||
|
||||
export class LogStack {
|
||||
private stack: string[] = [];
|
||||
private logger: PacketLogger;
|
||||
|
||||
constructor(logger: PacketLogger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
push(msg: string) {
|
||||
this.stack.push(msg);
|
||||
}
|
||||
|
||||
pushLogInfo(msg: string) {
|
||||
this.logger.info(msg);
|
||||
this.stack.push(`${new Date().toISOString()} [INFO] ${msg}`);
|
||||
}
|
||||
|
||||
pushLogWarn(msg: string) {
|
||||
this.logger.warn(msg);
|
||||
this.stack.push(`${new Date().toISOString()} [WARN] ${msg}`);
|
||||
}
|
||||
|
||||
pushLogError(msg: string) {
|
||||
this.logger.error(msg);
|
||||
this.stack.push(`${new Date().toISOString()} [ERROR] ${msg}`);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.stack = [];
|
||||
}
|
||||
|
||||
content() {
|
||||
return this.stack.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
export class PacketClientContext {
|
||||
private readonly _client: IPacketClient;
|
||||
private readonly context: PacketContext;
|
||||
private readonly logStack: LogStack;
|
||||
private readonly _client: IPacketClient;
|
||||
|
||||
constructor(context: PacketContext) {
|
||||
this.context = context;
|
||||
this.logStack = new LogStack(context.logger);
|
||||
this._client = this.newClient();
|
||||
}
|
||||
|
||||
@ -26,13 +65,17 @@ export class PacketClientContext {
|
||||
return this._client.available;
|
||||
}
|
||||
|
||||
get clientLogStack(): string {
|
||||
return this._client.logStack.content();
|
||||
}
|
||||
|
||||
async init(pid: number, recv: string, send: string): Promise<void> {
|
||||
await this._client.init(pid, recv, send);
|
||||
}
|
||||
|
||||
async sendOidbPacket(pkt: OidbPacket, rsp = false): Promise<Buffer> {
|
||||
async sendOidbPacket<T extends boolean = false>(pkt: OidbPacket, rsp?: T): Promise<T extends true ? Buffer : void> {
|
||||
const raw = await this._client.sendOidbPacket(pkt, rsp);
|
||||
return Buffer.from(raw.hex_data, "hex");
|
||||
return (rsp ? Buffer.from(raw.hex_data, "hex") : undefined) as T extends true ? Buffer : void;
|
||||
}
|
||||
|
||||
private newClient(): IPacketClient {
|
||||
@ -41,11 +84,11 @@ export class PacketClientContext {
|
||||
switch (prefer) {
|
||||
case "native":
|
||||
this.context.logger.info("使用指定的 NativePacketClient 作为后端");
|
||||
client = new NativePacketClient(this.context);
|
||||
client = new NativePacketClient(this.context, this.logStack);
|
||||
break;
|
||||
case "frida":
|
||||
this.context.logger.info("[Core] [Packet] 使用指定的 FridaPacketClient 作为后端");
|
||||
client = new wsPacketClient(this.context);
|
||||
client = new wsPacketClient(this.context, this.logStack);
|
||||
break;
|
||||
case "auto":
|
||||
case undefined:
|
||||
@ -64,7 +107,7 @@ export class PacketClientContext {
|
||||
private judgeClient(): IPacketClient {
|
||||
const sortedClients = Object.entries(clientPriority)
|
||||
.map(([priority, clientFactory]) => {
|
||||
const client = clientFactory(this.context);
|
||||
const client = clientFactory(this.context, this.logStack);
|
||||
const score = +priority * +client.check();
|
||||
return { client, score };
|
||||
})
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
MiniAppRawData,
|
||||
MiniAppReqCustomParams,
|
||||
MiniAppReqTemplateParams
|
||||
} from "@/core/packet/client/entities/miniApp";
|
||||
} from "@/core/packet/entities/miniApp";
|
||||
|
||||
type MiniAppTemplateNameList = "bili" | "weibo";
|
||||
|
||||
|
@ -10,7 +10,8 @@ export abstract class GetPacketStatusDepends<PT, RT> extends BaseAction<PT, RT>
|
||||
// TODO: add error stack?
|
||||
return {
|
||||
valid: false,
|
||||
message: "packetBackend不可用,请参照文档 https://napneko.github.io/config/advanced 和启动日志检查packetBackend状态或进行配置!",
|
||||
message: "packetBackend不可用,请参照文档 https://napneko.github.io/config/advanced 和启动日志检查packetBackend状态或进行配置!" +
|
||||
"错误堆栈信息:" + this.core.apis.PacketApi.clientLogStack,
|
||||
};
|
||||
}
|
||||
return await super.check(payload);
|
||||
|
@ -83,7 +83,7 @@ export class NapCatOneBot11Adapter {
|
||||
async registerNative(core: NapCatCore, context: InstanceContext) {
|
||||
try {
|
||||
this.nativeCore = new Native(context.pathWrapper.binaryPath);
|
||||
if (!this.nativeCore.inited) throw new Error('Native Not Init');
|
||||
// if (!this.nativeCore.inited) throw new Error('Native Not Init');
|
||||
this.nativeCore.registerRecallCallback(async (hex: string) => {
|
||||
try {
|
||||
// TODO: refactor!
|
||||
@ -346,10 +346,10 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
};
|
||||
msgListener.onKickedOffLine = async (kick) => {
|
||||
let event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc);
|
||||
const event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc);
|
||||
this.networkManager.emitEvent(event)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理Bot掉线失败', e));
|
||||
}
|
||||
};
|
||||
this.context.session.getMsgService().addKernelMsgListener(
|
||||
proxiedListenerOf(msgListener, this.context.logger),
|
||||
);
|
||||
|
@ -232,7 +232,7 @@ export async function NCoreInitShell() {
|
||||
logger.log(`可用于快速登录的 QQ:\n${historyLoginList
|
||||
.map((u, index) => `${index + 1}. ${u.uin} ${u.nickName}`)
|
||||
.join('\n')
|
||||
}`);
|
||||
}`);
|
||||
}
|
||||
loginService.getQRCodePicture();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user