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 fs from 'node:fs';
|
||||
import { systemPlatform } from '@/common/utils/system';
|
||||
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
|
||||
import AppidTable from '@/core/external/appid.json';
|
||||
import { LogWrapper } from './log';
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import { systemPlatform } from "@/common/utils/system";
|
||||
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from "./helper";
|
||||
import AppidTable from "@/core/external/appid.json";
|
||||
import { LogWrapper } from "./log";
|
||||
|
||||
export class QQBasicInfoWrapper {
|
||||
QQMainPath: string | undefined;
|
||||
QQPackageInfoPath: string | undefined;
|
||||
QQVersionConfigPath: string | undefined;
|
||||
isQuickUpdate: boolean | undefined;
|
||||
QQVersionConfig: QQVersionConfigType | undefined;
|
||||
QQPackageInfo: QQPackageInfoType | undefined;
|
||||
QQVersionAppid: string | undefined;
|
||||
QQVersionQua: string | undefined;
|
||||
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);
|
||||
QQMainPath: string | undefined;
|
||||
QQPackageInfoPath: string | undefined;
|
||||
QQVersionConfigPath: string | undefined;
|
||||
isQuickUpdate: boolean | undefined;
|
||||
QQVersionConfig: QQVersionConfigType | undefined;
|
||||
QQPackageInfo: QQPackageInfoType | undefined;
|
||||
QQVersionAppid: string | undefined;
|
||||
QQVersionQua: string | undefined;
|
||||
context: { logger: LogWrapper };
|
||||
|
||||
//基础信息获取 无快更则启用默认模板填充
|
||||
this.isQuickUpdate = !!this.QQVersionConfigPath;
|
||||
this.QQVersionConfig = this.isQuickUpdate ? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
||||
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
|
||||
let { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
|
||||
this.QQVersionAppid = IQQVersionAppid;
|
||||
this.QQVersionQua = IQQVersionQua;
|
||||
}
|
||||
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);
|
||||
|
||||
//基础函数
|
||||
getQQBuildStr() {
|
||||
return this.isQuickUpdate ? this.QQVersionConfig?.buildId : this.QQPackageInfo?.buildVersion;
|
||||
}
|
||||
getFullQQVesion() { return this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.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;
|
||||
}
|
||||
//基础信息获取 无快更则启用默认模板填充
|
||||
this.isQuickUpdate = !!this.QQVersionConfigPath;
|
||||
this.QQVersionConfig = this.isQuickUpdate
|
||||
? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString())
|
||||
: getDefaultQQVersionConfigInfo();
|
||||
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
|
||||
let { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
|
||||
this.QQVersionAppid = IQQVersionAppid;
|
||||
this.QQVersionQua = IQQVersionQua;
|
||||
}
|
||||
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 path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as fsPromise from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
import crypto from "node:crypto";
|
||||
import path from "node:path";
|
||||
import fs from "fs";
|
||||
import * as fsPromise from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
|
||||
//下面这个类是用于将uid+msgid合并的类
|
||||
|
||||
export class UUIDConverter {
|
||||
static encode(highStr: string, lowStr: string): string {
|
||||
const high = BigInt(highStr);
|
||||
const low = BigInt(lowStr);
|
||||
const highHex = high.toString(16).padStart(16, '0');
|
||||
const lowHex = low.toString(16).padStart(16, '0');
|
||||
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)}`;
|
||||
return uuid;
|
||||
}
|
||||
static decode(uuid: string): { high: string, low: string } {
|
||||
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() };
|
||||
}
|
||||
static encode(highStr: string, lowStr: string): string {
|
||||
const high = BigInt(highStr);
|
||||
const low = BigInt(lowStr);
|
||||
const highHex = high.toString(16).padStart(16, "0");
|
||||
const lowHex = low.toString(16).padStart(16, "0");
|
||||
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)}`;
|
||||
return uuid;
|
||||
}
|
||||
static decode(uuid: string): { high: string; low: string } {
|
||||
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> {
|
||||
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> {
|
||||
const timeoutPromise = new Promise<T>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms)
|
||||
);
|
||||
return Promise.race([promise, timeoutPromise]);
|
||||
const timeoutPromise = new Promise<T>((_, reject) =>
|
||||
setTimeout(() => reject(new Error("PromiseTimer: Operation timed out")), ms)
|
||||
);
|
||||
return Promise.race([promise, timeoutPromise]);
|
||||
}
|
||||
export async function runAllWithTimeout<T>(tasks: Promise<T>[], timeout: number): Promise<T[]> {
|
||||
const wrappedTasks = tasks.map(task =>
|
||||
PromiseTimer(task, timeout).then(
|
||||
result => ({ status: 'fulfilled', value: result }),
|
||||
error => ({ status: 'rejected', reason: error })
|
||||
)
|
||||
);
|
||||
const results = await Promise.all(wrappedTasks);
|
||||
return results
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => (result as { status: 'fulfilled'; value: T }).value);
|
||||
const wrappedTasks = tasks.map((task) =>
|
||||
PromiseTimer(task, timeout).then(
|
||||
(result) => ({ status: "fulfilled", value: result }),
|
||||
(error) => ({ status: "rejected", reason: error })
|
||||
)
|
||||
);
|
||||
const results = await Promise.all(wrappedTasks);
|
||||
return results
|
||||
.filter((result) => result.status === "fulfilled")
|
||||
.map((result) => (result as { status: "fulfilled"; value: T }).value);
|
||||
}
|
||||
|
||||
export function getMd5(s: string) {
|
||||
|
||||
const h = crypto.createHash('md5');
|
||||
h.update(s);
|
||||
return h.digest('hex');
|
||||
const h = crypto.createHash("md5");
|
||||
h.update(s);
|
||||
return h.digest("hex");
|
||||
}
|
||||
|
||||
export function isNull(value: any) {
|
||||
return value === undefined || value === null;
|
||||
return value === undefined || value === null;
|
||||
}
|
||||
|
||||
export function isNumeric(str: string) {
|
||||
return /^\d+$/.test(str);
|
||||
return /^\d+$/.test(str);
|
||||
}
|
||||
|
||||
export function truncateString(obj: any, maxLength = 500) {
|
||||
if (obj !== null && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach(key => {
|
||||
if (typeof obj[key] === 'string') {
|
||||
// 如果是字符串且超过指定长度,则截断
|
||||
if (obj[key].length > maxLength) {
|
||||
obj[key] = obj[key].substring(0, maxLength) + '...';
|
||||
}
|
||||
} else if (typeof obj[key] === 'object') {
|
||||
// 如果是对象或数组,则递归调用
|
||||
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;
|
||||
if (obj !== null && typeof obj === "object") {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if (typeof obj[key] === "string") {
|
||||
// 如果是字符串且超过指定长度,则截断
|
||||
if (obj[key].length > maxLength) {
|
||||
obj[key] = obj[key].substring(0, maxLength) + "...";
|
||||
}
|
||||
} else if (typeof obj[key] === "object") {
|
||||
// 如果是对象或数组,则递归调用
|
||||
truncateString(obj[key], maxLength);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
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;
|
||||
return obj;
|
||||
}
|
||||
export function isEqual(obj1: any, obj2: any) {
|
||||
if (obj1 === obj2) return true;
|
||||
if (obj1 == null || obj2 == null) return false;
|
||||
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
|
||||
if (obj1 === obj2) return true;
|
||||
if (obj1 == null || obj2 == null) return false;
|
||||
if (typeof obj1 !== "object" || typeof obj2 !== "object") return obj1 === obj2;
|
||||
|
||||
const keys1 = Object.keys(obj1);
|
||||
const keys2 = Object.keys(obj2);
|
||||
const keys1 = Object.keys(obj1);
|
||||
const keys2 = Object.keys(obj2);
|
||||
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
|
||||
for (const key of keys1) {
|
||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
for (const key of keys1) {
|
||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
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 {
|
||||
baseVersion: '3.2.12-26702',
|
||||
curVersion: '3.2.12-26702',
|
||||
prevVersion: '',
|
||||
onErrorVersions: [],
|
||||
buildId: '26702'
|
||||
baseVersion: "9.9.15-26702",
|
||||
curVersion: "9.9.15-26702",
|
||||
prevVersion: "",
|
||||
onErrorVersions: [],
|
||||
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 {
|
||||
let configVersionInfoPath;
|
||||
if (os.platform() !== 'linux') {
|
||||
configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json');
|
||||
} else {
|
||||
const userPath = os.homedir();
|
||||
const appDataPath = path.resolve(userPath, './.config/QQ');
|
||||
configVersionInfoPath = path.resolve(appDataPath, './versions/config.json');
|
||||
}
|
||||
if (typeof configVersionInfoPath !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
if (!fs.existsSync(configVersionInfoPath)) {
|
||||
return undefined;
|
||||
}
|
||||
return configVersionInfoPath;
|
||||
export function getQQVersionConfigPath(exePath: string = ""): string | undefined {
|
||||
let configVersionInfoPath;
|
||||
if (os.platform() !== "linux") {
|
||||
configVersionInfoPath = path.join(path.dirname(exePath), "resources", "app", "versions", "config.json");
|
||||
} else {
|
||||
const userPath = os.homedir();
|
||||
const appDataPath = path.resolve(userPath, "./.config/QQ");
|
||||
configVersionInfoPath = path.resolve(appDataPath, "./versions/config.json");
|
||||
}
|
||||
if (typeof configVersionInfoPath !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
if (!fs.existsSync(configVersionInfoPath)) {
|
||||
return undefined;
|
||||
}
|
||||
return configVersionInfoPath;
|
||||
}
|
||||
|
||||
export async function deleteOldFiles(directoryPath: string, daysThreshold: number) {
|
||||
try {
|
||||
const files = await fsPromise.readdir(directoryPath);
|
||||
try {
|
||||
const files = await fsPromise.readdir(directoryPath);
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(directoryPath, file);
|
||||
const stats = await fsPromise.stat(filePath);
|
||||
const lastModifiedTime = stats.mtimeMs;
|
||||
const currentTime = Date.now();
|
||||
const timeDifference = currentTime - lastModifiedTime;
|
||||
const daysDifference = timeDifference / (1000 * 60 * 60 * 24);
|
||||
for (const file of files) {
|
||||
const filePath = path.join(directoryPath, file);
|
||||
const stats = await fsPromise.stat(filePath);
|
||||
const lastModifiedTime = stats.mtimeMs;
|
||||
const currentTime = Date.now();
|
||||
const timeDifference = currentTime - lastModifiedTime;
|
||||
const daysDifference = timeDifference / (1000 * 60 * 60 * 24);
|
||||
|
||||
if (daysDifference > daysThreshold) {
|
||||
await fsPromise.unlink(filePath); // Delete the file
|
||||
//console.log(`Deleted: ${filePath}`);
|
||||
}
|
||||
if (daysDifference > daysThreshold) {
|
||||
await fsPromise.unlink(filePath); // Delete the file
|
||||
//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();
|
||||
|
||||
|
||||
export const systemPlatform = os.platform();
|
||||
export const cpuArch = os.arch();
|
||||
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 { NodeIQQNTWrapperSession } from "./wrapper/wrapper";
|
||||
|
||||
export enum NCoreWorkMode {
|
||||
export enum NapCatCoreWorkingEnv {
|
||||
Unknown = 0,
|
||||
Shell = 1,
|
||||
LiteLoader = 2
|
||||
LiteLoader = 2,
|
||||
}
|
||||
export class NapCatCore {
|
||||
public WorkMode: NCoreWorkMode = NCoreWorkMode.Unknown;
|
||||
public isInit: boolean = false;
|
||||
public session: NodeIQQNTWrapperSession | undefined;
|
||||
private proxyHandler = {
|
||||
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;
|
||||
|
||||
export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
|
||||
let wrapperNodePath = path.resolve(path.dirname(process.execPath), './resources/app/wrapper.node');
|
||||
if (!fs.existsSync(wrapperNodePath)) {
|
||||
wrapperNodePath = path.join(path.dirname(process.execPath), `resources/app/versions/${QQVersion}/wrapper.node`);
|
||||
}
|
||||
const nativemodule: any = { exports: {} };
|
||||
process.dlopen(nativemodule, wrapperNodePath);
|
||||
return nativemodule.exports;
|
||||
}
|
||||
export class NapCatShell extends NapCatCore {
|
||||
public WorkMode: NCoreWorkMode = NCoreWorkMode.Shell;
|
||||
Init() {
|
||||
|
||||
export class NapCatCore {
|
||||
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 fs from 'node:fs';
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from "../adapters";
|
||||
import {
|
||||
NodeIDependsAdapter,
|
||||
NodeIDispatcherAdapter,
|
||||
NodeIGlobalAdapter,
|
||||
} from '../adapters';
|
||||
NodeIKernelSessionListener,
|
||||
NodeIKernelMsgListener,
|
||||
NodeIKernelLoginListener,
|
||||
NodeIKernelBuddyListener,
|
||||
NodeIKernelGroupListener,
|
||||
NodeIKernelProfileListener,
|
||||
} from "../listeners";
|
||||
import {
|
||||
NodeIKernelSessionListener,
|
||||
NodeIKernelMsgListener,
|
||||
NodeIKernelLoginListener,
|
||||
NodeIKernelBuddyListener,
|
||||
NodeIKernelGroupListener,
|
||||
NodeIKernelProfileListener,
|
||||
} from '../listeners';
|
||||
import {
|
||||
NodeIKernelLoginService,
|
||||
NodeIKernelMsgService,
|
||||
NodeIKernelBuddyService,
|
||||
NodeIKernelGroupService,
|
||||
NodeIKernelProfileService,
|
||||
NodeIKernelProfileLikeService,
|
||||
NodeIKernelTicketService,
|
||||
NodeIKernelTipOffService,
|
||||
NodeIKernelRichMediaService,
|
||||
NodeIKernelAvatarService,
|
||||
} from '../services';
|
||||
import { NodeIKernelStorageCleanService } from '../services/NodeIKernelStorageCleanService';
|
||||
import { NodeIKernelRobotService } from '../services/NodeIKernelRobotService';
|
||||
import { NodeIKernelNodeMiscService } from '../services/NodeIKernelNodeMiscService';
|
||||
import { NodeIKernelUixConvertService } from '../services/NodeIKernelUixConvertService';
|
||||
import { NodeIKernelMsgBackupService } from '../services/NodeIKernelMsgBackupService';
|
||||
import { NodeIKernelAlbumService } from '../services/NodeIKernelAlbumService';
|
||||
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';
|
||||
NodeIKernelLoginService,
|
||||
NodeIKernelMsgService,
|
||||
NodeIKernelBuddyService,
|
||||
NodeIKernelGroupService,
|
||||
NodeIKernelProfileService,
|
||||
NodeIKernelProfileLikeService,
|
||||
NodeIKernelTicketService,
|
||||
NodeIKernelTipOffService,
|
||||
NodeIKernelRichMediaService,
|
||||
NodeIKernelAvatarService,
|
||||
} from "../services";
|
||||
import { NodeIKernelStorageCleanService } from "../services/NodeIKernelStorageCleanService";
|
||||
import { NodeIKernelRobotService } from "../services/NodeIKernelRobotService";
|
||||
import { NodeIKernelNodeMiscService } from "../services/NodeIKernelNodeMiscService";
|
||||
import { NodeIKernelUixConvertService } from "../services/NodeIKernelUixConvertService";
|
||||
import { NodeIKernelMsgBackupService } from "../services/NodeIKernelMsgBackupService";
|
||||
import { NodeIKernelAlbumService } from "../services/NodeIKernelAlbumService";
|
||||
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 {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeQQNTWrapperUtil
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
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 {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeIQQNTWrapperSession;
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new (): NodeIQQNTWrapperSession;
|
||||
|
||||
init(
|
||||
wrapperSessionInitConfig: WrapperSessionInitConfig,
|
||||
nodeIDependsAdapter: NodeIDependsAdapter,
|
||||
nodeIDispatcherAdapter: NodeIDispatcherAdapter,
|
||||
nodeIKernelSessionListener: NodeIKernelSessionListener
|
||||
): void;
|
||||
init(
|
||||
wrapperSessionInitConfig: WrapperSessionInitConfig,
|
||||
nodeIDependsAdapter: NodeIDependsAdapter,
|
||||
nodeIDispatcherAdapter: NodeIDispatcherAdapter,
|
||||
nodeIKernelSessionListener: NodeIKernelSessionListener
|
||||
): void;
|
||||
|
||||
startNT(n: 0): void;
|
||||
startNT(n: 0): void;
|
||||
|
||||
startNT(): void;
|
||||
startNT(): void;
|
||||
|
||||
getBdhUploadService(): unknown;
|
||||
|
||||
getECDHService(): NodeIKernelECDHService;
|
||||
getBdhUploadService(): unknown;
|
||||
|
||||
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 {
|
||||
base_path_prefix: string,
|
||||
platform_type: 3,
|
||||
app_type: 4,
|
||||
app_version: string,
|
||||
os_version: string,
|
||||
use_xlog: true,
|
||||
qua: string,
|
||||
global_path_config: {
|
||||
desktopGlobalPath: string,
|
||||
},
|
||||
thumb_config: { maxSide: 324, minSide: 48, longLimit: 6, density: 2 }
|
||||
base_path_prefix: string;
|
||||
platform_type: 3;
|
||||
app_type: 4;
|
||||
app_version: string;
|
||||
os_version: string;
|
||||
use_xlog: true;
|
||||
qua: string;
|
||||
global_path_config: {
|
||||
desktopGlobalPath: string;
|
||||
};
|
||||
thumb_config: { maxSide: 324; minSide: 48; longLimit: 6; density: 2 };
|
||||
}
|
||||
|
||||
export interface NodeIQQNTWrapperEngine {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeIQQNTWrapperEngine;
|
||||
initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new (): NodeIQQNTWrapperEngine;
|
||||
initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void;
|
||||
}
|
||||
|
||||
export interface WrapperNodeApi {
|
||||
[key: string]: any;
|
||||
[key: string]: any;
|
||||
|
||||
NodeIKernelBuddyListener: NodeIKernelBuddyListener;
|
||||
NodeIKernelGroupListener: NodeIKernelGroupListener;
|
||||
NodeQQNTWrapperUtil: NodeQQNTWrapperUtil;
|
||||
NodeIQQNTWrapperSession: NodeIQQNTWrapperSession;
|
||||
NodeIKernelMsgListener: NodeIKernelMsgListener;
|
||||
NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine;
|
||||
NodeIGlobalAdapter: NodeIGlobalAdapter;
|
||||
NodeIDependsAdapter: NodeIDependsAdapter;
|
||||
NodeIDispatcherAdapter: NodeIDispatcherAdapter;
|
||||
NodeIKernelSessionListener: NodeIKernelSessionListener;
|
||||
NodeIKernelLoginService: NodeIKernelLoginService;
|
||||
NodeIKernelLoginListener: NodeIKernelLoginListener;
|
||||
NodeIKernelProfileService: NodeIKernelProfileService;
|
||||
NodeIKernelProfileListener: NodeIKernelProfileListener;
|
||||
NodeIKernelBuddyListener: NodeIKernelBuddyListener;
|
||||
NodeIKernelGroupListener: NodeIKernelGroupListener;
|
||||
NodeQQNTWrapperUtil: NodeQQNTWrapperUtil;
|
||||
NodeIQQNTWrapperSession: NodeIQQNTWrapperSession;
|
||||
NodeIKernelMsgListener: NodeIKernelMsgListener;
|
||||
NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine;
|
||||
NodeIGlobalAdapter: NodeIGlobalAdapter;
|
||||
NodeIDependsAdapter: NodeIDependsAdapter;
|
||||
NodeIDispatcherAdapter: NodeIDispatcherAdapter;
|
||||
NodeIKernelSessionListener: NodeIKernelSessionListener;
|
||||
NodeIKernelLoginService: NodeIKernelLoginService;
|
||||
NodeIKernelLoginListener: NodeIKernelLoginListener;
|
||||
NodeIKernelProfileService: NodeIKernelProfileService;
|
||||
NodeIKernelProfileListener: NodeIKernelProfileListener;
|
||||
}
|
||||
export enum PlatformType {
|
||||
KUNKNOWN,
|
||||
KANDROID,
|
||||
KIOS,
|
||||
KWINDOWS,
|
||||
KMAC
|
||||
KUNKNOWN,
|
||||
KANDROID,
|
||||
KIOS,
|
||||
KWINDOWS,
|
||||
KMAC,
|
||||
}
|
||||
export enum DeviceType {
|
||||
KUNKNOWN,
|
||||
KPHONE,
|
||||
KPAD,
|
||||
KCOMPUTER
|
||||
KUNKNOWN,
|
||||
KPHONE,
|
||||
KPAD,
|
||||
KCOMPUTER,
|
||||
}
|
||||
//推送类型
|
||||
export enum VendorType {
|
||||
KNOSETONIOS = 0,
|
||||
KSUPPORTGOOGLEPUSH = 99,
|
||||
KSUPPORTHMS = 3,
|
||||
KSUPPORTOPPOPUSH = 4,
|
||||
KSUPPORTTPNS = 2,
|
||||
KSUPPORTVIVOPUSH = 5,
|
||||
KUNSUPPORTANDROIDPUSH = 1
|
||||
KNOSETONIOS = 0,
|
||||
KSUPPORTGOOGLEPUSH = 99,
|
||||
KSUPPORTHMS = 3,
|
||||
KSUPPORTOPPOPUSH = 4,
|
||||
KSUPPORTTPNS = 2,
|
||||
KSUPPORTVIVOPUSH = 5,
|
||||
KUNSUPPORTANDROIDPUSH = 1,
|
||||
}
|
||||
export interface WrapperSessionInitConfig {
|
||||
selfUin: string
|
||||
selfUid: string
|
||||
desktopPathConfig: {
|
||||
account_path: string // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
|
||||
}
|
||||
clientVer: string // 9.9.8-22355
|
||||
a2: string,
|
||||
d2: string,
|
||||
d2Key: string,
|
||||
machineId: string,
|
||||
platform: PlatformType, // 3是Windows?
|
||||
platVer: string, // 系统版本号, 应该可以固定
|
||||
appid: string,
|
||||
rdeliveryConfig: {
|
||||
appKey: string,
|
||||
systemId: number,
|
||||
appId: string,
|
||||
logicEnvironment: string,
|
||||
platform: PlatformType,
|
||||
language: string,
|
||||
sdkVersion: string,
|
||||
userId: string,
|
||||
appVersion: string,
|
||||
osVersion: string,
|
||||
bundleId: string,
|
||||
serverUrl: string,
|
||||
fixedAfterHitKeys: string[]
|
||||
}
|
||||
defaultFileDownloadPath: string, // 这个可以通过环境变量获取?
|
||||
deviceInfo: {
|
||||
guid: string,
|
||||
buildVer: string,
|
||||
localId: number,
|
||||
devName: string,
|
||||
devType: string,
|
||||
vendorName: string,
|
||||
osVer: string,
|
||||
vendorOsName: string,
|
||||
setMute: boolean,
|
||||
vendorType: VendorType
|
||||
},
|
||||
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}'
|
||||
}
|
||||
selfUin: string;
|
||||
selfUid: string;
|
||||
desktopPathConfig: {
|
||||
account_path: string; // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
|
||||
};
|
||||
clientVer: string; // 9.9.8-22355
|
||||
a2: string;
|
||||
d2: string;
|
||||
d2Key: string;
|
||||
machineId: string;
|
||||
platform: PlatformType; // 3是Windows?
|
||||
platVer: string; // 系统版本号, 应该可以固定
|
||||
appid: string;
|
||||
rdeliveryConfig: {
|
||||
appKey: string;
|
||||
systemId: number;
|
||||
appId: string;
|
||||
logicEnvironment: string;
|
||||
platform: PlatformType;
|
||||
language: string;
|
||||
sdkVersion: string;
|
||||
userId: string;
|
||||
appVersion: string;
|
||||
osVersion: string;
|
||||
bundleId: string;
|
||||
serverUrl: string;
|
||||
fixedAfterHitKeys: string[];
|
||||
};
|
||||
defaultFileDownloadPath: string; // 这个可以通过环境变量获取?
|
||||
deviceInfo: {
|
||||
guid: string;
|
||||
buildVer: string;
|
||||
localId: number;
|
||||
devName: string;
|
||||
devType: string;
|
||||
vendorName: string;
|
||||
osVer: string;
|
||||
vendorOsName: string;
|
||||
setMute: boolean;
|
||||
vendorType: VendorType;
|
||||
};
|
||||
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入口文件
|
||||
export async function NCoreInitLiteLoader() {
|
||||
export async function NCoreInitLiteLoader(session: NodeIQQNTWrapperSession, loginService: NodeIKernelLoginService) {
|
||||
//在进入本层前是否登录未进行判断
|
||||
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 入口文件
|
||||
export async function NCoreInitShell() {
|
||||
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