mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-16 04:45:46 +00:00
chore: 进度提交
This commit is contained in:
parent
c417a95e1f
commit
c70b2eaa30
262
src/common/framework/event-legacy.ts
Normal file
262
src/common/framework/event-legacy.ts
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
import { NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper";
|
||||||
|
import { randomUUID } from "crypto";
|
||||||
|
|
||||||
|
interface Internal_MapKey {
|
||||||
|
timeout: number;
|
||||||
|
createtime: number;
|
||||||
|
func: (...arg: any[]) => any;
|
||||||
|
checker: ((...args: any[]) => boolean) | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListenerClassBase {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListenerIBase {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
|
new (listener: any): ListenerClassBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NTEventWrapper {
|
||||||
|
private ListenerMap: { [key: string]: ListenerIBase } | undefined; //ListenerName-Unique -> Listener构造函数
|
||||||
|
private WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
|
||||||
|
private ListenerManger: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
|
||||||
|
private EventTask = new Map<string, Map<string, Map<string, Internal_MapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||||
|
constructor() {}
|
||||||
|
createProxyDispatch(ListenerMainName: string) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
|
const current = this;
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target: any, prop: any, receiver: any) {
|
||||||
|
// console.log('get', prop, typeof target[prop]);
|
||||||
|
if (typeof target[prop] === "undefined") {
|
||||||
|
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||||
|
return (...args: any[]) => {
|
||||||
|
current.DispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 如果方法存在,正常返回
|
||||||
|
return Reflect.get(target, prop, receiver);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
init({
|
||||||
|
ListenerMap,
|
||||||
|
WrapperSession,
|
||||||
|
}: {
|
||||||
|
ListenerMap: { [key: string]: typeof ListenerClassBase };
|
||||||
|
WrapperSession: NodeIQQNTWrapperSession;
|
||||||
|
}) {
|
||||||
|
this.ListenerMap = ListenerMap;
|
||||||
|
this.WrapperSession = WrapperSession;
|
||||||
|
}
|
||||||
|
CreatEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||||
|
const eventNameArr = eventName.split("/");
|
||||||
|
type eventType = {
|
||||||
|
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> };
|
||||||
|
};
|
||||||
|
if (eventNameArr.length > 1) {
|
||||||
|
const serviceName = "get" + eventNameArr[0].replace("NodeIKernel", "");
|
||||||
|
const eventName = eventNameArr[1];
|
||||||
|
//getNodeIKernelGroupListener,GroupService
|
||||||
|
//console.log('2', eventName);
|
||||||
|
const services = (this.WrapperSession as unknown as eventType)[serviceName]();
|
||||||
|
let event = services[eventName];
|
||||||
|
//重新绑定this
|
||||||
|
event = event.bind(services);
|
||||||
|
if (event) {
|
||||||
|
return event as T;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CreatListenerFunction<T>(listenerMainName: string, uniqueCode: string = ""): T {
|
||||||
|
const ListenerType = this.ListenerMap![listenerMainName];
|
||||||
|
let Listener = this.ListenerManger.get(listenerMainName + uniqueCode);
|
||||||
|
if (!Listener && ListenerType) {
|
||||||
|
Listener = new ListenerType(this.createProxyDispatch(listenerMainName));
|
||||||
|
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1];
|
||||||
|
const Service = "NodeIKernel" + ServiceSubName + "Service/addKernel" + ServiceSubName + "Listener";
|
||||||
|
const addfunc = this.CreatEventFunction<(listener: T) => number>(Service);
|
||||||
|
addfunc!(Listener as T);
|
||||||
|
//console.log(addfunc!(Listener as T));
|
||||||
|
this.ListenerManger.set(listenerMainName + uniqueCode, Listener);
|
||||||
|
}
|
||||||
|
return Listener as T;
|
||||||
|
}
|
||||||
|
//统一回调清理事件
|
||||||
|
async DispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||||
|
//console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args);
|
||||||
|
this.EventTask.get(ListenerMainName)
|
||||||
|
?.get(ListenerSubName)
|
||||||
|
?.forEach((task, uuid) => {
|
||||||
|
//console.log(task.func, uuid, task.createtime, task.timeout);
|
||||||
|
if (task.createtime + task.timeout < Date.now()) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (task.checker && task.checker(...args)) {
|
||||||
|
task.func(...args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(
|
||||||
|
EventName = "",
|
||||||
|
timeout: number = 3000,
|
||||||
|
...args: Parameters<EventType>
|
||||||
|
) {
|
||||||
|
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||||
|
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
||||||
|
let complete = false;
|
||||||
|
const Timeouter = setTimeout(() => {
|
||||||
|
if (!complete) {
|
||||||
|
reject(new Error("NTEvent EventName:" + EventName + " timeout"));
|
||||||
|
}
|
||||||
|
}, timeout);
|
||||||
|
const retData = await EventFunc!(...args);
|
||||||
|
complete = true;
|
||||||
|
resolve(retData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async RegisterListen<ListenerType extends (...args: any[]) => void>(
|
||||||
|
ListenerName = "",
|
||||||
|
waitTimes = 1,
|
||||||
|
timeout = 5000,
|
||||||
|
checker: (...args: Parameters<ListenerType>) => boolean
|
||||||
|
) {
|
||||||
|
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||||
|
const ListenerNameList = ListenerName.split("/");
|
||||||
|
const ListenerMainName = ListenerNameList[0];
|
||||||
|
const ListenerSubName = ListenerNameList[1];
|
||||||
|
const id = randomUUID();
|
||||||
|
let complete = 0;
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error(" ListenerName:" + ListenerName + " timeout"));
|
||||||
|
} else {
|
||||||
|
resolve(retData!);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const Timeouter = setTimeout(databack, timeout);
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: Parameters<ListenerType>) => {
|
||||||
|
complete++;
|
||||||
|
retData = args;
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter);
|
||||||
|
databack();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (!this.EventTask.get(ListenerMainName)) {
|
||||||
|
this.EventTask.set(ListenerMainName, new Map());
|
||||||
|
}
|
||||||
|
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
|
||||||
|
}
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
||||||
|
this.CreatListenerFunction(ListenerMainName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async CallNormalEvent<
|
||||||
|
EventType extends (...args: any[]) => Promise<any>,
|
||||||
|
ListenerType extends (...args: any[]) => void
|
||||||
|
>(
|
||||||
|
EventName = "",
|
||||||
|
ListenerName = "",
|
||||||
|
waitTimes = 1,
|
||||||
|
timeout: number = 3000,
|
||||||
|
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||||
|
...args: Parameters<EventType>
|
||||||
|
) {
|
||||||
|
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
|
||||||
|
async (resolve, reject) => {
|
||||||
|
const id = randomUUID();
|
||||||
|
let complete = 0;
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||||
|
let retEvent: any = {};
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(
|
||||||
|
new Error(
|
||||||
|
"Timeout: NTEvent EventName:" +
|
||||||
|
EventName +
|
||||||
|
" ListenerName:" +
|
||||||
|
ListenerName +
|
||||||
|
" EventRet:\n" +
|
||||||
|
JSON.stringify(retEvent, null, 4) +
|
||||||
|
"\n"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ListenerNameList = ListenerName.split("/");
|
||||||
|
const ListenerMainName = ListenerNameList[0];
|
||||||
|
const ListenerSubName = ListenerNameList[1];
|
||||||
|
|
||||||
|
const Timeouter = setTimeout(databack, timeout);
|
||||||
|
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: any[]) => {
|
||||||
|
complete++;
|
||||||
|
//console.log('func', ...args);
|
||||||
|
retData = args as Parameters<ListenerType>;
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter);
|
||||||
|
databack();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (!this.EventTask.get(ListenerMainName)) {
|
||||||
|
this.EventTask.set(ListenerMainName, new Map());
|
||||||
|
}
|
||||||
|
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
|
||||||
|
}
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
||||||
|
this.CreatListenerFunction(ListenerMainName);
|
||||||
|
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
||||||
|
retEvent = await EventFunc!(...(args as any[]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const NTEventDispatch = new NTEventWrapper();
|
||||||
|
|
||||||
|
// 示例代码 快速创建事件
|
||||||
|
// let NTEvent = new NTEventWrapper();
|
||||||
|
// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise<Number>>('NodeIKernelProfileLikeService/GetTest');
|
||||||
|
// if (TestEvent) {
|
||||||
|
// TestEvent(true);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 示例代码 快速创建监听Listener类
|
||||||
|
// let NTEvent = new NTEventWrapper();
|
||||||
|
// NTEvent.CreatListenerFunction<NodeIKernelMsgListener>('NodeIKernelMsgListener', 'core')
|
||||||
|
|
||||||
|
// 调用接口
|
||||||
|
//let NTEvent = new NTEventWrapper();
|
||||||
|
//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise<Number>, (data1: string, data2: number) => void>('NodeIKernelProfileLikeService/GetTest', 'NodeIKernelMsgListener/onAddSendMsg', 1, 3000, true);
|
||||||
|
|
||||||
|
// 注册监听 解除监听
|
||||||
|
// NTEventDispatch.RigisterListener('NodeIKernelMsgListener/onAddSendMsg','core',cb);
|
||||||
|
// NTEventDispatch.UnRigisterListener('NodeIKernelMsgListener/onAddSendMsg','core');
|
||||||
|
|
||||||
|
// let GetTest = NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode);
|
||||||
|
// GetTest('test');
|
||||||
|
|
||||||
|
// always模式
|
||||||
|
// NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode,(...args:any[])=>{ console.log(args) });
|
138
src/common/framework/event.ts
Normal file
138
src/common/framework/event.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import type { NodeIQQNTWrapperSession, WrapperNodeApi } from "@/core/wrapper/wrapper";
|
||||||
|
import { randomUUID } from "node:crypto";
|
||||||
|
import EventEmitter from "node:events";
|
||||||
|
|
||||||
|
export type ListenerClassBase = Record<string, string>;
|
||||||
|
|
||||||
|
export interface ListenerIBase {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
|
new(listener: any): ListenerClassBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NTEventChannel extends EventEmitter {
|
||||||
|
private wrapperApi: WrapperNodeApi;
|
||||||
|
private wrapperSession: NodeIQQNTWrapperSession;
|
||||||
|
private listenerRefStorage = new Map<string, ListenerIBase>();
|
||||||
|
constructor(WrapperApi: WrapperNodeApi, WrapperSession: NodeIQQNTWrapperSession) {
|
||||||
|
super();
|
||||||
|
this.on('error', () => { });
|
||||||
|
this.wrapperApi = WrapperApi;
|
||||||
|
this.wrapperSession = WrapperSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcherListener(ListenerEvent: string, ...args: any[]) {
|
||||||
|
this.emit(ListenerEvent, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
createProxyDispatch(ListenerMainName: string) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
|
const current = this;
|
||||||
|
return new Proxy({}, {
|
||||||
|
get(_target: any, prop: any, _receiver: any) {
|
||||||
|
return (...args: any[]) => {
|
||||||
|
current.dispatcherListener.apply(current, [ListenerMainName + '/' + prop, ...args]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOrInitListener<T>(listenerMainName: string): Promise<T> {
|
||||||
|
const ListenerType = this.wrapperApi[listenerMainName];
|
||||||
|
//获取NTQQ 外部 Listener包装
|
||||||
|
if (!ListenerType) throw new Error('Init Listener not found');
|
||||||
|
let Listener = this.listenerRefStorage.get(listenerMainName);
|
||||||
|
//判断是否已创建 创建则跳过
|
||||||
|
if (!Listener && ListenerType) {
|
||||||
|
Listener = new ListenerType(this.createProxyDispatch(listenerMainName));
|
||||||
|
if (!Listener) throw new Error('Init Listener failed');
|
||||||
|
//实例化NTQQ Listener外包装
|
||||||
|
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1];
|
||||||
|
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener';
|
||||||
|
const addfunc = this.createEventFunction<(listener: T) => number>(Service);
|
||||||
|
//添加Listener到NTQQ
|
||||||
|
addfunc!(Listener as T);
|
||||||
|
this.listenerRefStorage.set(listenerMainName, Listener);
|
||||||
|
//保存Listener实例
|
||||||
|
}
|
||||||
|
return Listener as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createEventWithListener<EventType extends (...args: any) => any, ListenerType extends (...args: any) => any>
|
||||||
|
(
|
||||||
|
eventName: string,
|
||||||
|
listenerName: string,
|
||||||
|
waitTimes = 1,
|
||||||
|
timeout: number = 3000,
|
||||||
|
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||||
|
...eventArg: Parameters<EventType>
|
||||||
|
) {
|
||||||
|
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
||||||
|
const ListenerNameList = listenerName.split('/');
|
||||||
|
const ListenerMainName = ListenerNameList[0];
|
||||||
|
//const ListenerSubName = ListenerNameList[1];
|
||||||
|
this.getOrInitListener<ListenerType>(ListenerMainName);
|
||||||
|
let complete = 0;
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||||
|
let retEvent: any = {};
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error('Timeout: NTEvent EventName:' + eventName + ' ListenerName:' + listenerName + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n'));
|
||||||
|
} else {
|
||||||
|
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const Timeouter = setTimeout(databack, timeout);
|
||||||
|
let callback = (...args: Parameters<ListenerType>) => {
|
||||||
|
if (checker(...args)) {
|
||||||
|
complete++;
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter);
|
||||||
|
this.removeListener(listenerName, callback);
|
||||||
|
databack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.on(listenerName, callback);
|
||||||
|
const EventFunc = this.createEventFunction<EventType>(eventName);
|
||||||
|
retEvent = await EventFunc!(...(eventArg as any[]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private createEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||||
|
const eventNameArr = eventName.split('/');
|
||||||
|
type eventType = {
|
||||||
|
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }
|
||||||
|
}
|
||||||
|
if (eventNameArr.length > 1) {
|
||||||
|
const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '');
|
||||||
|
const eventName = eventNameArr[1];
|
||||||
|
//getNodeIKernelGroupListener,GroupService
|
||||||
|
//console.log('2', eventName);
|
||||||
|
const services = (this.wrapperSession as unknown as eventType)[serviceName]();
|
||||||
|
let event = services[eventName]
|
||||||
|
//重新绑定this
|
||||||
|
.bind(services);
|
||||||
|
if (event) {
|
||||||
|
return event as T;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async callEvent<EventType extends (...args: any[]) => Promise<any> | any>(
|
||||||
|
EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||||
|
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||||
|
const EventFunc = this.createEventFunction<EventType>(EventName);
|
||||||
|
let complete = false;
|
||||||
|
const Timeouter = setTimeout(() => {
|
||||||
|
if (!complete) {
|
||||||
|
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
|
||||||
|
}
|
||||||
|
}, timeout);
|
||||||
|
const retData = await EventFunc!(...args);
|
||||||
|
complete = true;
|
||||||
|
resolve(retData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//NTEvent2.0
|
14
src/common/framework/napcat.ts
Normal file
14
src/common/framework/napcat.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import path, { dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
export class NapCatPathWrapper {
|
||||||
|
binaryPath: string;
|
||||||
|
logsPath: string;
|
||||||
|
configPath: string;
|
||||||
|
|
||||||
|
constructor(mainPath: string = dirname(fileURLToPath(import.meta.url))) {
|
||||||
|
this.binaryPath = mainPath;
|
||||||
|
this.logsPath = path.join(this.binaryPath, "logs");
|
||||||
|
this.configPath = path.join(this.binaryPath, "config");
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
import path, { dirname } from "path";
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
class NapCatPathWrapper {
|
|
||||||
NapCat_Main_Path: string | undefined;
|
|
||||||
NapCat_Logs_Path: string | undefined;
|
|
||||||
NapCat_Config_Path: string | undefined;
|
|
||||||
constructor() { }
|
|
||||||
Init(MainPath: string = dirname(fileURLToPath(import.meta.url))) {
|
|
||||||
this.NapCat_Main_Path = MainPath;
|
|
||||||
this.NapCat_Logs_Path = path.join(this.NapCat_Main_Path, "logs");
|
|
||||||
this.NapCat_Config_Path = path.join(this.NapCat_Main_Path, "config");
|
|
||||||
}
|
|
||||||
getScriptPath() {
|
|
||||||
return this.NapCat_Main_Path;
|
|
||||||
}
|
|
||||||
getLogsPath() {
|
|
||||||
return this.NapCat_Logs_Path;
|
|
||||||
}
|
|
||||||
getConfigPath() {
|
|
||||||
return this.NapCat_Config_Path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export let NapCatPath: NapCatPathWrapper | undefined;
|
|
@ -1,67 +1,78 @@
|
|||||||
import path from 'node:path';
|
import path from "node:path";
|
||||||
import fs from 'node:fs';
|
import fs from "node:fs";
|
||||||
import { systemPlatform } from '@/common/utils/system';
|
import { systemPlatform } from "@/common/utils/system";
|
||||||
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
|
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from "./helper";
|
||||||
import AppidTable from '@/core/external/appid.json';
|
import AppidTable from "@/core/external/appid.json";
|
||||||
import { LogWrapper } from './log';
|
import { LogWrapper } from "./log";
|
||||||
|
|
||||||
export class QQBasicInfoWrapper {
|
export class QQBasicInfoWrapper {
|
||||||
QQMainPath: string | undefined;
|
QQMainPath: string | undefined;
|
||||||
QQPackageInfoPath: string | undefined;
|
QQPackageInfoPath: string | undefined;
|
||||||
QQVersionConfigPath: string | undefined;
|
QQVersionConfigPath: string | undefined;
|
||||||
isQuickUpdate: boolean | undefined;
|
isQuickUpdate: boolean | undefined;
|
||||||
QQVersionConfig: QQVersionConfigType | undefined;
|
QQVersionConfig: QQVersionConfigType | undefined;
|
||||||
QQPackageInfo: QQPackageInfoType | undefined;
|
QQPackageInfo: QQPackageInfoType | undefined;
|
||||||
QQVersionAppid: string | undefined;
|
QQVersionAppid: string | undefined;
|
||||||
QQVersionQua: string | undefined;
|
QQVersionQua: string | undefined;
|
||||||
context: { logger: LogWrapper; };
|
context: { logger: LogWrapper };
|
||||||
constructor(context: { logger: LogWrapper }) {
|
|
||||||
//基础目录获取
|
|
||||||
this.context = context;
|
|
||||||
this.QQMainPath = process.execPath;
|
|
||||||
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json');
|
|
||||||
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
|
|
||||||
|
|
||||||
//基础信息获取 无快更则启用默认模板填充
|
constructor(context: { logger: LogWrapper }) {
|
||||||
this.isQuickUpdate = !!this.QQVersionConfigPath;
|
//基础目录获取
|
||||||
this.QQVersionConfig = this.isQuickUpdate ? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
this.context = context;
|
||||||
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
|
this.QQMainPath = process.execPath;
|
||||||
let { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
|
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), "resources", "app", "package.json");
|
||||||
this.QQVersionAppid = IQQVersionAppid;
|
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
|
||||||
this.QQVersionQua = IQQVersionQua;
|
|
||||||
}
|
|
||||||
|
|
||||||
//基础函数
|
//基础信息获取 无快更则启用默认模板填充
|
||||||
getQQBuildStr() {
|
this.isQuickUpdate = !!this.QQVersionConfigPath;
|
||||||
return this.isQuickUpdate ? this.QQVersionConfig?.buildId : this.QQPackageInfo?.buildVersion;
|
this.QQVersionConfig = this.isQuickUpdate
|
||||||
}
|
? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString())
|
||||||
getFullQQVesion() { return this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version; }
|
: getDefaultQQVersionConfigInfo();
|
||||||
|
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
|
||||||
requireMinNTQQBuild(buildStr: string) {
|
let { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
|
||||||
let currentBuild = parseInt(this.getQQBuildStr() || '0')
|
this.QQVersionAppid = IQQVersionAppid;
|
||||||
if (currentBuild == 0) throw new Error('QQBuildStr获取失败')
|
this.QQVersionQua = IQQVersionQua;
|
||||||
return currentBuild >= parseInt(buildStr);
|
|
||||||
}
|
|
||||||
//此方法不要直接使用
|
|
||||||
getQUAInternal() {
|
|
||||||
return systemPlatform === 'linux' ? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
|
||||||
}
|
|
||||||
getAppidV2(): { appid: string, qua: string } {
|
|
||||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
|
||||||
try {
|
|
||||||
let fullVersion = this.getFullQQVesion();
|
|
||||||
if (!fullVersion) throw new Error('QQ版本获取失败');
|
|
||||||
const data = appidTbale[fullVersion];
|
|
||||||
if (data) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
|
||||||
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
//基础函数
|
||||||
|
getQQBuildStr() {
|
||||||
|
return this.isQuickUpdate ? this.QQVersionConfig?.buildId : this.QQPackageInfo?.buildVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFullQQVesion() {
|
||||||
|
let version = this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version;
|
||||||
|
if(!version) throw new Error("QQ版本获取失败");
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
requireMinNTQQBuild(buildStr: string) {
|
||||||
|
let currentBuild = parseInt(this.getQQBuildStr() || "0");
|
||||||
|
if (currentBuild == 0) throw new Error("QQBuildStr获取失败");
|
||||||
|
return currentBuild >= parseInt(buildStr);
|
||||||
|
}
|
||||||
|
//此方法不要直接使用
|
||||||
|
getQUAInternal() {
|
||||||
|
return systemPlatform === "linux"
|
||||||
|
? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`
|
||||||
|
: `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||||
|
}
|
||||||
|
getAppidV2(): { appid: string; qua: string } {
|
||||||
|
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||||
|
try {
|
||||||
|
let fullVersion = this.getFullQQVesion();
|
||||||
|
if (!fullVersion) throw new Error("QQ版本获取失败");
|
||||||
|
const data = appidTbale[fullVersion];
|
||||||
|
if (data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||||
|
}
|
||||||
|
// 以下是兜底措施
|
||||||
|
this.context.logger.log(
|
||||||
|
`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`
|
||||||
|
);
|
||||||
|
return { appid: systemPlatform === "linux" ? "537237950" : "537237765", qua: this.getQUAInternal() };
|
||||||
}
|
}
|
||||||
// 以下是兜底措施
|
|
||||||
this.context.logger.log(`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`);
|
|
||||||
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: this.getQUAInternal() };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export let QQBasicInfo: QQBasicInfoWrapper | undefined;
|
export let QQBasicInfo: QQBasicInfoWrapper | undefined;
|
||||||
|
@ -1,390 +1,154 @@
|
|||||||
import crypto from 'node:crypto';
|
import crypto from "node:crypto";
|
||||||
import path from 'node:path';
|
import path from "node:path";
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
import { dirname } from 'node:path';
|
import * as fsPromise from "node:fs/promises";
|
||||||
import { fileURLToPath } from 'node:url';
|
import os from "node:os";
|
||||||
import * as fsPromise from 'node:fs/promises';
|
|
||||||
import os from 'node:os';
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = dirname(__filename);
|
|
||||||
|
|
||||||
//下面这个类是用于将uid+msgid合并的类
|
//下面这个类是用于将uid+msgid合并的类
|
||||||
|
|
||||||
export class UUIDConverter {
|
export class UUIDConverter {
|
||||||
static encode(highStr: string, lowStr: string): string {
|
static encode(highStr: string, lowStr: string): string {
|
||||||
const high = BigInt(highStr);
|
const high = BigInt(highStr);
|
||||||
const low = BigInt(lowStr);
|
const low = BigInt(lowStr);
|
||||||
const highHex = high.toString(16).padStart(16, '0');
|
const highHex = high.toString(16).padStart(16, "0");
|
||||||
const lowHex = low.toString(16).padStart(16, '0');
|
const lowHex = low.toString(16).padStart(16, "0");
|
||||||
const combinedHex = highHex + lowHex;
|
const combinedHex = highHex + lowHex;
|
||||||
const uuid = `${combinedHex.substring(0, 8)}-${combinedHex.substring(8, 12)}-${combinedHex.substring(12, 16)}-${combinedHex.substring(16, 20)}-${combinedHex.substring(20)}`;
|
const uuid = `${combinedHex.substring(0, 8)}-${combinedHex.substring(8, 12)}-${combinedHex.substring(
|
||||||
return uuid;
|
12,
|
||||||
}
|
16
|
||||||
static decode(uuid: string): { high: string, low: string } {
|
)}-${combinedHex.substring(16, 20)}-${combinedHex.substring(20)}`;
|
||||||
const hex = uuid.replace(/-/g, '');
|
return uuid;
|
||||||
const high = BigInt('0x' + hex.substring(0, 16));
|
}
|
||||||
const low = BigInt('0x' + hex.substring(16));
|
static decode(uuid: string): { high: string; low: string } {
|
||||||
return { high: high.toString(), low: low.toString() };
|
const hex = uuid.replace(/-/g, "");
|
||||||
}
|
const high = BigInt("0x" + hex.substring(0, 16));
|
||||||
|
const low = BigInt("0x" + hex.substring(16));
|
||||||
|
return { high: high.toString(), low: low.toString() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function sleep(ms: number): Promise<void> {
|
export function sleep(ms: number): Promise<void> {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PromiseTimer<T>(promise: Promise<T>, ms: number): Promise<T> {
|
export function PromiseTimer<T>(promise: Promise<T>, ms: number): Promise<T> {
|
||||||
const timeoutPromise = new Promise<T>((_, reject) =>
|
const timeoutPromise = new Promise<T>((_, reject) =>
|
||||||
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms)
|
setTimeout(() => reject(new Error("PromiseTimer: Operation timed out")), ms)
|
||||||
);
|
);
|
||||||
return Promise.race([promise, timeoutPromise]);
|
return Promise.race([promise, timeoutPromise]);
|
||||||
}
|
}
|
||||||
export async function runAllWithTimeout<T>(tasks: Promise<T>[], timeout: number): Promise<T[]> {
|
export async function runAllWithTimeout<T>(tasks: Promise<T>[], timeout: number): Promise<T[]> {
|
||||||
const wrappedTasks = tasks.map(task =>
|
const wrappedTasks = tasks.map((task) =>
|
||||||
PromiseTimer(task, timeout).then(
|
PromiseTimer(task, timeout).then(
|
||||||
result => ({ status: 'fulfilled', value: result }),
|
(result) => ({ status: "fulfilled", value: result }),
|
||||||
error => ({ status: 'rejected', reason: error })
|
(error) => ({ status: "rejected", reason: error })
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const results = await Promise.all(wrappedTasks);
|
const results = await Promise.all(wrappedTasks);
|
||||||
return results
|
return results
|
||||||
.filter(result => result.status === 'fulfilled')
|
.filter((result) => result.status === "fulfilled")
|
||||||
.map(result => (result as { status: 'fulfilled'; value: T }).value);
|
.map((result) => (result as { status: "fulfilled"; value: T }).value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMd5(s: string) {
|
export function getMd5(s: string) {
|
||||||
|
const h = crypto.createHash("md5");
|
||||||
const h = crypto.createHash('md5');
|
h.update(s);
|
||||||
h.update(s);
|
return h.digest("hex");
|
||||||
return h.digest('hex');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNull(value: any) {
|
export function isNull(value: any) {
|
||||||
return value === undefined || value === null;
|
return value === undefined || value === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNumeric(str: string) {
|
export function isNumeric(str: string) {
|
||||||
return /^\d+$/.test(str);
|
return /^\d+$/.test(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function truncateString(obj: any, maxLength = 500) {
|
export function truncateString(obj: any, maxLength = 500) {
|
||||||
if (obj !== null && typeof obj === 'object') {
|
if (obj !== null && typeof obj === "object") {
|
||||||
Object.keys(obj).forEach(key => {
|
Object.keys(obj).forEach((key) => {
|
||||||
if (typeof obj[key] === 'string') {
|
if (typeof obj[key] === "string") {
|
||||||
// 如果是字符串且超过指定长度,则截断
|
// 如果是字符串且超过指定长度,则截断
|
||||||
if (obj[key].length > maxLength) {
|
if (obj[key].length > maxLength) {
|
||||||
obj[key] = obj[key].substring(0, maxLength) + '...';
|
obj[key] = obj[key].substring(0, maxLength) + "...";
|
||||||
}
|
}
|
||||||
} else if (typeof obj[key] === 'object') {
|
} else if (typeof obj[key] === "object") {
|
||||||
// 如果是对象或数组,则递归调用
|
// 如果是对象或数组,则递归调用
|
||||||
truncateString(obj[key], maxLength);
|
truncateString(obj[key], maxLength);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
export function simpleDecorator(target: any, context: any) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// export function CacheClassFunc(ttl: number = 3600 * 1000, customKey: string = '') {
|
|
||||||
// const cache = new Map<string, { expiry: number; value: any }>();
|
|
||||||
// return function CacheClassFuncDecorator(originalMethod: Function, context: ClassMethodDecoratorContext) {
|
|
||||||
// async function CacheClassFuncDecoratorInternal(this: any, ...args: any[]) {
|
|
||||||
// const key = `${customKey}${String(context.name)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
|
||||||
// const cachedValue = cache.get(key);
|
|
||||||
// if (cachedValue && cachedValue.expiry > Date.now()) {
|
|
||||||
// return cachedValue.value;
|
|
||||||
// }
|
|
||||||
// const result = originalMethod.call(this, ...args);
|
|
||||||
// cache.set(key, { expiry: Date.now() + ttl, value: result });
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
// return CacheClassFuncDecoratorInternal;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
export function CacheClassFuncAsync(ttl: number = 3600 * 1000, customKey: string = '') {
|
|
||||||
//console.log('CacheClassFuncAsync', ttl, customKey);
|
|
||||||
function logExecutionTime(target: any, methodName: string, descriptor: PropertyDescriptor) {
|
|
||||||
//console.log('logExecutionTime', target, methodName, descriptor);
|
|
||||||
const cache = new Map<string, { expiry: number; value: any }>();
|
|
||||||
const originalMethod = descriptor.value;
|
|
||||||
descriptor.value = async function (...args: any[]) {
|
|
||||||
const key = `${customKey}${String(methodName)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
|
||||||
cache.forEach((value, key) => {
|
|
||||||
if (value.expiry < Date.now()) {
|
|
||||||
cache.delete(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const cachedValue = cache.get(key);
|
|
||||||
if (cachedValue && cachedValue.expiry > Date.now()) {
|
|
||||||
return cachedValue.value;
|
|
||||||
}
|
|
||||||
// const start = Date.now();
|
|
||||||
const result = await originalMethod.apply(this, args);
|
|
||||||
// const end = Date.now();
|
|
||||||
// console.log(`Method ${methodName} executed in ${end - start} ms.`);
|
|
||||||
cache.set(key, { expiry: Date.now() + ttl, value: result });
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return logExecutionTime;
|
|
||||||
}
|
|
||||||
export function CacheClassFuncAsyncExtend(ttl: number = 3600 * 1000, customKey: string = '', checker: any = (...data: any[]) => { return true; }) {
|
|
||||||
//console.log('CacheClassFuncAsync', ttl, customKey);
|
|
||||||
function logExecutionTime(target: any, methodName: string, descriptor: PropertyDescriptor) {
|
|
||||||
//console.log('logExecutionTime', target, methodName, descriptor);
|
|
||||||
const cache = new Map<string, { expiry: number; value: any }>();
|
|
||||||
const originalMethod = descriptor.value;
|
|
||||||
descriptor.value = async function (...args: any[]) {
|
|
||||||
const key = `${customKey}${String(methodName)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
|
||||||
cache.forEach((value, key) => {
|
|
||||||
if (value.expiry < Date.now()) {
|
|
||||||
cache.delete(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const cachedValue = cache.get(key);
|
|
||||||
if (cachedValue && cachedValue.expiry > Date.now()) {
|
|
||||||
return cachedValue.value;
|
|
||||||
}
|
|
||||||
// const start = Date.now();
|
|
||||||
const result = await originalMethod.apply(this, args);
|
|
||||||
if (!checker(...args, result)) {
|
|
||||||
return result;//丢弃缓存
|
|
||||||
}
|
|
||||||
// const end = Date.now();
|
|
||||||
// console.log(`Method ${methodName} executed in ${end - start} ms.`);
|
|
||||||
cache.set(key, { expiry: Date.now() + ttl, value: result });
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return logExecutionTime;
|
|
||||||
}
|
|
||||||
// export function CacheClassFuncAsync(ttl: number = 3600 * 1000, customKey: string = ''): any {
|
|
||||||
// const cache = new Map<string, { expiry: number; value: any }>();
|
|
||||||
|
|
||||||
// // 注意:在JavaScript装饰器中,我们通常不直接处理ClassMethodDecoratorContext这样的类型,
|
|
||||||
// // 因为装饰器的参数通常是目标类(对于类装饰器)、属性名(对于属性装饰器)等。
|
|
||||||
// // 对于方法装饰器,我们关注的是方法本身及其描述符。
|
|
||||||
// // 但这里我们维持原逻辑,假设有一个自定义的处理上下文的方式。
|
|
||||||
|
|
||||||
// return function (originalMethod: Function): any {
|
|
||||||
// console.log(originalMethod);
|
|
||||||
// // 由于JavaScript装饰器原生不支持异步直接定义,我们保持async定义以便处理异步方法。
|
|
||||||
// async function decoratorWrapper(this: any, ...args: any[]): Promise<any> {
|
|
||||||
// console.log(...args);
|
|
||||||
// const key = `${customKey}${originalMethod.name}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
|
||||||
// const cachedValue = cache.get(key);
|
|
||||||
// // 遍历cache 清除expiry内容
|
|
||||||
// cache.forEach((value, key) => {
|
|
||||||
// if (value.expiry < Date.now()) {
|
|
||||||
// cache.delete(key);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// if (cachedValue && cachedValue.expiry > Date.now()) {
|
|
||||||
// return cachedValue.value;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 直接await异步方法的结果
|
|
||||||
// const result = await originalMethod.apply(this, args);
|
|
||||||
// cache.set(key, { expiry: Date.now() + ttl, value: result });
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 返回装饰后的方法,保持与原方法相同的名称和描述符(如果需要更精细的控制,可以考虑使用Object.getOwnPropertyDescriptor等)
|
|
||||||
// return decoratorWrapper;
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 函数缓存装饰器,根据方法名、参数、自定义key生成缓存键,在一定时间内返回缓存结果
|
|
||||||
* @param ttl 超时时间,单位毫秒
|
|
||||||
* @param customKey 自定义缓存键前缀,可为空,防止方法名参数名一致时导致缓存键冲突
|
|
||||||
* @returns 处理后缓存或调用原方法的结果
|
|
||||||
*/
|
|
||||||
export function cacheFunc(ttl: number, customKey: string = '') {
|
|
||||||
const cache = new Map<string, { expiry: number; value: any }>();
|
|
||||||
|
|
||||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
|
|
||||||
const originalMethod = descriptor.value;
|
|
||||||
const className = target.constructor.name; // 获取类名
|
|
||||||
const methodName = propertyKey; // 获取方法名
|
|
||||||
descriptor.value = async function (...args: any[]) {
|
|
||||||
const cacheKey = `${customKey}${className}.${methodName}:${JSON.stringify(args)}`;
|
|
||||||
const cached = cache.get(cacheKey);
|
|
||||||
if (cached && cached.expiry > Date.now()) {
|
|
||||||
return cached.value;
|
|
||||||
} else {
|
|
||||||
const result = await originalMethod.apply(this, args);
|
|
||||||
cache.set(cacheKey, { value: result, expiry: Date.now() + ttl });
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return descriptor;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export function isValidOldConfig(config: any) {
|
|
||||||
if (typeof config !== 'object') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const requiredKeys = [
|
|
||||||
'httpHost', 'httpPort', 'httpPostUrls', 'httpSecret',
|
|
||||||
'wsHost', 'wsPort', 'wsReverseUrls', 'enableHttp',
|
|
||||||
'enableHttpHeart', 'enableHttpPost', 'enableWs', 'enableWsReverse',
|
|
||||||
'messagePostFormat', 'reportSelfMessage', 'enableLocalFile2Url',
|
|
||||||
'debug', 'heartInterval', 'token', 'musicSignUrl'
|
|
||||||
];
|
|
||||||
for (const key of requiredKeys) {
|
|
||||||
if (!(key in config)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
return obj;
|
||||||
if (!Array.isArray(config.httpPostUrls) || !Array.isArray(config.wsReverseUrls)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (config.httpPostUrls.some((url: any) => typeof url !== 'string')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (config.wsReverseUrls.some((url: any) => typeof url !== 'string')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (typeof config.httpPort !== 'number' || typeof config.wsPort !== 'number' || typeof config.heartInterval !== 'number') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof config.enableHttp !== 'boolean' ||
|
|
||||||
typeof config.enableHttpHeart !== 'boolean' ||
|
|
||||||
typeof config.enableHttpPost !== 'boolean' ||
|
|
||||||
typeof config.enableWs !== 'boolean' ||
|
|
||||||
typeof config.enableWsReverse !== 'boolean' ||
|
|
||||||
typeof config.enableLocalFile2Url !== 'boolean' ||
|
|
||||||
typeof config.reportSelfMessage !== 'boolean'
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (config.messagePostFormat !== 'array' && config.messagePostFormat !== 'string') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
export function migrateConfig(oldConfig: any) {
|
|
||||||
const newConfig = {
|
|
||||||
http: {
|
|
||||||
enable: oldConfig.enableHttp,
|
|
||||||
host: oldConfig.httpHost,
|
|
||||||
port: oldConfig.httpPort,
|
|
||||||
secret: oldConfig.httpSecret,
|
|
||||||
enableHeart: oldConfig.enableHttpHeart,
|
|
||||||
enablePost: oldConfig.enableHttpPost,
|
|
||||||
postUrls: oldConfig.httpPostUrls,
|
|
||||||
},
|
|
||||||
ws: {
|
|
||||||
enable: oldConfig.enableWs,
|
|
||||||
host: oldConfig.wsHost,
|
|
||||||
port: oldConfig.wsPort,
|
|
||||||
},
|
|
||||||
reverseWs: {
|
|
||||||
enable: oldConfig.enableWsReverse,
|
|
||||||
urls: oldConfig.wsReverseUrls,
|
|
||||||
},
|
|
||||||
GroupLocalTime: {
|
|
||||||
Record: false,
|
|
||||||
RecordList: []
|
|
||||||
},
|
|
||||||
debug: oldConfig.debug,
|
|
||||||
heartInterval: oldConfig.heartInterval,
|
|
||||||
messagePostFormat: oldConfig.messagePostFormat,
|
|
||||||
enableLocalFile2Url: oldConfig.enableLocalFile2Url,
|
|
||||||
musicSignUrl: oldConfig.musicSignUrl,
|
|
||||||
reportSelfMessage: oldConfig.reportSelfMessage,
|
|
||||||
token: oldConfig.token,
|
|
||||||
|
|
||||||
};
|
|
||||||
return newConfig;
|
|
||||||
}
|
}
|
||||||
export function isEqual(obj1: any, obj2: any) {
|
export function isEqual(obj1: any, obj2: any) {
|
||||||
if (obj1 === obj2) return true;
|
if (obj1 === obj2) return true;
|
||||||
if (obj1 == null || obj2 == null) return false;
|
if (obj1 == null || obj2 == null) return false;
|
||||||
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
|
if (typeof obj1 !== "object" || typeof obj2 !== "object") return obj1 === obj2;
|
||||||
|
|
||||||
const keys1 = Object.keys(obj1);
|
const keys1 = Object.keys(obj1);
|
||||||
const keys2 = Object.keys(obj2);
|
const keys2 = Object.keys(obj2);
|
||||||
|
|
||||||
if (keys1.length !== keys2.length) return false;
|
if (keys1.length !== keys2.length) return false;
|
||||||
|
|
||||||
for (const key of keys1) {
|
for (const key of keys1) {
|
||||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
||||||
if (os.platform() === 'linux') {
|
if (os.platform() === "linux") {
|
||||||
|
return {
|
||||||
|
baseVersion: "3.2.12-26702",
|
||||||
|
curVersion: "3.2.12-26702",
|
||||||
|
prevVersion: "",
|
||||||
|
onErrorVersions: [],
|
||||||
|
buildId: "26702",
|
||||||
|
};
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
baseVersion: '3.2.12-26702',
|
baseVersion: "9.9.15-26702",
|
||||||
curVersion: '3.2.12-26702',
|
curVersion: "9.9.15-26702",
|
||||||
prevVersion: '',
|
prevVersion: "",
|
||||||
onErrorVersions: [],
|
onErrorVersions: [],
|
||||||
buildId: '26702'
|
buildId: "26702",
|
||||||
};
|
};
|
||||||
}
|
|
||||||
return {
|
|
||||||
baseVersion: '9.9.15-26702',
|
|
||||||
curVersion: '9.9.15-26702',
|
|
||||||
prevVersion: '',
|
|
||||||
onErrorVersions: [],
|
|
||||||
buildId: '26702'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export async function promisePipeline(promises: Promise<any>[], callback: (result: any) => boolean): Promise<void> {
|
|
||||||
let callbackCalled = false;
|
|
||||||
for (const promise of promises) {
|
|
||||||
if (callbackCalled) break;
|
|
||||||
try {
|
|
||||||
const result = await promise;
|
|
||||||
if (!callbackCalled) {
|
|
||||||
callbackCalled = callback(result);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in promise pipeline:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
|
export function getQQVersionConfigPath(exePath: string = ""): string | undefined {
|
||||||
let configVersionInfoPath;
|
let configVersionInfoPath;
|
||||||
if (os.platform() !== 'linux') {
|
if (os.platform() !== "linux") {
|
||||||
configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json');
|
configVersionInfoPath = path.join(path.dirname(exePath), "resources", "app", "versions", "config.json");
|
||||||
} else {
|
} else {
|
||||||
const userPath = os.homedir();
|
const userPath = os.homedir();
|
||||||
const appDataPath = path.resolve(userPath, './.config/QQ');
|
const appDataPath = path.resolve(userPath, "./.config/QQ");
|
||||||
configVersionInfoPath = path.resolve(appDataPath, './versions/config.json');
|
configVersionInfoPath = path.resolve(appDataPath, "./versions/config.json");
|
||||||
}
|
}
|
||||||
if (typeof configVersionInfoPath !== 'string') {
|
if (typeof configVersionInfoPath !== "string") {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (!fs.existsSync(configVersionInfoPath)) {
|
if (!fs.existsSync(configVersionInfoPath)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return configVersionInfoPath;
|
return configVersionInfoPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteOldFiles(directoryPath: string, daysThreshold: number) {
|
export async function deleteOldFiles(directoryPath: string, daysThreshold: number) {
|
||||||
try {
|
try {
|
||||||
const files = await fsPromise.readdir(directoryPath);
|
const files = await fsPromise.readdir(directoryPath);
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const filePath = path.join(directoryPath, file);
|
const filePath = path.join(directoryPath, file);
|
||||||
const stats = await fsPromise.stat(filePath);
|
const stats = await fsPromise.stat(filePath);
|
||||||
const lastModifiedTime = stats.mtimeMs;
|
const lastModifiedTime = stats.mtimeMs;
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
const timeDifference = currentTime - lastModifiedTime;
|
const timeDifference = currentTime - lastModifiedTime;
|
||||||
const daysDifference = timeDifference / (1000 * 60 * 60 * 24);
|
const daysDifference = timeDifference / (1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
if (daysDifference > daysThreshold) {
|
if (daysDifference > daysThreshold) {
|
||||||
await fsPromise.unlink(filePath); // Delete the file
|
await fsPromise.unlink(filePath); // Delete the file
|
||||||
//console.log(`Deleted: ${filePath}`);
|
//console.log(`Deleted: ${filePath}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
//console.error('Error deleting files:', error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
//console.error('Error deleting files:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
0
src/common/utils/proxy-handler.ts
Normal file
0
src/common/utils/proxy-handler.ts
Normal file
@ -65,7 +65,6 @@ async function getMacMachineId(): Promise<string | undefined> {
|
|||||||
|
|
||||||
const homeDir = os.homedir();
|
const homeDir = os.homedir();
|
||||||
|
|
||||||
|
|
||||||
export const systemPlatform = os.platform();
|
export const systemPlatform = os.platform();
|
||||||
export const cpuArch = os.arch();
|
export const cpuArch = os.arch();
|
||||||
export const systemVersion = os.release();
|
export const systemVersion = os.release();
|
||||||
|
@ -1,42 +1,49 @@
|
|||||||
import { logDebug } from "@/common/utils/log";
|
import { LogWrapper } from "@/common/utils/log";
|
||||||
|
import { NodeIQQNTWrapperSession, WrapperNodeApi } from "./wrapper/wrapper";
|
||||||
|
import path from "node:path";
|
||||||
|
import fs from "node:fs";
|
||||||
import { NodeIKernelLoginService } from "./services";
|
import { NodeIKernelLoginService } from "./services";
|
||||||
import { NodeIQQNTWrapperSession } from "./wrapper/wrapper";
|
|
||||||
|
|
||||||
export enum NCoreWorkMode {
|
export enum NapCatCoreWorkingEnv {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Shell = 1,
|
Shell = 1,
|
||||||
LiteLoader = 2
|
LiteLoader = 2,
|
||||||
}
|
}
|
||||||
export class NapCatCore {
|
|
||||||
public WorkMode: NCoreWorkMode = NCoreWorkMode.Unknown;
|
export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
|
||||||
public isInit: boolean = false;
|
let wrapperNodePath = path.resolve(path.dirname(process.execPath), './resources/app/wrapper.node');
|
||||||
public session: NodeIQQNTWrapperSession | undefined;
|
if (!fs.existsSync(wrapperNodePath)) {
|
||||||
private proxyHandler = {
|
wrapperNodePath = path.join(path.dirname(process.execPath), `resources/app/versions/${QQVersion}/wrapper.node`);
|
||||||
get(target: any, prop: any, receiver: any) {
|
|
||||||
// console.log('get', prop, typeof target[prop]);
|
|
||||||
if (typeof target[prop] === 'undefined') {
|
|
||||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
|
||||||
return (...args: unknown[]) => {
|
|
||||||
logDebug(`${target.constructor.name} has no method ${prop}`);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// 如果方法存在,正常返回
|
|
||||||
return Reflect.get(target, prop, receiver);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
get IsInit(): boolean {
|
|
||||||
return this.isInit;
|
|
||||||
}
|
}
|
||||||
|
const nativemodule: any = { exports: {} };
|
||||||
|
process.dlopen(nativemodule, wrapperNodePath);
|
||||||
|
return nativemodule.exports;
|
||||||
}
|
}
|
||||||
export class NapCatShell extends NapCatCore {
|
|
||||||
public WorkMode: NCoreWorkMode = NCoreWorkMode.Shell;
|
export class NapCatCore {
|
||||||
Init() {
|
readonly workingEnv: NapCatCoreWorkingEnv;
|
||||||
|
readonly wrapper: WrapperNodeApi;
|
||||||
|
readonly session: NodeIQQNTWrapperSession;
|
||||||
|
readonly logger: LogWrapper;
|
||||||
|
readonly loginService: NodeIKernelLoginService;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
env: NapCatCoreWorkingEnv,
|
||||||
|
wrapper: WrapperNodeApi,
|
||||||
|
session: NodeIQQNTWrapperSession,
|
||||||
|
logger: LogWrapper,
|
||||||
|
loginService: NodeIKernelLoginService,
|
||||||
|
QQVersion: string
|
||||||
|
) {
|
||||||
|
this.workingEnv = env;
|
||||||
|
this.logger = logger;
|
||||||
|
this.wrapper = wrapper;
|
||||||
|
this.session = session;
|
||||||
|
this.loginService = loginService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renamed from 'InitDataListener'
|
||||||
|
initNapCatCoreListeners() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class NapCatLiteLoader extends NapCatCore {
|
|
||||||
public WorkMode: NCoreWorkMode = NCoreWorkMode.LiteLoader;
|
|
||||||
Init(WrapperSession: NodeIQQNTWrapperSession, LoginService: NodeIKernelLoginService) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
0
src/core/index.ts
Normal file
0
src/core/index.ts
Normal file
8
src/core/wrapper/data.ts
Normal file
8
src/core/wrapper/data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { SelfInfo } from "../entities";
|
||||||
|
|
||||||
|
export const selfInfo: SelfInfo = {
|
||||||
|
uid: '',
|
||||||
|
uin: '',
|
||||||
|
nick: '',
|
||||||
|
online: true
|
||||||
|
};
|
55
src/core/wrapper/helper.ts
Normal file
55
src/core/wrapper/helper.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import { PlatformType, VendorType, WrapperSessionInitConfig } from "./wrapper";
|
||||||
|
import { getMachineId, hostname, systemName, systemVersion } from "@/common/utils/system";
|
||||||
|
|
||||||
|
export async function genSessionConfig(QQVersionAppid: string, QQVersion: string, selfUin: string, selfUid: string, account_path: string): Promise<WrapperSessionInitConfig> {
|
||||||
|
const downloadPath = path.join(account_path, 'NapCat', 'temp');
|
||||||
|
fs.mkdirSync(downloadPath, { recursive: true });
|
||||||
|
let guid: string = await getMachineId();//26702 支持JS获取guid值 在LoginService中获取 TODO mlikiow a
|
||||||
|
const config: WrapperSessionInitConfig = {
|
||||||
|
selfUin,
|
||||||
|
selfUid,
|
||||||
|
desktopPathConfig: {
|
||||||
|
account_path // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
|
||||||
|
},
|
||||||
|
clientVer: QQVersion, // 9.9.8-22355
|
||||||
|
a2: '',
|
||||||
|
d2: '',
|
||||||
|
d2Key: '',
|
||||||
|
machineId: '',
|
||||||
|
platform: PlatformType.KWINDOWS, // 3是Windows?
|
||||||
|
platVer: systemVersion, // 系统版本号, 应该可以固定
|
||||||
|
appid: QQVersionAppid,
|
||||||
|
rdeliveryConfig: {
|
||||||
|
appKey: '',
|
||||||
|
systemId: 0,
|
||||||
|
appId: '',
|
||||||
|
logicEnvironment: '',
|
||||||
|
platform: PlatformType.KWINDOWS,
|
||||||
|
language: '',
|
||||||
|
sdkVersion: '',
|
||||||
|
userId: '',
|
||||||
|
appVersion: '',
|
||||||
|
osVersion: '',
|
||||||
|
bundleId: '',
|
||||||
|
serverUrl: '',
|
||||||
|
fixedAfterHitKeys: ['']
|
||||||
|
},
|
||||||
|
defaultFileDownloadPath: downloadPath,
|
||||||
|
deviceInfo: {
|
||||||
|
guid,
|
||||||
|
buildVer: QQVersion,
|
||||||
|
localId: 2052,
|
||||||
|
devName: hostname,
|
||||||
|
devType: systemName,
|
||||||
|
vendorName: '',
|
||||||
|
osVer: systemVersion,
|
||||||
|
vendorOsName: systemName,
|
||||||
|
setMute: false,
|
||||||
|
vendorType: VendorType.KNOSETONIOS
|
||||||
|
},
|
||||||
|
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}'
|
||||||
|
};
|
||||||
|
return config;
|
||||||
|
}
|
@ -1,347 +1,361 @@
|
|||||||
import path from 'node:path';
|
import path from "node:path";
|
||||||
import fs from 'node:fs';
|
import fs from "node:fs";
|
||||||
|
import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from "../adapters";
|
||||||
import {
|
import {
|
||||||
NodeIDependsAdapter,
|
NodeIKernelSessionListener,
|
||||||
NodeIDispatcherAdapter,
|
NodeIKernelMsgListener,
|
||||||
NodeIGlobalAdapter,
|
NodeIKernelLoginListener,
|
||||||
} from '../adapters';
|
NodeIKernelBuddyListener,
|
||||||
|
NodeIKernelGroupListener,
|
||||||
|
NodeIKernelProfileListener,
|
||||||
|
} from "../listeners";
|
||||||
import {
|
import {
|
||||||
NodeIKernelSessionListener,
|
NodeIKernelLoginService,
|
||||||
NodeIKernelMsgListener,
|
NodeIKernelMsgService,
|
||||||
NodeIKernelLoginListener,
|
NodeIKernelBuddyService,
|
||||||
NodeIKernelBuddyListener,
|
NodeIKernelGroupService,
|
||||||
NodeIKernelGroupListener,
|
NodeIKernelProfileService,
|
||||||
NodeIKernelProfileListener,
|
NodeIKernelProfileLikeService,
|
||||||
} from '../listeners';
|
NodeIKernelTicketService,
|
||||||
import {
|
NodeIKernelTipOffService,
|
||||||
NodeIKernelLoginService,
|
NodeIKernelRichMediaService,
|
||||||
NodeIKernelMsgService,
|
NodeIKernelAvatarService,
|
||||||
NodeIKernelBuddyService,
|
} from "../services";
|
||||||
NodeIKernelGroupService,
|
import { NodeIKernelStorageCleanService } from "../services/NodeIKernelStorageCleanService";
|
||||||
NodeIKernelProfileService,
|
import { NodeIKernelRobotService } from "../services/NodeIKernelRobotService";
|
||||||
NodeIKernelProfileLikeService,
|
import { NodeIKernelNodeMiscService } from "../services/NodeIKernelNodeMiscService";
|
||||||
NodeIKernelTicketService,
|
import { NodeIKernelUixConvertService } from "../services/NodeIKernelUixConvertService";
|
||||||
NodeIKernelTipOffService,
|
import { NodeIKernelMsgBackupService } from "../services/NodeIKernelMsgBackupService";
|
||||||
NodeIKernelRichMediaService,
|
import { NodeIKernelAlbumService } from "../services/NodeIKernelAlbumService";
|
||||||
NodeIKernelAvatarService,
|
import { NodeIKernelTianShuService } from "../services/NodeIKernelTianShuService";
|
||||||
} from '../services';
|
import { NodeIKernelUnitedConfigService } from "../services/NodeIKernelUnitedConfigService";
|
||||||
import { NodeIKernelStorageCleanService } from '../services/NodeIKernelStorageCleanService';
|
import { NodeIKernelSearchService } from "../services/NodeIKernelSearchService";
|
||||||
import { NodeIKernelRobotService } from '../services/NodeIKernelRobotService';
|
import { NodeIKernelCollectionService } from "../services/NodeIKernelCollectionService";
|
||||||
import { NodeIKernelNodeMiscService } from '../services/NodeIKernelNodeMiscService';
|
import { NodeIKernelRecentContactService } from "../services/NodeIKernelRecentContactService";
|
||||||
import { NodeIKernelUixConvertService } from '../services/NodeIKernelUixConvertService';
|
import { NodeIKernelMSFService } from "../services/NodeIKernelMSFService";
|
||||||
import { NodeIKernelMsgBackupService } from '../services/NodeIKernelMsgBackupService';
|
import { NodeIkernelTestPerformanceService } from "../services/NodeIkernelTestPerformanceService";
|
||||||
import { NodeIKernelAlbumService } from '../services/NodeIKernelAlbumService';
|
import { NodeIKernelECDHService } from "../services/NodeIKernelECDHService";
|
||||||
import { NodeIKernelTianShuService } from '../services/NodeIKernelTianShuService';
|
|
||||||
import { NodeIKernelUnitedConfigService } from '../services/NodeIKernelUnitedConfigService';
|
|
||||||
import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService';
|
|
||||||
import { NodeIKernelCollectionService } from '../services/NodeIKernelCollectionService';
|
|
||||||
import { NodeIKernelRecentContactService } from '../services/NodeIKernelRecentContactService';
|
|
||||||
import { NodeIKernelMSFService } from '../services/NodeIKernelMSFService';
|
|
||||||
import { NodeIkernelTestPerformanceService } from '../services/NodeIkernelTestPerformanceService';
|
|
||||||
import { NodeIKernelECDHService } from '../services/NodeIKernelECDHService';
|
|
||||||
export interface NodeQQNTWrapperUtil {
|
export interface NodeQQNTWrapperUtil {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
new(): NodeQQNTWrapperUtil
|
new (): NodeQQNTWrapperUtil;
|
||||||
|
|
||||||
getNTUserDataInfoConfig(): string
|
getNTUserDataInfoConfig(): string;
|
||||||
|
|
||||||
emptyWorkingSet(n: number): void
|
emptyWorkingSet(n: number): void;
|
||||||
|
|
||||||
getSsoCmdOfOidbReq(arg1: number, arg2: number): unknown,
|
getSsoCmdOfOidbReq(arg1: number, arg2: number): unknown;
|
||||||
|
|
||||||
getSsoBufferOfOidbReq(...args: unknown[]): unknown,//有点看不懂参数定义 待补充 好像是三个参数
|
getSsoBufferOfOidbReq(...args: unknown[]): unknown; //有点看不懂参数定义 待补充 好像是三个参数
|
||||||
|
|
||||||
getOidbRspInfo(arg: string): unknown,//可能是错的
|
getOidbRspInfo(arg: string): unknown; //可能是错的
|
||||||
|
|
||||||
getFileSize(path: string): Promise<number>,//直接的猜测
|
getFileSize(path: string): Promise<number>; //直接的猜测
|
||||||
|
|
||||||
genFileMd5Buf(arg: string): unknown,//可能是错的
|
genFileMd5Buf(arg: string): unknown; //可能是错的
|
||||||
|
|
||||||
genFileMd5Hex(path: string): unknown,//直接的猜测
|
genFileMd5Hex(path: string): unknown; //直接的猜测
|
||||||
|
|
||||||
genFileShaBuf(path: string): unknown,//直接的猜测
|
genFileShaBuf(path: string): unknown; //直接的猜测
|
||||||
|
|
||||||
genFileCumulateSha1(path: string): unknown,//直接的猜测
|
genFileCumulateSha1(path: string): unknown; //直接的猜测
|
||||||
|
|
||||||
genFileShaHex(path: string): unknown,//直接的猜测
|
genFileShaHex(path: string): unknown; //直接的猜测
|
||||||
|
|
||||||
fileIsExist(path: string): unknown,
|
fileIsExist(path: string): unknown;
|
||||||
|
|
||||||
startTrace(path: string): unknown,//可能是错的
|
startTrace(path: string): unknown; //可能是错的
|
||||||
|
|
||||||
copyFile(src: string, dst: string): unknown,
|
copyFile(src: string, dst: string): unknown;
|
||||||
|
|
||||||
genFileShaAndMd5Hex(path: string, unknown: number): unknown,//可能是错的
|
genFileShaAndMd5Hex(path: string, unknown: number): unknown; //可能是错的
|
||||||
|
|
||||||
setTraceInfo(unknown: Object): unknown,
|
setTraceInfo(unknown: Object): unknown;
|
||||||
|
|
||||||
encodeOffLine(unknown: Object): unknown,
|
encodeOffLine(unknown: Object): unknown;
|
||||||
|
|
||||||
decodeOffLine(arg: string): unknown,//可能是错的 传递hex
|
decodeOffLine(arg: string): unknown; //可能是错的 传递hex
|
||||||
|
|
||||||
DecoderRecentInfo(arg: string): unknown,//可能是错的 传递hex
|
DecoderRecentInfo(arg: string): unknown; //可能是错的 传递hex
|
||||||
|
|
||||||
getPinyin(arg0: string, arg1: boolean): unknown,
|
getPinyin(arg0: string, arg1: boolean): unknown;
|
||||||
|
|
||||||
matchInPinyin(arg0: any[], arg1: string): unknown,//参数特复杂 arg0是个复杂数据类型
|
matchInPinyin(arg0: any[], arg1: string): unknown; //参数特复杂 arg0是个复杂数据类型
|
||||||
|
|
||||||
makeDirByPath(arg0: string): unknown,
|
makeDirByPath(arg0: string): unknown;
|
||||||
|
|
||||||
emptyWorkingSet(arg0: number): unknown,//参数是UINT32
|
emptyWorkingSet(arg0: number): unknown; //参数是UINT32
|
||||||
|
|
||||||
runProcess(arg0: string, arg1: boolean): unknown,
|
runProcess(arg0: string, arg1: boolean): unknown;
|
||||||
|
|
||||||
runProcessArgs(arg0: string, arg1: { [key: string]: string; }, arg2: boolean): unknown,
|
runProcessArgs(arg0: string, arg1: { [key: string]: string }, arg2: boolean): unknown;
|
||||||
|
|
||||||
calcThumbSize(arg0: number, arg1: number, arg2: Object): unknown,
|
calcThumbSize(arg0: number, arg1: number, arg2: Object): unknown;
|
||||||
|
|
||||||
fullWordToHalfWord(arg0: string): unknown,
|
fullWordToHalfWord(arg0: string): unknown;
|
||||||
|
|
||||||
getNTUserDataInfoConfig(): unknown,
|
getNTUserDataInfoConfig(): unknown;
|
||||||
|
|
||||||
pathIsReadableAndWriteable(path: string): unknown,//直接的猜测
|
pathIsReadableAndWriteable(path: string): unknown; //直接的猜测
|
||||||
|
|
||||||
resetUserDataSavePathToDocument(): unknown,
|
resetUserDataSavePathToDocument(): unknown;
|
||||||
|
|
||||||
getSoBuildInfo(): any,//例如 0[0]_d491dc01e0a_0
|
getSoBuildInfo(): any; //例如 0[0]_d491dc01e0a_0
|
||||||
|
|
||||||
registerCountInstruments(arg0: string, arg1: string[], arg2: number, arg3: number): unknown,
|
registerCountInstruments(arg0: string, arg1: string[], arg2: number, arg3: number): unknown;
|
||||||
|
|
||||||
registerValueInstruments(arg0: string, arg1: string[], arg2: number, arg3: number): unknown,
|
registerValueInstruments(arg0: string, arg1: string[], arg2: number, arg3: number): unknown;
|
||||||
|
|
||||||
registerValueInstrumentsWithBoundary(arg0: string, arg1: unknown, arg2: unknown, arg3: number, arg4: number): unknown,
|
registerValueInstrumentsWithBoundary(
|
||||||
|
arg0: string,
|
||||||
|
arg1: unknown,
|
||||||
|
arg2: unknown,
|
||||||
|
arg3: number,
|
||||||
|
arg4: number
|
||||||
|
): unknown;
|
||||||
|
|
||||||
reportCountIndicators(arg0: string, arg1: Map<unknown, unknown>, arg2: string, arg3: number, arg4: boolean): unknown,
|
reportCountIndicators(
|
||||||
|
arg0: string,
|
||||||
|
arg1: Map<unknown, unknown>,
|
||||||
|
arg2: string,
|
||||||
|
arg3: number,
|
||||||
|
arg4: boolean
|
||||||
|
): unknown;
|
||||||
|
|
||||||
reportValueIndicators(arg0: string, arg1: Map<unknown, unknown>, arg2: string, arg3: boolean, arg4: number): unknown,
|
reportValueIndicators(
|
||||||
|
arg0: string,
|
||||||
|
arg1: Map<unknown, unknown>,
|
||||||
|
arg2: string,
|
||||||
|
arg3: boolean,
|
||||||
|
arg4: number
|
||||||
|
): unknown;
|
||||||
|
|
||||||
checkNewUserDataSaveDirAvailable(arg0: string): unknown,
|
checkNewUserDataSaveDirAvailable(arg0: string): unknown;
|
||||||
|
|
||||||
copyUserData(arg0: string, arg1: string): Promise<any>,
|
copyUserData(arg0: string, arg1: string): Promise<any>;
|
||||||
|
|
||||||
setUserDataSaveDirectory(arg0: string): Promise<any>,
|
setUserDataSaveDirectory(arg0: string): Promise<any>;
|
||||||
|
|
||||||
hasOtherRunningQQProcess(): boolean,
|
hasOtherRunningQQProcess(): boolean;
|
||||||
|
|
||||||
quitAllRunningQQProcess(arg: boolean): unknown,
|
quitAllRunningQQProcess(arg: boolean): unknown;
|
||||||
|
|
||||||
checkNvidiaConfig(): unknown,
|
checkNvidiaConfig(): unknown;
|
||||||
|
|
||||||
repairNvidiaConfig(): unknown,
|
repairNvidiaConfig(): unknown;
|
||||||
|
|
||||||
getNvidiaDriverVersion(): unknown,
|
getNvidiaDriverVersion(): unknown;
|
||||||
|
|
||||||
isNull(): unknown
|
isNull(): unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeIQQNTWrapperSession {
|
export interface NodeIQQNTWrapperSession {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
new(): NodeIQQNTWrapperSession;
|
new (): NodeIQQNTWrapperSession;
|
||||||
|
|
||||||
init(
|
init(
|
||||||
wrapperSessionInitConfig: WrapperSessionInitConfig,
|
wrapperSessionInitConfig: WrapperSessionInitConfig,
|
||||||
nodeIDependsAdapter: NodeIDependsAdapter,
|
nodeIDependsAdapter: NodeIDependsAdapter,
|
||||||
nodeIDispatcherAdapter: NodeIDispatcherAdapter,
|
nodeIDispatcherAdapter: NodeIDispatcherAdapter,
|
||||||
nodeIKernelSessionListener: NodeIKernelSessionListener
|
nodeIKernelSessionListener: NodeIKernelSessionListener
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
startNT(n: 0): void;
|
startNT(n: 0): void;
|
||||||
|
|
||||||
startNT(): void;
|
startNT(): void;
|
||||||
|
|
||||||
getBdhUploadService(): unknown;
|
getBdhUploadService(): unknown;
|
||||||
|
|
||||||
getECDHService(): NodeIKernelECDHService;
|
|
||||||
|
|
||||||
getMsgService(): NodeIKernelMsgService;
|
getECDHService(): NodeIKernelECDHService;
|
||||||
|
|
||||||
getProfileService(): NodeIKernelProfileService;
|
getMsgService(): NodeIKernelMsgService;
|
||||||
|
|
||||||
getProfileLikeService(): NodeIKernelProfileLikeService;
|
getProfileService(): NodeIKernelProfileService;
|
||||||
|
|
||||||
getGroupService(): NodeIKernelGroupService;
|
getProfileLikeService(): NodeIKernelProfileLikeService;
|
||||||
|
|
||||||
getStorageCleanService(): NodeIKernelStorageCleanService;
|
getGroupService(): NodeIKernelGroupService;
|
||||||
|
|
||||||
getBuddyService(): NodeIKernelBuddyService;
|
getStorageCleanService(): NodeIKernelStorageCleanService;
|
||||||
|
|
||||||
getRobotService(): NodeIKernelRobotService;
|
getBuddyService(): NodeIKernelBuddyService;
|
||||||
|
|
||||||
getTicketService(): NodeIKernelTicketService;
|
getRobotService(): NodeIKernelRobotService;
|
||||||
|
|
||||||
getTipOffService(): NodeIKernelTipOffService;
|
getTicketService(): NodeIKernelTicketService;
|
||||||
|
|
||||||
getNodeMiscService(): NodeIKernelNodeMiscService;
|
getTipOffService(): NodeIKernelTipOffService;
|
||||||
|
|
||||||
getRichMediaService(): NodeIKernelRichMediaService;
|
getNodeMiscService(): NodeIKernelNodeMiscService;
|
||||||
|
|
||||||
getMsgBackupService(): NodeIKernelMsgBackupService;
|
getRichMediaService(): NodeIKernelRichMediaService;
|
||||||
|
|
||||||
getAlbumService(): NodeIKernelAlbumService;
|
getMsgBackupService(): NodeIKernelMsgBackupService;
|
||||||
|
|
||||||
getTianShuService(): NodeIKernelTianShuService;
|
getAlbumService(): NodeIKernelAlbumService;
|
||||||
|
|
||||||
getUnitedConfigService(): NodeIKernelUnitedConfigService;
|
getTianShuService(): NodeIKernelTianShuService;
|
||||||
|
|
||||||
getSearchService(): NodeIKernelSearchService;
|
getUnitedConfigService(): NodeIKernelUnitedConfigService;
|
||||||
|
|
||||||
getDirectSessionService(): unknown;
|
getSearchService(): NodeIKernelSearchService;
|
||||||
|
|
||||||
getRDeliveryService(): unknown;
|
getDirectSessionService(): unknown;
|
||||||
|
|
||||||
getAvatarService(): NodeIKernelAvatarService;
|
getRDeliveryService(): unknown;
|
||||||
|
|
||||||
getFeedChannelService(): unknown;
|
getAvatarService(): NodeIKernelAvatarService;
|
||||||
|
|
||||||
getYellowFaceService(): unknown;
|
getFeedChannelService(): unknown;
|
||||||
|
|
||||||
getCollectionService(): NodeIKernelCollectionService;
|
getYellowFaceService(): unknown;
|
||||||
|
|
||||||
getSettingService(): unknown;
|
getCollectionService(): NodeIKernelCollectionService;
|
||||||
|
|
||||||
getQiDianService(): unknown;
|
getSettingService(): unknown;
|
||||||
|
|
||||||
getFileAssistantService(): unknown;
|
getQiDianService(): unknown;
|
||||||
|
|
||||||
getGuildService(): unknown;
|
getFileAssistantService(): unknown;
|
||||||
|
|
||||||
getSkinService(): unknown;
|
getGuildService(): unknown;
|
||||||
|
|
||||||
getTestPerformanceService(): NodeIkernelTestPerformanceService;
|
getSkinService(): unknown;
|
||||||
|
|
||||||
getQQPlayService(): unknown;
|
getTestPerformanceService(): NodeIkernelTestPerformanceService;
|
||||||
|
|
||||||
getDbToolsService(): unknown;
|
getQQPlayService(): unknown;
|
||||||
|
|
||||||
getUixConvertService(): NodeIKernelUixConvertService;
|
getDbToolsService(): unknown;
|
||||||
|
|
||||||
getOnlineStatusService(): unknown;
|
getUixConvertService(): NodeIKernelUixConvertService;
|
||||||
|
|
||||||
getRemotingService(): unknown;
|
getOnlineStatusService(): unknown;
|
||||||
|
|
||||||
getGroupTabService(): unknown;
|
getRemotingService(): unknown;
|
||||||
|
|
||||||
getGroupSchoolService(): unknown;
|
getGroupTabService(): unknown;
|
||||||
|
|
||||||
getLiteBusinessService(): unknown;
|
getGroupSchoolService(): unknown;
|
||||||
|
|
||||||
getGuildMsgService(): unknown;
|
getLiteBusinessService(): unknown;
|
||||||
|
|
||||||
getLockService(): unknown;
|
getGuildMsgService(): unknown;
|
||||||
|
|
||||||
getMSFService(): NodeIKernelMSFService;
|
getLockService(): unknown;
|
||||||
|
|
||||||
getGuildHotUpdateService(): unknown;
|
getMSFService(): NodeIKernelMSFService;
|
||||||
|
|
||||||
getAVSDKService(): unknown;
|
getGuildHotUpdateService(): unknown;
|
||||||
|
|
||||||
getRecentContactService(): NodeIKernelRecentContactService;
|
getAVSDKService(): unknown;
|
||||||
|
|
||||||
getConfigMgrService(): unknown;
|
getRecentContactService(): NodeIKernelRecentContactService;
|
||||||
|
|
||||||
|
getConfigMgrService(): unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnginInitDesktopConfig {
|
export interface EnginInitDesktopConfig {
|
||||||
base_path_prefix: string,
|
base_path_prefix: string;
|
||||||
platform_type: 3,
|
platform_type: 3;
|
||||||
app_type: 4,
|
app_type: 4;
|
||||||
app_version: string,
|
app_version: string;
|
||||||
os_version: string,
|
os_version: string;
|
||||||
use_xlog: true,
|
use_xlog: true;
|
||||||
qua: string,
|
qua: string;
|
||||||
global_path_config: {
|
global_path_config: {
|
||||||
desktopGlobalPath: string,
|
desktopGlobalPath: string;
|
||||||
},
|
};
|
||||||
thumb_config: { maxSide: 324, minSide: 48, longLimit: 6, density: 2 }
|
thumb_config: { maxSide: 324; minSide: 48; longLimit: 6; density: 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeIQQNTWrapperEngine {
|
export interface NodeIQQNTWrapperEngine {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
new(): NodeIQQNTWrapperEngine;
|
new (): NodeIQQNTWrapperEngine;
|
||||||
initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void;
|
initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WrapperNodeApi {
|
export interface WrapperNodeApi {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
||||||
NodeIKernelBuddyListener: NodeIKernelBuddyListener;
|
NodeIKernelBuddyListener: NodeIKernelBuddyListener;
|
||||||
NodeIKernelGroupListener: NodeIKernelGroupListener;
|
NodeIKernelGroupListener: NodeIKernelGroupListener;
|
||||||
NodeQQNTWrapperUtil: NodeQQNTWrapperUtil;
|
NodeQQNTWrapperUtil: NodeQQNTWrapperUtil;
|
||||||
NodeIQQNTWrapperSession: NodeIQQNTWrapperSession;
|
NodeIQQNTWrapperSession: NodeIQQNTWrapperSession;
|
||||||
NodeIKernelMsgListener: NodeIKernelMsgListener;
|
NodeIKernelMsgListener: NodeIKernelMsgListener;
|
||||||
NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine;
|
NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine;
|
||||||
NodeIGlobalAdapter: NodeIGlobalAdapter;
|
NodeIGlobalAdapter: NodeIGlobalAdapter;
|
||||||
NodeIDependsAdapter: NodeIDependsAdapter;
|
NodeIDependsAdapter: NodeIDependsAdapter;
|
||||||
NodeIDispatcherAdapter: NodeIDispatcherAdapter;
|
NodeIDispatcherAdapter: NodeIDispatcherAdapter;
|
||||||
NodeIKernelSessionListener: NodeIKernelSessionListener;
|
NodeIKernelSessionListener: NodeIKernelSessionListener;
|
||||||
NodeIKernelLoginService: NodeIKernelLoginService;
|
NodeIKernelLoginService: NodeIKernelLoginService;
|
||||||
NodeIKernelLoginListener: NodeIKernelLoginListener;
|
NodeIKernelLoginListener: NodeIKernelLoginListener;
|
||||||
NodeIKernelProfileService: NodeIKernelProfileService;
|
NodeIKernelProfileService: NodeIKernelProfileService;
|
||||||
NodeIKernelProfileListener: NodeIKernelProfileListener;
|
NodeIKernelProfileListener: NodeIKernelProfileListener;
|
||||||
}
|
}
|
||||||
export enum PlatformType {
|
export enum PlatformType {
|
||||||
KUNKNOWN,
|
KUNKNOWN,
|
||||||
KANDROID,
|
KANDROID,
|
||||||
KIOS,
|
KIOS,
|
||||||
KWINDOWS,
|
KWINDOWS,
|
||||||
KMAC
|
KMAC,
|
||||||
}
|
}
|
||||||
export enum DeviceType {
|
export enum DeviceType {
|
||||||
KUNKNOWN,
|
KUNKNOWN,
|
||||||
KPHONE,
|
KPHONE,
|
||||||
KPAD,
|
KPAD,
|
||||||
KCOMPUTER
|
KCOMPUTER,
|
||||||
}
|
}
|
||||||
//推送类型
|
//推送类型
|
||||||
export enum VendorType {
|
export enum VendorType {
|
||||||
KNOSETONIOS = 0,
|
KNOSETONIOS = 0,
|
||||||
KSUPPORTGOOGLEPUSH = 99,
|
KSUPPORTGOOGLEPUSH = 99,
|
||||||
KSUPPORTHMS = 3,
|
KSUPPORTHMS = 3,
|
||||||
KSUPPORTOPPOPUSH = 4,
|
KSUPPORTOPPOPUSH = 4,
|
||||||
KSUPPORTTPNS = 2,
|
KSUPPORTTPNS = 2,
|
||||||
KSUPPORTVIVOPUSH = 5,
|
KSUPPORTVIVOPUSH = 5,
|
||||||
KUNSUPPORTANDROIDPUSH = 1
|
KUNSUPPORTANDROIDPUSH = 1,
|
||||||
}
|
}
|
||||||
export interface WrapperSessionInitConfig {
|
export interface WrapperSessionInitConfig {
|
||||||
selfUin: string
|
selfUin: string;
|
||||||
selfUid: string
|
selfUid: string;
|
||||||
desktopPathConfig: {
|
desktopPathConfig: {
|
||||||
account_path: string // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
|
account_path: string; // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
|
||||||
}
|
};
|
||||||
clientVer: string // 9.9.8-22355
|
clientVer: string; // 9.9.8-22355
|
||||||
a2: string,
|
a2: string;
|
||||||
d2: string,
|
d2: string;
|
||||||
d2Key: string,
|
d2Key: string;
|
||||||
machineId: string,
|
machineId: string;
|
||||||
platform: PlatformType, // 3是Windows?
|
platform: PlatformType; // 3是Windows?
|
||||||
platVer: string, // 系统版本号, 应该可以固定
|
platVer: string; // 系统版本号, 应该可以固定
|
||||||
appid: string,
|
appid: string;
|
||||||
rdeliveryConfig: {
|
rdeliveryConfig: {
|
||||||
appKey: string,
|
appKey: string;
|
||||||
systemId: number,
|
systemId: number;
|
||||||
appId: string,
|
appId: string;
|
||||||
logicEnvironment: string,
|
logicEnvironment: string;
|
||||||
platform: PlatformType,
|
platform: PlatformType;
|
||||||
language: string,
|
language: string;
|
||||||
sdkVersion: string,
|
sdkVersion: string;
|
||||||
userId: string,
|
userId: string;
|
||||||
appVersion: string,
|
appVersion: string;
|
||||||
osVersion: string,
|
osVersion: string;
|
||||||
bundleId: string,
|
bundleId: string;
|
||||||
serverUrl: string,
|
serverUrl: string;
|
||||||
fixedAfterHitKeys: string[]
|
fixedAfterHitKeys: string[];
|
||||||
}
|
};
|
||||||
defaultFileDownloadPath: string, // 这个可以通过环境变量获取?
|
defaultFileDownloadPath: string; // 这个可以通过环境变量获取?
|
||||||
deviceInfo: {
|
deviceInfo: {
|
||||||
guid: string,
|
guid: string;
|
||||||
buildVer: string,
|
buildVer: string;
|
||||||
localId: number,
|
localId: number;
|
||||||
devName: string,
|
devName: string;
|
||||||
devType: string,
|
devType: string;
|
||||||
vendorName: string,
|
vendorName: string;
|
||||||
osVer: string,
|
osVer: string;
|
||||||
vendorOsName: string,
|
vendorOsName: string;
|
||||||
setMute: boolean,
|
setMute: boolean;
|
||||||
vendorType: VendorType
|
vendorType: VendorType;
|
||||||
},
|
};
|
||||||
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}'
|
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}';
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,68 @@
|
|||||||
|
import { NTEventChannel } from "@/common/framework/event";
|
||||||
|
import { NapCatPathWrapper } from "@/common/framework/napcat";
|
||||||
|
import { sleep } from "@/common/utils/helper";
|
||||||
|
import { LogWrapper } from "@/common/utils/log";
|
||||||
|
import { proxiedListenerOf } from "@/common/utils/proxy-handler";
|
||||||
|
import { QQBasicInfoWrapper } from "@/common/utils/QQBasicInfo";
|
||||||
|
import { NapCatCoreWorkingEnv, loadQQWrapper } from "@/core/core";
|
||||||
|
import { LoginListener } from "@/core/listeners";
|
||||||
|
import { NodeIKernelLoginService } from "@/core/services";
|
||||||
|
import { selfInfo } from "@/core/wrapper/data";
|
||||||
|
import { WrapperNodeApi, NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper";
|
||||||
|
import { NapCatOneBot11Adapter } from "@/onebot";
|
||||||
|
|
||||||
//LiteLoader ES入口文件
|
//LiteLoader ES入口文件
|
||||||
export async function NCoreInitLiteLoader() {
|
export async function NCoreInitLiteLoader(session: NodeIQQNTWrapperSession, loginService: NodeIKernelLoginService) {
|
||||||
|
//在进入本层前是否登录未进行判断
|
||||||
console.log("NapCat LiteLoader App Loading...");
|
console.log("NapCat LiteLoader App Loading...");
|
||||||
}
|
let Basicframework = new NapCatPathWrapper();
|
||||||
|
let logger = new LogWrapper(Basicframework.logsPath);
|
||||||
|
let BasicInfo = new QQBasicInfoWrapper({ logger });
|
||||||
|
let LLNC = new NapCatLiteLoader(logger, session, loginService, BasicInfo);
|
||||||
|
|
||||||
|
//直到登录成功后,执行下一步
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
let OBLoginListener = new LoginListener();
|
||||||
|
OBLoginListener.onQRCodeLoginSucceed = async (arg) => resolve();
|
||||||
|
loginService.addKernelLoginListener(new LLNC.wrapper.NodeIKernelLoginListener(proxiedListenerOf(OBLoginListener, logger)));
|
||||||
|
});
|
||||||
|
//启动WebUi
|
||||||
|
|
||||||
|
//初始化LLNC的Onebot实现
|
||||||
|
new NapCatOneBot11Adapter();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NapCatLiteLoader {
|
||||||
|
public workingEnv: NapCatCoreWorkingEnv = NapCatCoreWorkingEnv.LiteLoader;
|
||||||
|
public wrapper: WrapperNodeApi;
|
||||||
|
public EventChannel: NTEventChannel;
|
||||||
|
public session: NodeIQQNTWrapperSession;
|
||||||
|
public logger: LogWrapper;
|
||||||
|
public loginListener: LoginListener;
|
||||||
|
//public core: NapCatCore;
|
||||||
|
constructor(
|
||||||
|
logger: LogWrapper,
|
||||||
|
session: NodeIQQNTWrapperSession,
|
||||||
|
loginService: NodeIKernelLoginService,
|
||||||
|
QQBasic: QQBasicInfoWrapper
|
||||||
|
) {
|
||||||
|
this.session = session;
|
||||||
|
this.logger = logger;
|
||||||
|
//context保存
|
||||||
|
this.wrapper = loadQQWrapper(QQBasic.getFullQQVesion());
|
||||||
|
//载入Wrapper.node
|
||||||
|
this.EventChannel = new NTEventChannel(this.wrapper, session);
|
||||||
|
this.loginListener = new LoginListener();
|
||||||
|
this.loginListener.onQRCodeLoginSucceed = async (arg) => {
|
||||||
|
await sleep(2500); // TODO: 等待登录完成 init那堆不知道多久完成 搞清楚之前先用个sleep 2500顶着
|
||||||
|
selfInfo.uin = arg.uin;
|
||||||
|
selfInfo.uid = arg.uid;
|
||||||
|
// 保存基础登录信息
|
||||||
|
// 初始化DataListener
|
||||||
|
};
|
||||||
|
loginService.addKernelLoginListener(new this.wrapper.NodeIKernelLoginListener(
|
||||||
|
proxiedListenerOf(this.loginListener, logger)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1 +1,4 @@
|
|||||||
//OneBot实现类
|
//OneBot实现类
|
||||||
|
export class NapCatOneBot11Adapter{
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,127 @@
|
|||||||
|
import { NapCatPathWrapper } from "@/common/framework/napcat";
|
||||||
|
import { LogWrapper } from "@/common/utils/log";
|
||||||
|
import { QQBasicInfoWrapper } from "@/common/utils/QQBasicInfo";
|
||||||
|
import { hostname, systemVersion } from "@/common/utils/system";
|
||||||
|
import { DependsAdapter, DispatcherAdapter, GlobalAdapter } from "@/core/adapters";
|
||||||
|
import { NapCatCoreWorkingEnv, NapCatCore, loadQQWrapper } from "@/core/core";
|
||||||
|
import { LoginListener, SessionListener } from "@/core/listeners";
|
||||||
|
import { NodeIKernelLoginService } from "@/core/services";
|
||||||
|
import { WrapperNodeApi, NodeIQQNTWrapperEngine, NodeQQNTWrapperUtil, NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper";
|
||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
import os from "os";
|
||||||
|
import { genSessionConfig } from "@/core/wrapper/helper";
|
||||||
|
import { selfInfo } from "@/core/wrapper/data";
|
||||||
|
|
||||||
// NapCat Shell App ES 入口文件
|
// NapCat Shell App ES 入口文件
|
||||||
export async function NCoreInitShell() {
|
export async function NCoreInitShell() {
|
||||||
console.log("NapCat Shell App Loading...");
|
console.log("NapCat Shell App Loading...");
|
||||||
}
|
let Basicframework = new NapCatPathWrapper();
|
||||||
|
let logger = new LogWrapper(Basicframework.logsPath);
|
||||||
|
let BasicInfo = new QQBasicInfoWrapper({ logger });
|
||||||
|
new NapCatShell(logger, BasicInfo);
|
||||||
|
}
|
||||||
|
export class NapCatShell {
|
||||||
|
public QQWrapper: WrapperNodeApi;
|
||||||
|
public WorkMode: NapCatCoreWorkingEnv = NapCatCoreWorkingEnv.Shell;
|
||||||
|
public Core: NapCatCore | undefined;
|
||||||
|
public engine: NodeIQQNTWrapperEngine;
|
||||||
|
public util: NodeQQNTWrapperUtil;
|
||||||
|
loginService: NodeIKernelLoginService;
|
||||||
|
session: NodeIQQNTWrapperSession;
|
||||||
|
loginListener: LoginListener;
|
||||||
|
|
||||||
|
get dataPath(): string {
|
||||||
|
let result = this.util.getNTUserDataInfoConfig();
|
||||||
|
if (!result) {
|
||||||
|
result = path.resolve(os.homedir(), './.config/QQ');
|
||||||
|
fs.mkdirSync(result, { recursive: true });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dataPathGlobal(): string {
|
||||||
|
return path.resolve(this.dataPath, './nt_qq/global');
|
||||||
|
}
|
||||||
|
private initSession(BasicInfo: QQBasicInfoWrapper, uin: string, uid: string): Promise<number> {
|
||||||
|
return new Promise(async (res, rej) => {
|
||||||
|
if (!BasicInfo.QQVersionAppid) throw new Error("QQVersionAppid must be provided");
|
||||||
|
const sessionConfig = await genSessionConfig(BasicInfo.QQVersionAppid, BasicInfo.getFullQQVesion(), uin, uid, this.dataPath);
|
||||||
|
const sessionListener = new SessionListener();
|
||||||
|
sessionListener.onSessionInitComplete = (r: unknown) => {
|
||||||
|
if ((r as number) === 0) {
|
||||||
|
return res(0);
|
||||||
|
}
|
||||||
|
rej(r);
|
||||||
|
};
|
||||||
|
// const oldOnSendOidbRepl = this.session.onSendOidbRepl;
|
||||||
|
// this.session.onSendOidbRepl = (...args: unknown[]) => {
|
||||||
|
// console.log('onSendOidbRepl', args);
|
||||||
|
// return oldOnSendOidbRepl(...args);
|
||||||
|
// };
|
||||||
|
this.session.init(sessionConfig,
|
||||||
|
new this.QQWrapper.NodeIDependsAdapter(new DependsAdapter()),
|
||||||
|
new this.QQWrapper.NodeIDispatcherAdapter(new DispatcherAdapter()),
|
||||||
|
new this.QQWrapper.NodeIKernelSessionListener(sessionListener)
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
this.session.startNT(0);
|
||||||
|
} catch (__) { /* Empty */
|
||||||
|
try {
|
||||||
|
this.session.startNT();
|
||||||
|
} catch (e) {
|
||||||
|
rej('init failed ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
constructor(logger: LogWrapper, QQBasic: QQBasicInfoWrapper) {
|
||||||
|
this.QQWrapper = loadQQWrapper(QQBasic.getFullQQVesion());
|
||||||
|
this.engine = new this.QQWrapper.NodeIQQNTWrapperEngine();
|
||||||
|
this.util = new this.QQWrapper.NodeQQNTWrapperUtil();
|
||||||
|
this.loginService = new this.QQWrapper.NodeIKernelLoginService();
|
||||||
|
this.session = new this.QQWrapper.NodeIQQNTWrapperSession();
|
||||||
|
this.loginListener = new LoginListener();
|
||||||
|
this.loginListener.onUserLoggedIn = (userid: string) => {
|
||||||
|
logger.logError('当前账号(' + userid + ')已登录,无法重复登录');
|
||||||
|
};
|
||||||
|
this.initConfig(QQBasic.getFullQQVesion(), QQBasic.QQVersionAppid, QQBasic.QQVersionQua);
|
||||||
|
this.loginListener.onQRCodeLoginSucceed = (arg) => {
|
||||||
|
this.initSession(QQBasic, arg.uin, arg.uid).then((r) => {
|
||||||
|
selfInfo.uin = arg.uin;
|
||||||
|
selfInfo.uid = arg.uid;
|
||||||
|
const dataPath = path.resolve(this.dataPath, './NapCat/data');
|
||||||
|
fs.mkdirSync(dataPath, { recursive: true });
|
||||||
|
logger.logDebug('本账号数据/缓存目录:', dataPath);
|
||||||
|
//this.initDataListener();
|
||||||
|
}).catch((e) => {
|
||||||
|
logger.logError('initSession failed', e);
|
||||||
|
throw new Error(`启动失败: ${JSON.stringify(e)}`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
initConfig(QQVersion: string | undefined, QQVersionAppid: string | undefined, QQVersionQua: string | undefined) {
|
||||||
|
if (!QQVersion || !QQVersionAppid || !QQVersionQua) throw new Error('QQVersion, QQVersionAppid, QQVersionQua must be provided');
|
||||||
|
this.engine.initWithDeskTopConfig({
|
||||||
|
base_path_prefix: '',
|
||||||
|
platform_type: 3,
|
||||||
|
app_type: 4,
|
||||||
|
app_version: QQVersion,
|
||||||
|
os_version: 'Windows 10 Pro',
|
||||||
|
use_xlog: true,
|
||||||
|
qua: QQVersionQua,
|
||||||
|
global_path_config: {
|
||||||
|
desktopGlobalPath: this.dataPathGlobal,
|
||||||
|
},
|
||||||
|
thumb_config: { maxSide: 324, minSide: 48, longLimit: 6, density: 2 }
|
||||||
|
}, new this.QQWrapper.NodeIGlobalAdapter(new GlobalAdapter()));
|
||||||
|
this.loginService.initConfig({
|
||||||
|
machineId: '',
|
||||||
|
appid: QQVersionAppid,
|
||||||
|
platVer: systemVersion,
|
||||||
|
commonPath: this.dataPathGlobal,
|
||||||
|
clientVer: QQVersion,
|
||||||
|
hostName: hostname
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user