mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-06 13:05:09 +00:00
refactor: init
This commit is contained in:
@@ -1,132 +0,0 @@
|
||||
import express, { Express, Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import http from 'http';
|
||||
import { log, logDebug, logError } from '../utils/log';
|
||||
import { ob11Config } from '@/onebot11/config';
|
||||
|
||||
type RegisterHandler = (res: Response, payload: any) => Promise<any>
|
||||
|
||||
export abstract class HttpServerBase {
|
||||
name: string = 'NapCatQQ';
|
||||
private readonly expressAPP: Express;
|
||||
private _server: http.Server | null = null;
|
||||
|
||||
public get server(): http.Server | null {
|
||||
return this._server;
|
||||
}
|
||||
|
||||
private set server(value: http.Server | null) {
|
||||
this._server = value;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.expressAPP = express();
|
||||
this.expressAPP.use(cors());
|
||||
this.expressAPP.use(express.urlencoded({ extended: true, limit: '5000mb' }));
|
||||
this.expressAPP.use((req, res, next) => {
|
||||
// 兼容处理没有带content-type的请求
|
||||
// log("req.headers['content-type']", req.headers['content-type'])
|
||||
req.headers['content-type'] = 'application/json';
|
||||
const originalJson = express.json({ limit: '5000mb' });
|
||||
// 调用原始的express.json()处理器
|
||||
originalJson(req, res, (err) => {
|
||||
if (err) {
|
||||
logError('Error parsing JSON:', err);
|
||||
return res.status(400).send('Invalid JSON');
|
||||
}
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
authorize(req: Request, res: Response, next: () => void) {
|
||||
const serverToken = ob11Config.token;
|
||||
let clientToken = '';
|
||||
const authHeader = req.get('authorization');
|
||||
if (authHeader) {
|
||||
clientToken = authHeader.split('Bearer ').pop() || '';
|
||||
//logDebug('receive http header token', clientToken);
|
||||
} else if (req.query.access_token) {
|
||||
if (Array.isArray(req.query.access_token)) {
|
||||
clientToken = req.query.access_token[0].toString();
|
||||
} else {
|
||||
clientToken = req.query.access_token.toString();
|
||||
}
|
||||
//logDebug('receive http url token', clientToken);
|
||||
}
|
||||
|
||||
if (serverToken && clientToken != serverToken) {
|
||||
return res.status(403).send(JSON.stringify({ message: 'token verify failed!' }));
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
start(port: number, host: string) {
|
||||
try {
|
||||
this.expressAPP.get('/', (req: Request, res: Response) => {
|
||||
res.send(`${this.name}已启动`);
|
||||
});
|
||||
this.listen(port, host);
|
||||
} catch (e: any) {
|
||||
logError('HTTP服务启动失败', e.toString());
|
||||
// httpServerError = "HTTP服务启动失败, " + e.toString()
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
// httpServerError = ""
|
||||
if (this.server) {
|
||||
this.server.close();
|
||||
this.server = null;
|
||||
}
|
||||
}
|
||||
|
||||
restart(port: number, host: string) {
|
||||
this.stop();
|
||||
this.start(port, host);
|
||||
}
|
||||
|
||||
abstract handleFailed(res: Response, payload: any, err: Error): void
|
||||
|
||||
registerRouter(method: 'post' | 'get' | string, url: string, handler: RegisterHandler) {
|
||||
if (!url.startsWith('/')) {
|
||||
url = '/' + url;
|
||||
}
|
||||
|
||||
// @ts-expect-error wait fix
|
||||
if (!this.expressAPP[method]) {
|
||||
const err = `${this.name} register router failed,${method} not exist`;
|
||||
logError(err);
|
||||
throw err;
|
||||
}
|
||||
// @ts-expect-error wait fix
|
||||
this.expressAPP[method](url, this.authorize, async (req: Request, res: Response) => {
|
||||
let payload = req.body;
|
||||
if (method == 'get') {
|
||||
payload = req.query;
|
||||
} else if (req.query) {
|
||||
payload = { ...req.query, ...req.body };
|
||||
}
|
||||
logDebug('收到http请求', url, payload);
|
||||
try {
|
||||
res.send(await handler(res, payload));
|
||||
} catch (e: any) {
|
||||
this.handleFailed(res, payload, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected listen(port: number, host: string = '0.0.0.0') {
|
||||
host = host || '0.0.0.0';
|
||||
try {
|
||||
this.server = this.expressAPP.listen(port, host, () => {
|
||||
const info = `${this.name} started ${host}:${port}`;
|
||||
log(info);
|
||||
}).on('error', (err) => {
|
||||
logError('HTTP服务启动失败', err.toString());
|
||||
});
|
||||
} catch (e: any) {
|
||||
logError('HTTP服务启动失败, 请检查监听的ip地址和端口', e.stack.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import { WebSocket, WebSocketServer } from 'ws';
|
||||
import http from 'http';
|
||||
import urlParse from 'url';
|
||||
import { IncomingMessage } from 'node:http';
|
||||
import { log } from '@/common/utils/log';
|
||||
|
||||
class WebsocketClientBase {
|
||||
private wsClient: WebSocket | undefined;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
send(msg: string) {
|
||||
if (this.wsClient && this.wsClient.readyState == WebSocket.OPEN) {
|
||||
this.wsClient.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
onMessage(msg: string) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class WebsocketServerBase {
|
||||
private ws: WebSocketServer | null = null;
|
||||
public token: string = '';
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
start(port: number | http.Server, host: string = '') {
|
||||
if (port instanceof http.Server) {
|
||||
try {
|
||||
const wss = new WebSocketServer({
|
||||
noServer: true,
|
||||
maxPayload: 1024 * 1024 * 1024
|
||||
}).on('error', () => {
|
||||
});
|
||||
this.ws = wss;
|
||||
port.on('upgrade', function upgrade(request, socket, head) {
|
||||
wss.handleUpgrade(request, socket, head, function done(ws) {
|
||||
wss.emit('connection', ws, request);
|
||||
});
|
||||
});
|
||||
log('ws服务启动成功, 绑定到HTTP服务');
|
||||
} catch (e: any) {
|
||||
throw Error('ws服务启动失败, 可能是绑定的HTTP服务异常' + e.toString());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
this.ws = new WebSocketServer({
|
||||
port,
|
||||
host: '',
|
||||
maxPayload: 1024 * 1024 * 1024
|
||||
}).on('error', () => {
|
||||
});
|
||||
log(`ws服务启动成功, ${host}:${port}`);
|
||||
} catch (e: any) {
|
||||
throw Error('ws服务启动失败, 请检查监听的ip和端口' + e.toString());
|
||||
}
|
||||
}
|
||||
this.ws.on('connection', (wsClient, req) => {
|
||||
const url: string = req.url!.split('?').shift() || '/';
|
||||
this.authorize(wsClient, req);
|
||||
this.onConnect(wsClient, url, req);
|
||||
wsClient.on('message', async (msg) => {
|
||||
this.onMessage(wsClient, url, msg.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.ws) {
|
||||
this.ws.close((err) => {
|
||||
if (err) log('ws server close failed!', err);
|
||||
});
|
||||
this.ws = null;
|
||||
}
|
||||
}
|
||||
|
||||
restart(port: number) {
|
||||
this.stop();
|
||||
this.start(port);
|
||||
}
|
||||
|
||||
authorize(wsClient: WebSocket, req: IncomingMessage) {
|
||||
const url = req.url!.split('?').shift();
|
||||
log('ws connect', url);
|
||||
let clientToken: string = '';
|
||||
const authHeader = req.headers['authorization'];
|
||||
if (authHeader) {
|
||||
clientToken = authHeader.split('Bearer ').pop() || '';
|
||||
log('receive ws header token', clientToken);
|
||||
} else {
|
||||
const parsedUrl = urlParse.parse(req.url || '/', true);
|
||||
const urlToken = parsedUrl.query.access_token;
|
||||
if (urlToken) {
|
||||
if (Array.isArray(urlToken)) {
|
||||
clientToken = urlToken[0];
|
||||
} else {
|
||||
clientToken = urlToken;
|
||||
}
|
||||
log('receive ws url token', clientToken);
|
||||
}
|
||||
}
|
||||
if (this.token && clientToken != this.token) {
|
||||
this.authorizeFailed(wsClient);
|
||||
return wsClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
authorizeFailed(wsClient: WebSocket) {
|
||||
|
||||
}
|
||||
|
||||
onConnect(wsClient: WebSocket, url: string, req: IncomingMessage) {
|
||||
|
||||
}
|
||||
|
||||
onMessage(wsClient: WebSocket, url: string, msg: string) {
|
||||
|
||||
}
|
||||
|
||||
sendHeart() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { log, logDebug, logError } from '@/common/utils/log';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { selfInfo } from '@/core/data';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const configDir = path.resolve(__dirname, 'config');
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
|
||||
|
||||
export class ConfigBase<T> {
|
||||
public name: string = 'default_config';
|
||||
private pathName: string | null = null; // 本次读取的文件路径
|
||||
constructor() {
|
||||
}
|
||||
|
||||
protected getKeys(): string[] | null {
|
||||
// 决定 key 在json配置文件中的顺序
|
||||
return null;
|
||||
}
|
||||
|
||||
getConfigDir() {
|
||||
const configDir = path.resolve(__dirname, 'config');
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
return configDir;
|
||||
}
|
||||
getConfigPath(pathName: string | null): string {
|
||||
const suffix = pathName ? `_${pathName}` : '';
|
||||
const filename = `${this.name}${suffix}.json`;
|
||||
return path.join(this.getConfigDir(), filename);
|
||||
}
|
||||
read() {
|
||||
// 尝试加载当前账号配置
|
||||
if (this.read_from_file(selfInfo.uin, false)) return this;
|
||||
// 尝试加载默认配置
|
||||
return this.read_from_file('', true);
|
||||
}
|
||||
read_from_file(pathName: string, createIfNotExist: boolean) {
|
||||
const configPath = this.getConfigPath(pathName);
|
||||
if (!fs.existsSync(configPath)) {
|
||||
if (!createIfNotExist) return null;
|
||||
this.pathName = pathName; // 记录有效的设置文件
|
||||
try {
|
||||
fs.writeFileSync(configPath, JSON.stringify(this, this.getKeys(), 2));
|
||||
log(`配置文件${configPath}已创建\n如果修改此文件后需要重启 NapCat 生效`);
|
||||
}
|
||||
catch (e: any) {
|
||||
logError(`创建配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
logDebug(`配置文件${configPath}已加载`, data);
|
||||
Object.assign(this, data);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
this.save(this); // 保存一次,让新版本的字段写入
|
||||
return this;
|
||||
} catch (e: any) {
|
||||
if (e instanceof SyntaxError) {
|
||||
logError(`配置文件 ${configPath} 格式错误,请检查配置文件:`, e.message);
|
||||
} else {
|
||||
logError(`读取配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
save(config: T, overwrite: boolean = false) {
|
||||
Object.assign(this, config);
|
||||
if (overwrite) {
|
||||
// 用户要求强制写入,则变更当前文件为目标文件
|
||||
this.pathName = `${selfInfo.uin}`;
|
||||
}
|
||||
const configPath = this.getConfigPath(this.pathName);
|
||||
try {
|
||||
fs.writeFileSync(configPath, JSON.stringify(this, this.getKeys(), 2));
|
||||
} catch (e: any) {
|
||||
logError(`保存配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
import { NodeIQQNTWrapperSession } from '@/core/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) });
|
||||
@@ -1,144 +0,0 @@
|
||||
import { Peer } from '@/core';
|
||||
import crypto, { randomInt, randomUUID } from 'crypto';
|
||||
import { logError } from './log';
|
||||
|
||||
export class LimitedHashTable<K, V> {
|
||||
private keyToValue: Map<K, V> = new Map();
|
||||
private valueToKey: Map<V, K> = new Map();
|
||||
private maxSize: number;
|
||||
|
||||
constructor(maxSize: number) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
resize(count: number) {
|
||||
this.maxSize = count;
|
||||
}
|
||||
|
||||
set(key: K, value: V): void {
|
||||
// const isExist = this.keyToValue.get(key);
|
||||
// if (isExist && isExist === value) {
|
||||
// return;
|
||||
// }
|
||||
this.keyToValue.set(key, value);
|
||||
this.valueToKey.set(value, key);
|
||||
while (this.keyToValue.size !== this.valueToKey.size) {
|
||||
console.log('keyToValue.size !== valueToKey.size Error Atom');
|
||||
this.keyToValue.clear();
|
||||
this.valueToKey.clear();
|
||||
}
|
||||
// console.log('---------------');
|
||||
// console.log(this.keyToValue);
|
||||
// console.log(this.valueToKey);
|
||||
// console.log('---------------');
|
||||
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
|
||||
//console.log(this.keyToValue.size > this.maxSize, this.valueToKey.size > this.maxSize);
|
||||
const oldestKey = this.keyToValue.keys().next().value;
|
||||
this.valueToKey.delete(this.keyToValue.get(oldestKey)!);
|
||||
this.keyToValue.delete(oldestKey);
|
||||
}
|
||||
}
|
||||
|
||||
getValue(key: K): V | undefined {
|
||||
return this.keyToValue.get(key);
|
||||
}
|
||||
|
||||
getKey(value: V): K | undefined {
|
||||
return this.valueToKey.get(value);
|
||||
}
|
||||
|
||||
deleteByValue(value: V): void {
|
||||
const key = this.valueToKey.get(value);
|
||||
if (key !== undefined) {
|
||||
this.keyToValue.delete(key);
|
||||
this.valueToKey.delete(value);
|
||||
}
|
||||
}
|
||||
|
||||
deleteByKey(key: K): void {
|
||||
const value = this.keyToValue.get(key);
|
||||
if (value !== undefined) {
|
||||
this.keyToValue.delete(key);
|
||||
this.valueToKey.delete(value);
|
||||
}
|
||||
}
|
||||
|
||||
getKeyList(): K[] {
|
||||
return Array.from(this.keyToValue.keys());
|
||||
}
|
||||
//获取最近刚写入的几个值
|
||||
getHeads(size: number): { key: K; value: V }[] | undefined {
|
||||
const keyList = this.getKeyList();
|
||||
if (keyList.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const result: { key: K; value: V }[] = [];
|
||||
const listSize = Math.min(size, keyList.length);
|
||||
for (let i = 0; i < listSize; i++) {
|
||||
const key = keyList[listSize - i];
|
||||
result.push({ key, value: this.keyToValue.get(key)! });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class MessageUniqueWrapper {
|
||||
private msgDataMap: LimitedHashTable<string, number>;
|
||||
private msgIdMap: LimitedHashTable<string, number>;
|
||||
constructor(maxMap: number = 1000) {
|
||||
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
||||
this.msgDataMap = new LimitedHashTable<string, number>(maxMap);
|
||||
}
|
||||
getRecentMsgIds(Peer: Peer, size: number): string[] {
|
||||
const heads = this.msgIdMap.getHeads(size);
|
||||
if (!heads) {
|
||||
return [];
|
||||
}
|
||||
const data = heads.map((t) => MessageUnique.getMsgIdAndPeerByShortId(t.value));
|
||||
const ret = data.filter((t) => t?.Peer.chatType === Peer.chatType && t?.Peer.peerUid === Peer.peerUid);
|
||||
return ret.map((t) => t?.MsgId).filter((t) => t !== undefined);
|
||||
}
|
||||
createMsg(peer: Peer, msgId: string): number | undefined {
|
||||
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
|
||||
const hash = crypto.createHash('md5').update(key).digest();
|
||||
//设置第一个bit为0 保证shortId为正数
|
||||
hash[0] &= 0x7f;
|
||||
const shortId = hash.readInt32BE(0);
|
||||
//减少性能损耗
|
||||
// const isExist = this.msgIdMap.getKey(shortId);
|
||||
// if (isExist && isExist === msgId) {
|
||||
// return shortId;
|
||||
// }
|
||||
this.msgIdMap.set(msgId, shortId);
|
||||
this.msgDataMap.set(key, shortId);
|
||||
return shortId;
|
||||
}
|
||||
|
||||
getMsgIdAndPeerByShortId(shortId: number): { MsgId: string; Peer: Peer } | undefined {
|
||||
const data = this.msgDataMap.getKey(shortId);
|
||||
if (data) {
|
||||
const [msgId, chatTypeStr, peerUid] = data.split('|');
|
||||
const peer: Peer = {
|
||||
chatType: parseInt(chatTypeStr),
|
||||
peerUid,
|
||||
guildId: '',
|
||||
};
|
||||
return { MsgId: msgId, Peer: peer };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getShortIdByMsgId(msgId: string): number | undefined {
|
||||
return this.msgIdMap.getValue(msgId);
|
||||
}
|
||||
getPeerByMsgId(msgId: string) {
|
||||
const shortId = this.msgIdMap.getValue(msgId);
|
||||
if (!shortId) return undefined;
|
||||
return this.getMsgIdAndPeerByShortId(shortId);
|
||||
}
|
||||
resize(maxSize: number): void {
|
||||
this.msgIdMap.resize(maxSize);
|
||||
this.msgDataMap.resize(maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper();
|
||||
@@ -1,17 +0,0 @@
|
||||
// 方案一 MiniApp发包方案
|
||||
// 前置条件: 处于GUI环境 存在MiniApp
|
||||
|
||||
import { NTQQSystemApi } from '@/core';
|
||||
|
||||
// 前排提示: 开发验证仅Win平台开展
|
||||
export class MiniAppUtil {
|
||||
static async RunMiniAppWithGUI() {
|
||||
//process.env.ELECTRON_RUN_AS_NODE = undefined;//没用还是得自己用cpp之类的语言写个程序转发参数
|
||||
return NTQQSystemApi.BootMiniApp(process.execPath, 'miniapp://open/1007?url=https%3A%2F%2Fm.q.qq.com%2Fa%2Fs%2Fedd0a83d3b8afe233dfa07adaaf8033f%3Fscene%3D1007%26min_refer%3D10001');
|
||||
}
|
||||
}
|
||||
// 方案二 MiniApp发包方案 替代MiniApp方案
|
||||
// 前置条件: 无
|
||||
export class MojoMiniAppUtil{
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
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 { log } from './log';
|
||||
|
||||
//基础目录获取
|
||||
export const QQMainPath = process.execPath;
|
||||
export const QQPackageInfoPath: string = path.join(path.dirname(QQMainPath), 'resources', 'app', 'package.json');
|
||||
export const QQVersionConfigPath: string | undefined = getQQVersionConfigPath(QQMainPath);
|
||||
|
||||
//基础信息获取 无快更则启用默认模板填充
|
||||
export const isQuickUpdate: boolean = !!QQVersionConfigPath;
|
||||
export const QQVersionConfig: QQVersionConfigType = isQuickUpdate ? JSON.parse(fs.readFileSync(QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
||||
export const QQPackageInfo: QQPackageInfoType = JSON.parse(fs.readFileSync(QQPackageInfoPath).toString());
|
||||
export const { appid: QQVersionAppid, qua: QQVersionQua } = getAppidV2();
|
||||
|
||||
//基础函数
|
||||
export function getQQBuildStr() {
|
||||
return isQuickUpdate ? QQVersionConfig.buildId : QQPackageInfo.buildVersion;
|
||||
}
|
||||
export function getFullQQVesion() {
|
||||
return isQuickUpdate ? QQVersionConfig.curVersion : QQPackageInfo.version;
|
||||
}
|
||||
export function requireMinNTQQBuild(buildStr: string) {
|
||||
return parseInt(getQQBuildStr()) >= parseInt(buildStr);
|
||||
}
|
||||
//此方法不要直接使用
|
||||
export function getQUAInternal() {
|
||||
return systemPlatform === 'linux' ? `V1_LNX_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B`;
|
||||
}
|
||||
export function getAppidV2(): { appid: string, qua: string } {
|
||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||
try {
|
||||
const data = appidTbale[getFullQQVesion()];
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||
}
|
||||
// 以下是兜底措施
|
||||
log(`[QQ版本兼容性检测] ${getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`);
|
||||
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: getQUAInternal() };
|
||||
}
|
||||
// platform_type: 3,
|
||||
// app_type: 4,
|
||||
// app_version: '9.9.12-25765',
|
||||
// qua: 'V1_WIN_NQ_9.9.12_25765_GW_B',
|
||||
// appid: '537234702',
|
||||
// platVer: '10.0.26100',
|
||||
// clientVer: '9.9.9-25765',
|
||||
// Linux
|
||||
// app_version: '3.2.9-25765',
|
||||
// qua: 'V1_LNX_NQ_3.2.10_25765_GW_B',
|
||||
@@ -1,136 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import { encode, getDuration, getWavFileInfo, isWav, isSilk } from 'silk-wasm';
|
||||
import fsPromise from 'fs/promises';
|
||||
import { log, logError } from './log';
|
||||
import path from 'node:path';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { getTempDir } from '@/common/utils/file';
|
||||
|
||||
let TEMP_DIR = './';
|
||||
setTimeout(() => {
|
||||
TEMP_DIR = getTempDir();
|
||||
}, 100);
|
||||
export async function encodeSilk(filePath: string) {
|
||||
function getFileHeader(filePath: string) {
|
||||
// 定义要读取的字节数
|
||||
const bytesToRead = 7;
|
||||
try {
|
||||
const buffer = fs.readFileSync(filePath, {
|
||||
encoding: null,
|
||||
flag: 'r',
|
||||
});
|
||||
|
||||
const fileHeader = buffer.toString('hex', 0, bytesToRead);
|
||||
return fileHeader;
|
||||
} catch (err) {
|
||||
logError('读取文件错误:', err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function isWavFile(filePath: string) {
|
||||
return isWav(fs.readFileSync(filePath));
|
||||
}
|
||||
|
||||
async function guessDuration(pttPath: string) {
|
||||
const pttFileInfo = await fsPromise.stat(pttPath);
|
||||
let duration = pttFileInfo.size / 1024 / 3; // 3kb/s
|
||||
duration = Math.floor(duration);
|
||||
duration = Math.max(1, duration);
|
||||
log('通过文件大小估算语音的时长:', duration);
|
||||
return duration;
|
||||
}
|
||||
|
||||
// function verifyDuration(oriDuration: number, guessDuration: number) {
|
||||
// // 单位都是秒
|
||||
// if (oriDuration - guessDuration > 10) {
|
||||
// return guessDuration
|
||||
// }
|
||||
// oriDuration = Math.max(1, oriDuration)
|
||||
// return oriDuration
|
||||
// }
|
||||
// async function getAudioSampleRate(filePath: string) {
|
||||
// try {
|
||||
// const mm = await import('music-metadata');
|
||||
// const metadata = await mm.parseFile(filePath);
|
||||
// log(`${filePath}采样率`, metadata.format.sampleRate);
|
||||
// return metadata.format.sampleRate;
|
||||
// } catch (error) {
|
||||
// log(`${filePath}采样率获取失败`, error.stack);
|
||||
// // console.error(error);
|
||||
// }
|
||||
// }
|
||||
|
||||
try {
|
||||
const file = await fsPromise.readFile(filePath);
|
||||
const pttPath = path.join(TEMP_DIR, randomUUID());
|
||||
if (!isSilk(file)) {
|
||||
log(`语音文件${filePath}需要转换成silk`);
|
||||
const _isWav = isWav(file);
|
||||
const pcmPath = pttPath + '.pcm';
|
||||
let sampleRate = 0;
|
||||
const convert = () => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
// todo: 通过配置文件获取ffmpeg路径
|
||||
const ffmpegPath = process.env.FFMPEG_PATH || 'ffmpeg';
|
||||
const cp = spawn(ffmpegPath, ['-y', '-i', filePath, '-ar', '24000', '-ac', '1', '-f', 's16le', pcmPath]);
|
||||
cp.on('error', err => {
|
||||
log('FFmpeg处理转换出错: ', err.message);
|
||||
return reject(err);
|
||||
});
|
||||
cp.on('exit', (code, signal) => {
|
||||
const EXIT_CODES = [0, 255];
|
||||
if (code == null || EXIT_CODES.includes(code)) {
|
||||
sampleRate = 24000;
|
||||
const data = fs.readFileSync(pcmPath);
|
||||
fs.unlink(pcmPath, (err) => {
|
||||
});
|
||||
return resolve(data);
|
||||
}
|
||||
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`);
|
||||
reject(Error('FFmpeg处理转换失败'));
|
||||
});
|
||||
});
|
||||
};
|
||||
let input: Buffer;
|
||||
if (!_isWav) {
|
||||
input = await convert();
|
||||
} else {
|
||||
input = file;
|
||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000];
|
||||
const { fmt } = getWavFileInfo(input);
|
||||
// log(`wav文件信息`, fmt)
|
||||
if (!allowSampleRate.includes(fmt.sampleRate)) {
|
||||
input = await convert();
|
||||
}
|
||||
}
|
||||
const silk = await encode(input, sampleRate);
|
||||
fs.writeFileSync(pttPath, silk.data);
|
||||
log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration);
|
||||
return {
|
||||
converted: true,
|
||||
path: pttPath,
|
||||
duration: silk.duration / 1000
|
||||
};
|
||||
} else {
|
||||
const silk = file;
|
||||
let duration = 0;
|
||||
try {
|
||||
duration = getDuration(silk) / 1000;
|
||||
} catch (e: any) {
|
||||
log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack);
|
||||
duration = await guessDuration(filePath);
|
||||
}
|
||||
|
||||
return {
|
||||
converted: false,
|
||||
path: filePath,
|
||||
duration,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
logError('convert silk failed', error.stack);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import * as os from 'os';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
export function getModuleWithArchName(moduleName: string) {
|
||||
const systemPlatform = os.platform();
|
||||
const cpuArch = os.arch();
|
||||
return `${moduleName}-${systemPlatform}-${cpuArch}.node`;
|
||||
}
|
||||
|
||||
export function cpModule(moduleName: string) {
|
||||
const currentDir = path.resolve(__dirname);
|
||||
const fileName = `./${getModuleWithArchName(moduleName)}`;
|
||||
try {
|
||||
fs.copyFileSync(path.join(currentDir, fileName), path.join(currentDir, `${moduleName}.node`));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
@@ -1,316 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import fsPromise, { stat } from 'fs/promises';
|
||||
import crypto from 'crypto';
|
||||
import util from 'util';
|
||||
import path from 'node:path';
|
||||
import { log, logError } from './log';
|
||||
import * as fileType from 'file-type';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { napCatCore } from '@/core';
|
||||
|
||||
export const getNapCatDir = () => {
|
||||
const p = path.join(napCatCore.dataPath, 'NapCat');
|
||||
fs.mkdirSync(p, { recursive: true });
|
||||
return p;
|
||||
};
|
||||
export const getTempDir = () => {
|
||||
const p = path.join(getNapCatDir(), 'temp');
|
||||
// 创建临时目录
|
||||
if (!fs.existsSync(p)) {
|
||||
fs.mkdirSync(p, { recursive: true });
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
|
||||
export function isGIF(path: string) {
|
||||
const buffer = Buffer.alloc(4);
|
||||
const fd = fs.openSync(path, 'r');
|
||||
fs.readSync(fd, buffer, 0, 4, 0);
|
||||
fs.closeSync(fd);
|
||||
return buffer.toString() === 'GIF8';
|
||||
}
|
||||
|
||||
// 定义一个异步函数来检查文件是否存在
|
||||
export function checkFileReceived(path: string, timeout: number = 3000): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
function check() {
|
||||
if (fs.existsSync(path)) {
|
||||
resolve();
|
||||
} else if (Date.now() - startTime > timeout) {
|
||||
reject(new Error(`文件不存在: ${path}`));
|
||||
} else {
|
||||
setTimeout(check, 100);
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
});
|
||||
}
|
||||
// 定义一个异步函数来检查文件是否存在
|
||||
export async function checkFileReceived2(path: string, timeout: number = 3000): Promise<void> {
|
||||
// 使用 Promise.race 来同时进行文件状态检查和超时计时
|
||||
// Promise.race 会返回第一个解决(resolve)或拒绝(reject)的 Promise
|
||||
await Promise.race([
|
||||
checkFile(path),
|
||||
timeoutPromise(timeout, `文件不存在: ${path}`),
|
||||
]);
|
||||
}
|
||||
|
||||
// 转换超时时间至 Promise
|
||||
function timeoutPromise(timeout: number, errorMsg: string): Promise<void> {
|
||||
return new Promise((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error(errorMsg));
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
// 异步检查文件是否存在
|
||||
async function checkFile(path: string): Promise<void> {
|
||||
try {
|
||||
await stat(path);
|
||||
} catch (error: any) {
|
||||
if (error.code === 'ENOENT') {
|
||||
// 如果文件不存在,则抛出一个错误
|
||||
throw new Error(`文件不存在: ${path}`);
|
||||
} else {
|
||||
// 对于 stat 调用的其他错误,重新抛出
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
||||
}
|
||||
export async function file2base64(path: string) {
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
const result = {
|
||||
err: '',
|
||||
data: ''
|
||||
};
|
||||
try {
|
||||
// 读取文件内容
|
||||
// if (!fs.existsSync(path)){
|
||||
// path = path.replace("\\Ori\\", "\\Thumb\\");
|
||||
// }
|
||||
try {
|
||||
await checkFileReceived(path, 5000);
|
||||
} catch (e: any) {
|
||||
result.err = e.toString();
|
||||
return result;
|
||||
}
|
||||
const data = await readFile(path);
|
||||
// 转换为Base64编码
|
||||
result.data = data.toString('base64');
|
||||
} catch (err: any) {
|
||||
result.err = err.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
export function calculateFileMD5(filePath: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 创建一个流式读取器
|
||||
const stream = fs.createReadStream(filePath);
|
||||
const hash = crypto.createHash('md5');
|
||||
|
||||
stream.on('data', (data: Buffer) => {
|
||||
// 当读取到数据时,更新哈希对象的状态
|
||||
hash.update(data);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
// 文件读取完成,计算哈希
|
||||
const md5 = hash.digest('hex');
|
||||
resolve(md5);
|
||||
});
|
||||
|
||||
stream.on('error', (err: Error) => {
|
||||
// 处理可能的读取错误
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export interface HttpDownloadOptions {
|
||||
url: string;
|
||||
headers?: Record<string, string> | string;
|
||||
}
|
||||
|
||||
export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> {
|
||||
const chunks: Buffer[] = [];
|
||||
let url: string;
|
||||
let headers: Record<string, string> = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36'
|
||||
};
|
||||
if (typeof options === 'string') {
|
||||
url = options;
|
||||
const host = new URL(url).hostname;
|
||||
headers['Host'] = host;
|
||||
} else {
|
||||
url = options.url;
|
||||
if (options.headers) {
|
||||
if (typeof options.headers === 'string') {
|
||||
headers = JSON.parse(options.headers);
|
||||
} else {
|
||||
headers = options.headers;
|
||||
}
|
||||
}
|
||||
}
|
||||
const fetchRes = await fetch(url, { headers }).catch((err) => {
|
||||
if (err.cause) {
|
||||
throw err.cause;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`);
|
||||
|
||||
const blob = await fetchRes.blob();
|
||||
const buffer = await blob.arrayBuffer();
|
||||
return Buffer.from(buffer);
|
||||
}
|
||||
|
||||
type Uri2LocalRes = {
|
||||
success: boolean,
|
||||
errMsg: string,
|
||||
fileName: string,
|
||||
ext: string,
|
||||
path: string,
|
||||
isLocal: boolean
|
||||
}
|
||||
|
||||
export async function uri2local(UriOrPath: string, fileName: string | null = null): Promise<Uri2LocalRes> {
|
||||
const res = {
|
||||
success: false,
|
||||
errMsg: '',
|
||||
fileName: '',
|
||||
ext: '',
|
||||
path: '',
|
||||
isLocal: false
|
||||
};
|
||||
if (!fileName) fileName = randomUUID();
|
||||
let filePath = path.join(getTempDir(), fileName);//临时目录
|
||||
let url = null;
|
||||
//区分path和uri
|
||||
try {
|
||||
if (fs.existsSync(UriOrPath)) url = new URL('file://' + UriOrPath);
|
||||
} catch (error: any) { }
|
||||
try {
|
||||
url = new URL(UriOrPath);
|
||||
} catch (error: any) { }
|
||||
|
||||
//验证url
|
||||
if (!url) {
|
||||
res.errMsg = `UriOrPath ${UriOrPath} 解析失败,可能${UriOrPath}不存在`;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (url.protocol == 'base64:') {
|
||||
// base64转成文件
|
||||
const base64Data = UriOrPath.split('base64://')[1];
|
||||
try {
|
||||
const buffer = Buffer.from(base64Data, 'base64');
|
||||
fs.writeFileSync(filePath, buffer);
|
||||
} catch (e: any) {
|
||||
res.errMsg = 'base64文件下载失败,' + e.toString();
|
||||
return res;
|
||||
}
|
||||
} else if (url.protocol == 'http:' || url.protocol == 'https:') {
|
||||
// 下载文件
|
||||
let buffer: Buffer | null = null;
|
||||
try {
|
||||
buffer = await httpDownload(UriOrPath);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `${url}下载失败,` + e.toString();
|
||||
return res;
|
||||
}
|
||||
try {
|
||||
const pathInfo = path.parse(decodeURIComponent(url.pathname));
|
||||
if (pathInfo.name) {
|
||||
fileName = pathInfo.name;
|
||||
if (pathInfo.ext) {
|
||||
fileName += pathInfo.ext;
|
||||
// res.ext = pathInfo.ext
|
||||
}
|
||||
}
|
||||
fileName = fileName.replace(/[/\\:*?"<>|]/g, '_');
|
||||
res.fileName = fileName;
|
||||
filePath = path.join(getTempDir(), randomUUID() + fileName);
|
||||
fs.writeFileSync(filePath, buffer);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `${url}下载失败,` + e.toString();
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
let pathname: string;
|
||||
if (url.protocol === 'file:') {
|
||||
// await fs.copyFile(url.pathname, filePath);
|
||||
pathname = decodeURIComponent(url.pathname);
|
||||
if (process.platform === 'win32') {
|
||||
filePath = pathname.slice(1);
|
||||
} else {
|
||||
filePath = pathname;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 26702执行forword file文件操作 不应该在这里乱来
|
||||
// const cache = await dbUtil.getFileCacheByName(uri);
|
||||
// if (cache) {
|
||||
// filePath = cache.path;
|
||||
// } else {
|
||||
// filePath = uri;
|
||||
// }
|
||||
}
|
||||
res.isLocal = true;
|
||||
}
|
||||
// else{
|
||||
// res.errMsg = `不支持的file协议,` + url.protocol
|
||||
// return res
|
||||
// }
|
||||
// if (isGIF(filePath) && !res.isLocal) {
|
||||
// await fs.rename(filePath, filePath + ".gif");
|
||||
// filePath += ".gif";
|
||||
// }
|
||||
if (!res.isLocal && !res.ext) {
|
||||
try {
|
||||
const ext: string | undefined = (await fileType.fileTypeFromFile(filePath))?.ext;
|
||||
if (ext) {
|
||||
log('获取文件类型', ext, filePath);
|
||||
fs.renameSync(filePath, filePath + `.${ext}`);
|
||||
filePath += `.${ext}`;
|
||||
res.fileName += `.${ext}`;
|
||||
res.ext = ext;
|
||||
}
|
||||
} catch (e) {
|
||||
// log("获取文件类型失败", filePath,e.stack)
|
||||
}
|
||||
}
|
||||
res.success = true;
|
||||
res.path = filePath;
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function copyFolder(sourcePath: string, destPath: string) {
|
||||
try {
|
||||
const entries = await fsPromise.readdir(sourcePath, { withFileTypes: true });
|
||||
await fsPromise.mkdir(destPath, { recursive: true });
|
||||
for (const entry of entries) {
|
||||
const srcPath = path.join(sourcePath, entry.name);
|
||||
const dstPath = path.join(destPath, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await copyFolder(srcPath, dstPath);
|
||||
} else {
|
||||
try {
|
||||
await fsPromise.copyFile(srcPath, dstPath);
|
||||
} catch (error) {
|
||||
logError(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
|
||||
// 这里可以决定是否要继续复制其他文件
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logError('复制文件夹时出错:', error);
|
||||
}
|
||||
}
|
||||
@@ -1,405 +0,0 @@
|
||||
import crypto from 'node:crypto';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import { log, logDebug } from './log';
|
||||
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);
|
||||
|
||||
//下面这个类是用于将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() };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
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]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
export function getMd5(s: string) {
|
||||
|
||||
const h = crypto.createHash('md5');
|
||||
h.update(s);
|
||||
return h.digest('hex');
|
||||
}
|
||||
|
||||
export function isNull(value: any) {
|
||||
return value === undefined || value === null;
|
||||
}
|
||||
|
||||
export function isNumeric(str: string) {
|
||||
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 (!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 async function UpdateConfig() {
|
||||
const configFiles = await fsPromise.readdir(path.join(__dirname, 'config'));
|
||||
for (const file of configFiles) {
|
||||
if (file.match(/^onebot11_\d+.json$/)) {
|
||||
const CurrentConfig = JSON.parse(await fsPromise.readFile(path.join(__dirname, 'config', file), 'utf8'));
|
||||
if (isValidOldConfig(CurrentConfig)) {
|
||||
log('正在迁移旧配置到新配置 File:', file);
|
||||
const NewConfig = migrateConfig(CurrentConfig);
|
||||
await fsPromise.writeFile(path.join(__dirname, 'config', file), JSON.stringify(NewConfig, null, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
const keys1 = Object.keys(obj1);
|
||||
const keys2 = Object.keys(obj2);
|
||||
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
|
||||
for (const key of keys1) {
|
||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
||||
if (os.platform() === 'linux') {
|
||||
return {
|
||||
baseVersion: '3.2.12-26702',
|
||||
curVersion: '3.2.12-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 async function deleteOldFiles(directoryPath: string, daysThreshold: number) {
|
||||
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);
|
||||
|
||||
if (daysDifference > daysThreshold) {
|
||||
await fsPromise.unlink(filePath); // Delete the file
|
||||
//console.log(`Deleted: ${filePath}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
//console.error('Error deleting files:', error);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
import log4js, { Configuration } from 'log4js';
|
||||
import { truncateString } from '@/common/utils/helper';
|
||||
import path from 'node:path';
|
||||
import { SelfInfo } from '@/core';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import chalk from 'chalk';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export enum LogLevel {
|
||||
DEBUG = 'debug',
|
||||
INFO = 'info',
|
||||
WARN = 'warn',
|
||||
ERROR = 'error',
|
||||
FATAL = 'fatal',
|
||||
}
|
||||
|
||||
const logDir = path.join(path.resolve(__dirname), 'logs');
|
||||
|
||||
function getFormattedTimestamp() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = now.getDate().toString().padStart(2, '0');
|
||||
const hours = now.getHours().toString().padStart(2, '0');
|
||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
|
||||
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
|
||||
}
|
||||
|
||||
const filename = `${getFormattedTimestamp()}.log`;
|
||||
const logPath = path.join(logDir, filename);
|
||||
|
||||
const logConfig: Configuration = {
|
||||
appenders: {
|
||||
FileAppender: { // 输出到文件的appender
|
||||
type: 'file',
|
||||
filename: logPath, // 指定日志文件的位置和文件名
|
||||
maxLogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] %X{userInfo} | %m'
|
||||
}
|
||||
},
|
||||
ConsoleAppender: { // 输出到控制台的appender
|
||||
type: 'console',
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m`
|
||||
}
|
||||
}
|
||||
},
|
||||
categories: {
|
||||
default: { appenders: ['FileAppender', 'ConsoleAppender'], level: 'debug' }, // 默认情况下同时输出到文件和控制台
|
||||
file: { appenders: ['FileAppender'], level: 'debug' },
|
||||
console: { appenders: ['ConsoleAppender'], level: 'debug' }
|
||||
}
|
||||
};
|
||||
|
||||
log4js.configure(logConfig);
|
||||
const loggerConsole = log4js.getLogger('console');
|
||||
const loggerFile = log4js.getLogger('file');
|
||||
const loggerDefault = log4js.getLogger('default');
|
||||
|
||||
export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||
logConfig.categories.file.level = fileLogLevel;
|
||||
logConfig.categories.console.level = consoleLogLevel;
|
||||
log4js.configure(logConfig);
|
||||
}
|
||||
|
||||
export function setLogSelfInfo(selfInfo: SelfInfo) {
|
||||
const userInfo = `${selfInfo.nick}(${selfInfo.uin})`;
|
||||
loggerConsole.addContext('userInfo', userInfo);
|
||||
loggerFile.addContext('userInfo', userInfo);
|
||||
loggerDefault.addContext('userInfo', userInfo);
|
||||
}
|
||||
setLogSelfInfo({ nick: '', uin: '', uid: '' });
|
||||
|
||||
let fileLogEnabled = true;
|
||||
let consoleLogEnabled = true;
|
||||
export function enableFileLog(enable: boolean) {
|
||||
fileLogEnabled = enable;
|
||||
}
|
||||
export function enableConsoleLog(enable: boolean) {
|
||||
consoleLogEnabled = enable;
|
||||
}
|
||||
|
||||
function formatMsg(msg: any[]) {
|
||||
let logMsg = '';
|
||||
for (const msgItem of msg) {
|
||||
if (msgItem instanceof Error) { // 判断是否是错误
|
||||
logMsg += msgItem.stack + ' ';
|
||||
continue;
|
||||
} else if (typeof msgItem === 'object') { // 判断是否是对象
|
||||
const obj = JSON.parse(JSON.stringify(msgItem, null, 2));
|
||||
logMsg += JSON.stringify(truncateString(obj)) + ' ';
|
||||
continue;
|
||||
}
|
||||
logMsg += msgItem + ' ';
|
||||
}
|
||||
return logMsg;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
|
||||
|
||||
function _log(level: LogLevel, ...args: any[]) {
|
||||
if (consoleLogEnabled) {
|
||||
loggerConsole[level](formatMsg(args));
|
||||
}
|
||||
if (fileLogEnabled) {
|
||||
loggerFile[level](formatMsg(args).replace(colorEscape, ''));
|
||||
}
|
||||
}
|
||||
|
||||
export function log(...args: any[]) {
|
||||
// info 等级
|
||||
_log(LogLevel.INFO, ...args);
|
||||
}
|
||||
|
||||
export function logDebug(...args: any[]) {
|
||||
_log(LogLevel.DEBUG, ...args);
|
||||
}
|
||||
|
||||
export function logError(...args: any[]) {
|
||||
_log(LogLevel.ERROR, ...args);
|
||||
}
|
||||
|
||||
export function logWarn(...args: any[]) {
|
||||
_log(LogLevel.WARN, ...args);
|
||||
}
|
||||
|
||||
export function logFatal(...args: any[]) {
|
||||
_log(LogLevel.FATAL, ...args);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// QQ等级换算
|
||||
import { QQLevel } from '@/core/entities';
|
||||
|
||||
export function calcQQLevel(level: QQLevel) {
|
||||
const { crownNum, sunNum, moonNum, starNum } = level;
|
||||
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { pid, ppid, exit } from 'node:process';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export async function rebootWithQuickLogin(uin: string) {
|
||||
const batScript = resolve(__dirname, './napcat.bat');
|
||||
const batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
||||
const bashScript = resolve(__dirname, './napcat.sh');
|
||||
if (process.platform === 'win32') {
|
||||
const subProcess = spawn(`start ${batUtf8Script} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||
subProcess.unref();
|
||||
// 子父进程一起送走 有点效果
|
||||
spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
} else if (process.platform === 'linux') {
|
||||
const subProcess = spawn(`${bashScript} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||
//还没兼容
|
||||
subProcess.unref();
|
||||
exit(0);
|
||||
}
|
||||
//exit(0);
|
||||
}
|
||||
export async function rebootWithNormolLogin() {
|
||||
const batScript = resolve(__dirname, './napcat.bat');
|
||||
const batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
||||
const bashScript = resolve(__dirname, './napcat.sh');
|
||||
if (process.platform === 'win32') {
|
||||
const subProcess = spawn(`start ${batUtf8Script} `, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||
subProcess.unref();
|
||||
// 子父进程一起送走 有点效果
|
||||
spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
} else if (process.platform === 'linux') {
|
||||
const subProcess = spawn(`${bashScript}`, { detached: true, windowsHide: false, env: process.env, shell: true });
|
||||
subProcess.unref();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
import https from 'node:https';
|
||||
import http from 'node:http';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { NTQQUserApi } from '@/core';
|
||||
export class RequestUtil {
|
||||
// 适用于获取服务器下发cookies时获取,仅GET
|
||||
static async HttpsGetCookies(url: string): Promise<{ [key: string]: string }> {
|
||||
const client = url.startsWith('https') ? https : http;
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = client.get(url, (res) => {
|
||||
let cookies: { [key: string]: string } = {};
|
||||
const handleRedirect = (res: http.IncomingMessage) => {
|
||||
//console.log(res.headers.location);
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
if (res.headers.location) {
|
||||
const redirectUrl = new URL(res.headers.location, url);
|
||||
RequestUtil.HttpsGetCookies(redirectUrl.href).then((redirectCookies) => {
|
||||
// 合并重定向过程中的cookies
|
||||
cookies = { ...cookies, ...redirectCookies };
|
||||
resolve(cookies);
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
};
|
||||
res.on('data', () => { }); // Necessary to consume the stream
|
||||
res.on('end', () => {
|
||||
handleRedirect(res);
|
||||
});
|
||||
if (res.headers['set-cookie']) {
|
||||
//console.log(res.headers['set-cookie']);
|
||||
res.headers['set-cookie'].forEach((cookie) => {
|
||||
const parts = cookie.split(';')[0].split('=');
|
||||
const key = parts[0];
|
||||
const value = parts[1];
|
||||
if (key && value && key.length > 0 && value.length > 0) {
|
||||
cookies[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
req.on('error', (error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 请求和回复都是JSON data传原始内容 自动编码json
|
||||
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}, isJsonRet: boolean = true, isArgJson: boolean = true): Promise<T> {
|
||||
const option = new URL(url);
|
||||
const protocol = url.startsWith('https://') ? https : http;
|
||||
const options = {
|
||||
hostname: option.hostname,
|
||||
port: option.port,
|
||||
path: option.href,
|
||||
method: method,
|
||||
headers: headers
|
||||
};
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Content-Length': Buffer.byteLength(postData),
|
||||
// },
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = protocol.request(options, (res: any) => {
|
||||
let responseBody = '';
|
||||
res.on('data', (chunk: string | Buffer) => {
|
||||
responseBody += chunk.toString();
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
if (isJsonRet) {
|
||||
const responseJson = JSON.parse(responseBody);
|
||||
resolve(responseJson as T);
|
||||
} else {
|
||||
resolve(responseBody as T);
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(parseError);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
||||
if (isArgJson) {
|
||||
req.write(JSON.stringify(data));
|
||||
} else {
|
||||
req.write(data);
|
||||
}
|
||||
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 请求返回都是原始内容
|
||||
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
||||
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
||||
}
|
||||
|
||||
static async createFormData(boundary: string, filePath: string): Promise<Buffer> {
|
||||
let type = 'image/png';
|
||||
if (filePath.endsWith('.jpg')) {
|
||||
type = 'image/jpeg';
|
||||
}
|
||||
const formDataParts = [
|
||||
`------${boundary}\r\n`,
|
||||
`Content-Disposition: form-data; name="share_image"; filename="${filePath}"\r\n`,
|
||||
'Content-Type: ' + type + '\r\n\r\n'
|
||||
];
|
||||
|
||||
const fileContent = readFileSync(filePath);
|
||||
const footer = `\r\n------${boundary}--`;
|
||||
return Buffer.concat([
|
||||
Buffer.from(formDataParts.join(''), 'utf8'),
|
||||
fileContent,
|
||||
Buffer.from(footer, 'utf8')
|
||||
]);
|
||||
}
|
||||
|
||||
static async uploadImageForOpenPlatform(filePath: string): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
type retType = { retcode: number, result?: { url: string } };
|
||||
try {
|
||||
const cookies = Object.entries(await NTQQUserApi.getCookies('connect.qq.com')).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const options = {
|
||||
hostname: 'cgi.connect.qq.com',
|
||||
port: 443,
|
||||
path: '/qqconnectopen/upload_share_image',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Referer': 'https://cgi.connect.qq.com',
|
||||
'Cookie': cookies,
|
||||
'Accept': '*/*',
|
||||
'Connection': 'keep-alive',
|
||||
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
|
||||
}
|
||||
};
|
||||
const req = https.request(options, async (res) => {
|
||||
let responseBody = '';
|
||||
|
||||
res.on('data', (chunk: string | Buffer) => {
|
||||
responseBody += chunk.toString();
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
const responseJson = JSON.parse(responseBody) as retType;
|
||||
resolve(responseJson.result!.url!);
|
||||
} else {
|
||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(parseError);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
console.error('Error during upload:', error);
|
||||
});
|
||||
|
||||
const body = await RequestUtil.createFormData('WebKitFormBoundary7MA4YWxkTrZu0gW', filePath);
|
||||
// req.setHeader('Content-Length', Buffer.byteLength(body));
|
||||
// console.log(`Prepared data size: ${Buffer.byteLength(body)} bytes`);
|
||||
req.write(body);
|
||||
req.end();
|
||||
return;
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { networkInterfaces } from 'os';
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
// 缓解Win7设备兼容性问题
|
||||
let osName: string;
|
||||
// 设备ID
|
||||
let machineId: Promise<string>;
|
||||
|
||||
try {
|
||||
osName = os.hostname();
|
||||
} catch (e) {
|
||||
osName = 'NapCat'; // + crypto.randomUUID().substring(0, 4);
|
||||
}
|
||||
|
||||
const invalidMacAddresses = new Set([
|
||||
'00:00:00:00:00:00',
|
||||
'ff:ff:ff:ff:ff:ff',
|
||||
'ac:de:48:00:11:22'
|
||||
]);
|
||||
|
||||
function validateMacAddress(candidate: string): boolean {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
|
||||
return !invalidMacAddresses.has(tempCandidate);
|
||||
}
|
||||
|
||||
export async function getMachineId(): Promise<string> {
|
||||
if (!machineId) {
|
||||
machineId = (async () => {
|
||||
const id = await getMacMachineId();
|
||||
return id || randomUUID(); // fallback, generate a UUID
|
||||
})();
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
export function getMac(): string {
|
||||
const ifaces = networkInterfaces();
|
||||
for (const name in ifaces) {
|
||||
const networkInterface = ifaces[name];
|
||||
if (networkInterface) {
|
||||
for (const { mac } of networkInterface) {
|
||||
if (validateMacAddress(mac)) {
|
||||
return mac;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unable to retrieve mac address (unexpected format)');
|
||||
}
|
||||
|
||||
async function getMacMachineId(): Promise<string | undefined> {
|
||||
try {
|
||||
const crypto = await import('crypto');
|
||||
const macAddress = getMac();
|
||||
return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const homeDir = os.homedir();
|
||||
|
||||
|
||||
export const systemPlatform = os.platform();
|
||||
export const cpuArch = os.arch();
|
||||
export const systemVersion = os.release();
|
||||
export const hostname = osName;
|
||||
export const downloadsPath = path.join(homeDir, 'Downloads');
|
||||
export const systemName = os.type();
|
||||
@@ -1,17 +0,0 @@
|
||||
//QQVersionType
|
||||
type QQPackageInfoType = {
|
||||
version: string;
|
||||
buildVersion: string;
|
||||
platform: string;
|
||||
eleArch: string;
|
||||
}
|
||||
type QQVersionConfigType = {
|
||||
baseVersion: string;
|
||||
curVersion: string;
|
||||
prevVersion: string;
|
||||
onErrorVersions: Array<any>;
|
||||
buildId: string;
|
||||
}
|
||||
type QQAppidTableType = {
|
||||
[key: string]: { appid: string, qua: string };
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { logDebug } from './log';
|
||||
import { RequestUtil } from './request';
|
||||
export async function checkVersion(): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const MirrorList =
|
||||
[
|
||||
'https://jsd.cdn.zzko.cn/gh/NapNeko/NapCatQQ@main/package.json',
|
||||
'https://fastly.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json',
|
||||
'https://gcore.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json',
|
||||
'https://cdn.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json'
|
||||
];
|
||||
let version = undefined;
|
||||
for (const url of MirrorList) {
|
||||
try {
|
||||
version = (await RequestUtil.HttpGetJson<{ version: string }>(url)).version;
|
||||
} catch (e) {
|
||||
logDebug('检测更新异常',e);
|
||||
}
|
||||
if (version) {
|
||||
resolve(version);
|
||||
}
|
||||
}
|
||||
reject('get verison error!');
|
||||
});
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,67 +0,0 @@
|
||||
module.exports = {
|
||||
'root': true,
|
||||
'env': {
|
||||
'es2021': true,
|
||||
'node': true
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended'
|
||||
],
|
||||
'overrides': [
|
||||
{
|
||||
'env': {
|
||||
'node': true
|
||||
},
|
||||
'files': [
|
||||
'.eslintrc.{js,cjs}'
|
||||
],
|
||||
'parserOptions': {
|
||||
'sourceType': 'script'
|
||||
}
|
||||
}
|
||||
],
|
||||
'parser': '@typescript-eslint/parser',
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 'latest',
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'plugins': [
|
||||
'@typescript-eslint',
|
||||
'import'
|
||||
],
|
||||
'settings': {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts']
|
||||
},
|
||||
'import/resolver': {
|
||||
'typescript': {
|
||||
'alwaysTryTypes': true
|
||||
}
|
||||
}
|
||||
},
|
||||
'rules': {
|
||||
'indent': [
|
||||
'error',
|
||||
2
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'quotes': [
|
||||
'error',
|
||||
'single'
|
||||
],
|
||||
'semi': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'no-unused-vars': 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
}
|
||||
};
|
||||
5
src/core/.gitignore
vendored
5
src/core/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
.idea/
|
||||
node_modules/
|
||||
dist/
|
||||
lib/
|
||||
package-lock.json
|
||||
@@ -1,3 +0,0 @@
|
||||
# @napneko/core
|
||||
|
||||
此仓库目前只用于隐藏源码,目前无法进行单独打包,只是作为 NapCatQQ 的 git submodule 引用。
|
||||
@@ -1,51 +0,0 @@
|
||||
const swc = require("@swc/core");
|
||||
const glob = require('glob');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const files = glob.sync('src/**/*.ts');
|
||||
|
||||
function transfrom(file) {
|
||||
return swc
|
||||
.transformFile(file, {
|
||||
// Some options cannot be specified in .swcrc
|
||||
sourceMaps: false,
|
||||
// Input files are treated as module by default.
|
||||
// isModule: false,
|
||||
module: {
|
||||
type: 'commonjs'
|
||||
},
|
||||
|
||||
// All options below can be configured via .swcrc
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: "typescript",
|
||||
decorators: true,
|
||||
},
|
||||
transform: {
|
||||
"legacyDecorator": true,
|
||||
"decoratorMetadata": true
|
||||
},
|
||||
target: 'es2017'
|
||||
},
|
||||
// "keepClassNames": true,
|
||||
// "loose": true
|
||||
})
|
||||
.then((output) => {
|
||||
// console.log(output.code); // transformed code
|
||||
return {
|
||||
file,
|
||||
output
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const result = await Promise.all(files.map((file) => {
|
||||
return transfrom(file)
|
||||
}));
|
||||
|
||||
await Promise.all(result.map((item) => {
|
||||
return fs.outputFile(item.file.replace('src', 'dist').replace('.ts', '.js'), item.output.code)
|
||||
}));
|
||||
//console.timeEnd('swc build');
|
||||
})()
|
||||
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "@napneko/core",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"main": "./lib/index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint --fix ./src/**/*.ts",
|
||||
"build": "npx tsc --target es2022 --experimentalDecorators && node ./scripts/obfuscator.cjs"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/NapNeko/core.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/NapNeko/core/issues"
|
||||
},
|
||||
"homepage": "https://github.com/NapNeko/core#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.7",
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@swc/core": "^1.6.1",
|
||||
"@types/node": "^20.12.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-standard-with-typescript": "^43.0.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.8",
|
||||
"vite-plugin-babel": "^1.2.0",
|
||||
"vite-plugin-dts": "^3.8.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@log4js-node/log4js-api": "^1.0.2"
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "@napneko/core",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"main": "./index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint --fix ./src/**/*.ts",
|
||||
"build:dev": "vite build --mode development",
|
||||
"build:prod": "vite build --mode production",
|
||||
"build": "npm run build:dev"
|
||||
},
|
||||
"author": "NapNeko",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/NapNeko/NapCatQQ/issues"
|
||||
},
|
||||
"homepage": "https://github.com/NapNeko/NapCatQQ#readme"
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
let JavaScriptObfuscator = require('javascript-obfuscator');
|
||||
|
||||
const dirPath = path.join(__dirname, '../dist/core');
|
||||
const outputPath = dirPath;
|
||||
|
||||
if (!fs.existsSync(outputPath)) {
|
||||
fs.mkdirSync(outputPath, {recursive: true});
|
||||
}
|
||||
|
||||
function obfuscateDir(currentPath, outputDir) {
|
||||
fs.readdir(currentPath, {withFileTypes: true}, (err, entries) => {
|
||||
if (err) throw err;
|
||||
|
||||
entries.forEach(entry => {
|
||||
const localBasePath = path.join(currentPath, entry.name);
|
||||
const outputLocalBasePath = path.join(outputDir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// 如果是目录,递归调用
|
||||
if (!fs.existsSync(outputLocalBasePath)) {
|
||||
fs.mkdirSync(outputLocalBasePath, {recursive: true});
|
||||
}
|
||||
obfuscateDir(localBasePath, outputLocalBasePath);
|
||||
} else if (entry.isFile() && path.extname(entry.name) === '.js') {
|
||||
// 如果是文件且为 .js,进行混淆
|
||||
fs.readFile(localBasePath, (err, content)=>{
|
||||
// console.log('read file', localBasePath);
|
||||
const obfuscated = JavaScriptObfuscator.obfuscate(content.toString(), {
|
||||
compact: true,
|
||||
controlFlowFlattening: true
|
||||
});
|
||||
// console.log('obfuscate file', localBasePath);
|
||||
fs.writeFile(outputLocalBasePath, obfuscated.getObfuscatedCode(), ()=>{
|
||||
// console.log(`[NapCat] [Obfuscator] ${localBasePath} => ${outputLocalBasePath}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 开始混淆
|
||||
obfuscateDir(dirPath, outputPath);
|
||||
@@ -1,29 +0,0 @@
|
||||
import { log } from "@/common/utils/log";
|
||||
|
||||
interface IDependsAdapter {
|
||||
onMSFStatusChange(arg1: number, arg2: number): void;
|
||||
|
||||
onMSFSsoError(args: unknown): void;
|
||||
|
||||
getGroupCode(args: unknown): void;
|
||||
}
|
||||
|
||||
export interface NodeIDependsAdapter extends IDependsAdapter {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IDependsAdapter): NodeIDependsAdapter;
|
||||
}
|
||||
|
||||
export class DependsAdapter implements IDependsAdapter {
|
||||
onMSFStatusChange(arg1: number, arg2: number) {
|
||||
// console.log(arg1, arg2);
|
||||
// if (arg1 == 2 && arg2 == 2) {
|
||||
// log("NapCat丢失网络连接,请检查网络")
|
||||
// }
|
||||
}
|
||||
|
||||
onMSFSsoError(args: unknown) {
|
||||
}
|
||||
|
||||
getGroupCode(args: unknown) {
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
interface IDispatcherAdapter {
|
||||
dispatchRequest(arg: unknown): void;
|
||||
|
||||
dispatchCall(arg: unknown): void;
|
||||
|
||||
dispatchCallWithJson(arg: unknown): void;
|
||||
}
|
||||
|
||||
export interface NodeIDispatcherAdapter extends IDispatcherAdapter {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IDispatcherAdapter): NodeIDispatcherAdapter;
|
||||
}
|
||||
|
||||
export class DispatcherAdapter implements IDispatcherAdapter {
|
||||
dispatchRequest(arg: unknown) {
|
||||
}
|
||||
|
||||
dispatchCall(arg: unknown) {
|
||||
}
|
||||
|
||||
dispatchCallWithJson(arg: unknown) {
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
interface IGlobalAdapter {
|
||||
onLog(...args: unknown[]): void;
|
||||
|
||||
onGetSrvCalTime(...args: unknown[]): void;
|
||||
|
||||
onShowErrUITips(...args: unknown[]): void;
|
||||
|
||||
fixPicImgType(...args: unknown[]): void;
|
||||
|
||||
getAppSetting(...args: unknown[]): void;
|
||||
|
||||
onInstallFinished(...args: unknown[]): void;
|
||||
|
||||
onUpdateGeneralFlag(...args: unknown[]): void;
|
||||
|
||||
onGetOfflineMsg(...args: unknown[]): void;
|
||||
}
|
||||
|
||||
export interface NodeIGlobalAdapter extends IGlobalAdapter {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IGlobalAdapter): NodeIGlobalAdapter;
|
||||
}
|
||||
|
||||
export class GlobalAdapter implements IGlobalAdapter {
|
||||
onLog(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGetSrvCalTime(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onShowErrUITips(...args: unknown[]) {
|
||||
}
|
||||
|
||||
fixPicImgType(...args: unknown[]) {
|
||||
}
|
||||
|
||||
getAppSetting(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onInstallFinished(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onUpdateGeneralFlag(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGetOfflineMsg(...args: unknown[]) {
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './NodeIDependsAdapter';
|
||||
export * from './NodeIDispatcherAdapter';
|
||||
export * from './NodeIGlobalAdapter';
|
||||
@@ -1,53 +0,0 @@
|
||||
import { napCatCore } from "..";
|
||||
|
||||
export class NTQQCollectionApi {
|
||||
static async createCollection(authorUin: string, authorUid: string, authorName: string, brief: string, rawData: string) {
|
||||
let param = {
|
||||
commInfo: {
|
||||
bid: 1,
|
||||
category: 2,
|
||||
author: {
|
||||
type: 1,
|
||||
numId: authorUin,
|
||||
strId: authorName,
|
||||
groupId: '0',
|
||||
groupName: '',
|
||||
uid: authorUid
|
||||
},
|
||||
customGroupId: '0',
|
||||
createTime: Date.now().toString(),
|
||||
sequence: Date.now().toString()
|
||||
},
|
||||
richMediaSummary: {
|
||||
originalUri: '',
|
||||
publisher: '',
|
||||
richMediaVersion: 0,
|
||||
subTitle: '',
|
||||
title: '',
|
||||
brief: brief,
|
||||
picList: [],
|
||||
contentType: 1
|
||||
},
|
||||
richMediaContent: {
|
||||
rawData: rawData,
|
||||
bizDataList: [],
|
||||
picList: [],
|
||||
fileList: []
|
||||
},
|
||||
need_share_url: false
|
||||
};
|
||||
return napCatCore.session.getCollectionService().createNewCollectionItem(param);
|
||||
}
|
||||
static async getAllCollection(category: number = 0, count: number = 50) {
|
||||
let param = {
|
||||
category: category,
|
||||
groupId: -1,
|
||||
forceSync: true,
|
||||
forceFromDb: false,
|
||||
timeStamp: "0",
|
||||
count: count,
|
||||
searchDown: true
|
||||
};
|
||||
return napCatCore.session.getCollectionService().getCollectionItemList(param);
|
||||
}
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
import {
|
||||
CacheFileListItem,
|
||||
CacheFileType,
|
||||
ChatCacheListItemBasic,
|
||||
ChatType,
|
||||
ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, Peer, PicElement, RawMessage
|
||||
} from '@/core/entities';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import fsPromises from 'fs/promises';
|
||||
import { log, logDebug, logError } from '@/common/utils/log';
|
||||
import { GeneralCallResult, napCatCore, OnRichMediaDownloadCompleteParams } from '@/core';
|
||||
import { calculateFileMD5 } from '@/common/utils/file';
|
||||
import * as fileType from 'file-type';
|
||||
import imageSize from 'image-size';
|
||||
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
||||
import { sessionConfig } from '@/core/sessionConfig';
|
||||
import { rkeyManager } from '../utils/rkey';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService';
|
||||
import { selfInfo } from '../data';
|
||||
|
||||
|
||||
export class NTQQFileApi {
|
||||
static async getFileType(filePath: string) {
|
||||
return fileType.fileTypeFromFile(filePath);
|
||||
}
|
||||
|
||||
static async copyFile(filePath: string, destPath: string) {
|
||||
await napCatCore.util.copyFile(filePath, destPath);
|
||||
}
|
||||
|
||||
static async getFileSize(filePath: string): Promise<number> {
|
||||
return await napCatCore.util.getFileSize(filePath);
|
||||
}
|
||||
static async getVideoUrl(peer: Peer, msgId: string, elementId: string) {
|
||||
return (await napCatCore.session.getRichMediaService().getVideoPlayUrlV2(peer, msgId, elementId, 0, { downSourceType: 1, triggerType: 1 })).urlResult.domainUrl;
|
||||
}
|
||||
// 上传文件到QQ的文件夹
|
||||
static async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
||||
// napCatCore.wrapper.util.
|
||||
const fileMd5 = await calculateFileMD5(filePath);
|
||||
let ext: string = (await NTQQFileApi.getFileType(filePath))?.ext as string || '';
|
||||
if (ext) {
|
||||
ext = '.' + ext;
|
||||
}
|
||||
let fileName = `${path.basename(filePath)}`;
|
||||
if (fileName.indexOf('.') === -1) {
|
||||
fileName += ext;
|
||||
}
|
||||
const mediaPath = napCatCore.session.getMsgService().getRichMediaFilePathForGuild({
|
||||
md5HexStr: fileMd5,
|
||||
fileName: fileName,
|
||||
elementType: elementType,
|
||||
elementSubType,
|
||||
thumbSize: 0,
|
||||
needCreate: true,
|
||||
downloadType: 1,
|
||||
file_uuid: ''
|
||||
});
|
||||
await NTQQFileApi.copyFile(filePath, mediaPath!);
|
||||
const fileSize = await NTQQFileApi.getFileSize(filePath);
|
||||
return {
|
||||
md5: fileMd5,
|
||||
fileName,
|
||||
path: mediaPath,
|
||||
fileSize,
|
||||
ext
|
||||
};
|
||||
}
|
||||
static async downloadMediaByUuid() {
|
||||
//napCatCore.session.getRichMediaService().downloadFileForFileUuid();
|
||||
}
|
||||
static async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
|
||||
//logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force);
|
||||
// 用于下载收到的消息中的图片等
|
||||
if (sourcePath && fs.existsSync(sourcePath)) {
|
||||
if (force) {
|
||||
try {
|
||||
await fsPromises.unlink(sourcePath);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
} else {
|
||||
return sourcePath;
|
||||
}
|
||||
}
|
||||
let data = await NTEventDispatch.CallNormalEvent<
|
||||
(
|
||||
params: {
|
||||
fileModelId: string,
|
||||
downloadSourceType: number,
|
||||
triggerType: number,
|
||||
msgId: string,
|
||||
chatType: ChatType,
|
||||
peerUid: string,
|
||||
elementId: string,
|
||||
thumbSize: number,
|
||||
downloadType: number,
|
||||
filePath: string
|
||||
}) => Promise<unknown>,
|
||||
(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) => void
|
||||
>(
|
||||
'NodeIKernelMsgService/downloadRichMedia',
|
||||
'NodeIKernelMsgListener/onRichMediaDownloadComplete',
|
||||
1,
|
||||
timeout,
|
||||
(arg: OnRichMediaDownloadCompleteParams) => {
|
||||
if (arg.msgId === msgId) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
{
|
||||
fileModelId: '0',
|
||||
downloadSourceType: 0,
|
||||
triggerType: 1,
|
||||
msgId: msgId,
|
||||
chatType: chatType,
|
||||
peerUid: peerUid,
|
||||
elementId: elementId,
|
||||
thumbSize: 0,
|
||||
downloadType: 1,
|
||||
filePath: thumbPath
|
||||
}
|
||||
);
|
||||
let filePath = data[1].filePath;
|
||||
if (filePath.startsWith('\\')) {
|
||||
// log('filePath start with \\');
|
||||
const downloadPath = sessionConfig.defaultFileDownloadPath;
|
||||
//logDebug('downloadPath', downloadPath);
|
||||
filePath = path.join(downloadPath, filePath);
|
||||
// 下载路径是下载文件夹的相对路径
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
static async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
imageSize(filePath, (err, dimensions) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(dimensions);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
static async addFileCache(peer: Peer, msgId: string, msgSeq: string, senderUid: string, elemId: string, elemType: string, fileSize: string, fileName: string) {
|
||||
let GroupData;
|
||||
let BuddyData;
|
||||
if (peer.chatType === ChatType.group) {
|
||||
GroupData =
|
||||
[{
|
||||
groupCode: peer.peerUid,
|
||||
isConf: false,
|
||||
hasModifyConfGroupFace: true,
|
||||
hasModifyConfGroupName: true,
|
||||
groupName: "NapCat.Cached",
|
||||
remark: "NapCat.Cached"
|
||||
}];
|
||||
} else if (peer.chatType === ChatType.friend) {
|
||||
BuddyData = [{
|
||||
category_name: 'NapCat.Cached',
|
||||
peerUid: peer.peerUid,
|
||||
peerUin: peer.peerUid,
|
||||
remark: 'NapCat.Cached'
|
||||
}];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return napCatCore.session.getSearchService().addSearchHistory({
|
||||
type: 4,
|
||||
contactList: [],
|
||||
id: -1,
|
||||
groupInfos: [],
|
||||
msgs: [],
|
||||
fileInfos: [
|
||||
{
|
||||
chatType: peer.chatType,
|
||||
buddyChatInfo: BuddyData || [],
|
||||
discussChatInfo: [],
|
||||
groupChatInfo: GroupData || [],
|
||||
dataLineChatInfo: [],
|
||||
tmpChatInfo: [],
|
||||
msgId: msgId,
|
||||
msgSeq: msgSeq,
|
||||
msgTime: Math.floor(Date.now() / 1000).toString(),
|
||||
senderUid: senderUid,
|
||||
senderNick: 'NapCat.Cached',
|
||||
senderRemark: 'NapCat.Cached',
|
||||
senderCard: 'NapCat.Cached',
|
||||
elemId: elemId,
|
||||
elemType: elemType,
|
||||
fileSize: fileSize,
|
||||
filePath: '',
|
||||
fileName: fileName,
|
||||
hits: [{
|
||||
start: 12,
|
||||
end: 14
|
||||
}]
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
static async searchfile(keys: string[]) {
|
||||
type EventType = NodeIKernelSearchService['searchFileWithKeywords'];
|
||||
interface OnListener {
|
||||
searchId: string,
|
||||
hasMore: boolean,
|
||||
resultItems: {
|
||||
chatType: ChatType,
|
||||
buddyChatInfo: any[],
|
||||
discussChatInfo: any[],
|
||||
groupChatInfo:
|
||||
{
|
||||
groupCode: string,
|
||||
isConf: boolean,
|
||||
hasModifyConfGroupFace: boolean,
|
||||
hasModifyConfGroupName: boolean,
|
||||
groupName: string,
|
||||
remark: string
|
||||
}[]
|
||||
,
|
||||
dataLineChatInfo: any[],
|
||||
tmpChatInfo: any[],
|
||||
msgId: string,
|
||||
msgSeq: string,
|
||||
msgTime: string,
|
||||
senderUid: string,
|
||||
senderNick: string,
|
||||
senderRemark: string,
|
||||
senderCard: string,
|
||||
elemId: string,
|
||||
elemType: number,
|
||||
fileSize: string,
|
||||
filePath: string,
|
||||
fileName: string,
|
||||
hits:
|
||||
{
|
||||
start: number,
|
||||
end: number
|
||||
}[]
|
||||
}[]
|
||||
};
|
||||
const Event = await NTEventDispatch.CreatEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords');
|
||||
let id = '';
|
||||
const Listener = NTEventDispatch.RegisterListen<(params: OnListener) => void>('NodeIKernelSearchListener/onSearchFileKeywordsResult', 1, 20000, (params) => {
|
||||
if (id !== '' && params.searchId == id) {
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
});
|
||||
id = await Event!(keys, 12);
|
||||
let [ret] = (await Listener);
|
||||
return ret;
|
||||
}
|
||||
static async getImageUrl(element: PicElement) {
|
||||
if (!element) {
|
||||
return '';
|
||||
}
|
||||
const url: string = element.originImageUrl!; // 没有域名
|
||||
const md5HexStr = element.md5HexStr;
|
||||
const fileMd5 = element.md5HexStr;
|
||||
const fileUuid = element.fileUuid;
|
||||
|
||||
if (url) {
|
||||
let UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
|
||||
let imageAppid = UrlParse.searchParams.get('appid');
|
||||
let isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid);
|
||||
if (isNewPic) {
|
||||
let UrlRkey = UrlParse.searchParams.get('rkey');
|
||||
if (UrlRkey) {
|
||||
return IMAGE_HTTP_HOST_NT + url;
|
||||
}
|
||||
const rkeyData = await rkeyManager.getRkey();
|
||||
UrlRkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||
return IMAGE_HTTP_HOST_NT + url + `${UrlRkey}`;
|
||||
} else {
|
||||
// 老的图片url,不需要rkey
|
||||
return IMAGE_HTTP_HOST + url;
|
||||
}
|
||||
} else if (fileMd5 || md5HexStr) {
|
||||
// 没有url,需要自己拼接
|
||||
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0`;
|
||||
}
|
||||
logDebug('图片url获取失败', element);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export class NTQQFileCacheApi {
|
||||
static async setCacheSilentScan(isSilent: boolean = true) {
|
||||
return '';
|
||||
}
|
||||
|
||||
static getCacheSessionPathList() {
|
||||
return '';
|
||||
}
|
||||
|
||||
static clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
|
||||
// 参数未验证
|
||||
return napCatCore.session.getStorageCleanService().clearCacheDataByKeys(cacheKeys);
|
||||
}
|
||||
|
||||
static addCacheScannedPaths(pathMap: object = {}) {
|
||||
return napCatCore.session.getStorageCleanService().addCacheScanedPaths(pathMap);
|
||||
}
|
||||
|
||||
static scanCache(): Promise<GeneralCallResult & {
|
||||
size: string[]
|
||||
}> {
|
||||
// 需要注册Listener onFinishScan
|
||||
return napCatCore.session.getStorageCleanService().scanCache();
|
||||
}
|
||||
|
||||
static getHotUpdateCachePath() {
|
||||
// 未实现
|
||||
return '';
|
||||
}
|
||||
|
||||
static getDesktopTmpPath() {
|
||||
// 未实现
|
||||
return '';
|
||||
}
|
||||
|
||||
static getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) {
|
||||
return napCatCore.session.getStorageCleanService().getChatCacheInfo(type, pageSize, 1, pageIndex);
|
||||
}
|
||||
|
||||
static getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
|
||||
const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
|
||||
//需要五个参数
|
||||
//return napCatCore.session.getStorageCleanService().getFileCacheInfo();
|
||||
}
|
||||
|
||||
static async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {
|
||||
return napCatCore.session.getStorageCleanService().clearChatCacheInfo(chats, fileKeys);
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import { FriendRequest, FriendV2, SimpleInfo, User } from '@/core/entities';
|
||||
import { BuddyListReqType, napCatCore, NodeIKernelBuddyListener, NodeIKernelProfileService, OnBuddyChangeParams } from '@/core';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { LimitedHashTable } from '@/common/utils/MessageUnique';
|
||||
import { CacheClassFuncAsyncExtend } from '@/common/utils/helper';
|
||||
export class NTQQFriendApi {
|
||||
static async getBuddyV2(refresh = false): Promise<FriendV2[]> {
|
||||
let uids: string[] = [];
|
||||
const buddyService = napCatCore.session.getBuddyService();
|
||||
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
|
||||
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
|
||||
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||
);
|
||||
return Array.from(data.values());
|
||||
}
|
||||
@CacheClassFuncAsyncExtend(3600 * 1000, 'getBuddyIdMap', () => true)
|
||||
static async getBuddyIdMapCache(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||
return await NTQQFriendApi.getBuddyIdMap(refresh);
|
||||
}
|
||||
static async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||
let uids: string[] = [];
|
||||
let retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000);
|
||||
const buddyService = napCatCore.session.getBuddyService();
|
||||
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
|
||||
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
|
||||
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||
);
|
||||
data.forEach((value, key) => {
|
||||
retMap.set(value.uin!, value.uid!);
|
||||
});
|
||||
//console.log('getBuddyIdMap', retMap.getValue);
|
||||
return retMap;
|
||||
}
|
||||
static async getBuddyV2ExWithCate(refresh = false) {
|
||||
let uids: string[] = [];
|
||||
let categoryMap: Map<string, any> = new Map();
|
||||
const buddyService = napCatCore.session.getBuddyService();
|
||||
const buddyListV2 = refresh ? (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data : (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data;
|
||||
uids.push(
|
||||
...buddyListV2.flatMap(item => {
|
||||
item.buddyUids.forEach(uid => {
|
||||
categoryMap.set(uid, { categoryId: item.categoryId, categroyName: item.categroyName });
|
||||
});
|
||||
return item.buddyUids
|
||||
}));
|
||||
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||
);
|
||||
return Array.from(data).map(([key, value]) => {
|
||||
const category = categoryMap.get(key);
|
||||
return category ? { ...value, categoryId: category.categoryId, categroyName: category.categroyName } : value;
|
||||
});
|
||||
}
|
||||
static async isBuddy(uid: string) {
|
||||
return napCatCore.session.getBuddyService().isBuddy(uid);
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
* @param forced
|
||||
* @returns
|
||||
*/
|
||||
static async getFriends(forced = false): Promise<User[]> {
|
||||
let [_retData, _BuddyArg] = await NTEventDispatch.CallNormalEvent
|
||||
<(force: boolean) => Promise<any>, (arg: OnBuddyChangeParams) => void>
|
||||
(
|
||||
'NodeIKernelBuddyService/getBuddyList',
|
||||
'NodeIKernelBuddyListener/onBuddyListChange',
|
||||
1,
|
||||
5000,
|
||||
() => true,
|
||||
forced
|
||||
);
|
||||
const friends: User[] = [];
|
||||
for (const categoryItem of _BuddyArg) {
|
||||
for (const friend of categoryItem.buddyList) {
|
||||
friends.push(friend);
|
||||
}
|
||||
}
|
||||
return friends;
|
||||
}
|
||||
|
||||
static async handleFriendRequest(flag: string, accept: boolean) {
|
||||
let data = flag.split('|');
|
||||
if (data.length < 2) {
|
||||
return;
|
||||
}
|
||||
let friendUid = data[0];
|
||||
let reqTime = data[1];
|
||||
napCatCore.session.getBuddyService()?.approvalFriendRequest({
|
||||
friendUid: friendUid,
|
||||
reqTime: reqTime,
|
||||
accept
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
import { GroupMember, GroupRequestOperateTypes, GroupMemberRole, GroupNotify, Group, MemberExtSourceType, GroupNotifyTypes, ChatType, Peer, GroupListUpdateType } from '../entities';
|
||||
import { GeneralCallResult, NTQQUserApi, NodeIKernelGroupListener, NodeIKernelGroupService, napCatCore } from '@/core';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { log } from '@/common/utils/log';
|
||||
import { groupMembers } from '../data';
|
||||
import { CacheClassFuncAsyncExtend, runAllWithTimeout } from '@/common/utils/helper';
|
||||
export class NTQQGroupApi {
|
||||
static async setGroupAvatar(gc: string, filePath: string) {
|
||||
return napCatCore.session.getGroupService().setHeader(gc, filePath);
|
||||
}
|
||||
static async getGroups(forced = false) {
|
||||
type ListenerType = NodeIKernelGroupListener['onGroupListUpdate'];
|
||||
let [_retData, _updateType, groupList] = await NTEventDispatch.CallNormalEvent
|
||||
<(force: boolean) => Promise<any>, ListenerType>
|
||||
(
|
||||
'NodeIKernelGroupService/getGroupList',
|
||||
'NodeIKernelGroupListener/onGroupListUpdate',
|
||||
1,
|
||||
5000,
|
||||
(updateType) => true,
|
||||
forced
|
||||
);
|
||||
return groupList;
|
||||
}
|
||||
|
||||
@CacheClassFuncAsyncExtend(3600 * 1000, "LastestSendTime", () => true)
|
||||
static async getGroupMemberLastestSendTimeCache(GroupCode: string) {
|
||||
return NTQQGroupApi.getGroupMemberLastestSendTime(GroupCode);
|
||||
}
|
||||
/**
|
||||
* 通过QQ自带数据库获取群成员最后发言时间(仅返回有效数据 且消耗延迟大 需要进行缓存)
|
||||
* @param GroupCode 群号
|
||||
* @returns Map<string, string> key: uin value: sendTime
|
||||
* @example
|
||||
* let ret = await NTQQGroupApi.getGroupMemberLastestSendTime('123456');
|
||||
* for (let [uin, sendTime] of ret) {
|
||||
* console.log(uin, sendTime);
|
||||
* }
|
||||
*/
|
||||
static async getGroupMemberLastestSendTime(GroupCode: string) {
|
||||
async function getdata(uid: string) {
|
||||
let NTRet = await NTQQGroupApi.getLastestMsgByUids(GroupCode, [uid]);
|
||||
if (NTRet.result != 0 && NTRet.msgList.length < 1) {
|
||||
return undefined;
|
||||
}
|
||||
return { sendUin: NTRet.msgList[0].senderUin, sendTime: NTRet.msgList[0].msgTime }
|
||||
}
|
||||
let currentGroupMembers = groupMembers.get(GroupCode);
|
||||
let PromiseData: Promise<({
|
||||
sendUin: string;
|
||||
sendTime: string;
|
||||
} | undefined)>[] = [];
|
||||
let ret: Map<string, string> = new Map();
|
||||
if (!currentGroupMembers) {
|
||||
return ret;
|
||||
}
|
||||
for (let member of currentGroupMembers.values()) {
|
||||
PromiseData.push(getdata(member.uid).catch(() => undefined));
|
||||
}
|
||||
let allRet = await runAllWithTimeout(PromiseData, 2500);
|
||||
for (let PromiseDo of allRet) {
|
||||
if (PromiseDo) {
|
||||
ret.set(PromiseDo.sendUin, PromiseDo.sendTime);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static async getLastestMsgByUids(GroupCode: string, uids: string[]) {
|
||||
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||
chatInfo: {
|
||||
peerUid: GroupCode,
|
||||
chatType: ChatType.group,
|
||||
},
|
||||
filterMsgType: [],
|
||||
filterSendersUid: uids,
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
static async getGroupMemberAll(GroupCode: string, forced = false) {
|
||||
return napCatCore.session.getGroupService().getAllMemberList(GroupCode, forced);
|
||||
}
|
||||
static async getLastestMsg(GroupCode: string, uins: string[]) {
|
||||
let uids: Array<string> = [];
|
||||
for (let uin of uins) {
|
||||
let uid = await NTQQUserApi.getUidByUin(uin)
|
||||
if (uid) {
|
||||
uids.push(uid);
|
||||
}
|
||||
}
|
||||
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||
chatInfo: {
|
||||
peerUid: GroupCode,
|
||||
chatType: ChatType.group,
|
||||
},
|
||||
filterMsgType: [],
|
||||
filterSendersUid: uids,
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
static async getGroupRecommendContactArkJson(GroupCode: string) {
|
||||
return napCatCore.session.getGroupService().getGroupRecommendContactArkJson(GroupCode);
|
||||
}
|
||||
static async CreatGroupFileFolder(groupCode: string, folderName: string) {
|
||||
return napCatCore.session.getRichMediaService().createGroupFolder(groupCode, folderName);
|
||||
}
|
||||
static async DelGroupFile(groupCode: string, files: string[]) {
|
||||
return napCatCore.session.getRichMediaService().deleteGroupFile(groupCode, [102], files);
|
||||
}
|
||||
static async DelGroupFileFolder(groupCode: string, folderId: string) {
|
||||
return napCatCore.session.getRichMediaService().deleteGroupFolder(groupCode, folderId);
|
||||
}
|
||||
static async addGroupEssence(GroupCode: string, msgId: string) {
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
let MsgData = await napCatCore.session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false);
|
||||
let param = {
|
||||
groupCode: GroupCode,
|
||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
||||
};
|
||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
||||
return napCatCore.session.getGroupService().addGroupEssence(param);
|
||||
}
|
||||
static async removeGroupEssence(GroupCode: string, msgId: string) {
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
let MsgData = await napCatCore.session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false);
|
||||
let param = {
|
||||
groupCode: GroupCode,
|
||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
||||
};
|
||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
||||
return napCatCore.session.getGroupService().removeGroupEssence(param);
|
||||
}
|
||||
static async getSingleScreenNotifies(num: number) {
|
||||
let [_retData, _doubt, _seq, notifies] = await NTEventDispatch.CallNormalEvent
|
||||
<(arg1: boolean, arg2: string, arg3: number) => Promise<any>, (doubt: boolean, seq: string, notifies: GroupNotify[]) => void>
|
||||
(
|
||||
'NodeIKernelGroupService/getSingleScreenNotifies',
|
||||
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
|
||||
1,
|
||||
5000,
|
||||
() => true,
|
||||
false,
|
||||
'',
|
||||
num
|
||||
);
|
||||
return notifies;
|
||||
}
|
||||
static async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
|
||||
type ListenerType = NodeIKernelGroupListener['onMemberInfoChange'];
|
||||
type EventType = NodeIKernelGroupService['getMemberInfo'];
|
||||
// NTEventDispatch.CreatListenerFunction('NodeIKernelGroupListener/onGroupMemberInfoUpdate',
|
||||
//return napCatCore.session.getGroupService().getMemberInfo(GroupCode, [uid], forced);
|
||||
const [ret, _groupCode, _changeType, _members] = await NTEventDispatch.CallNormalEvent
|
||||
<EventType, ListenerType>
|
||||
(
|
||||
'NodeIKernelGroupService/getMemberInfo',
|
||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||
1,
|
||||
5000,
|
||||
(groupCode: string, changeType: number, members: Map<string, GroupMember>) => {
|
||||
return groupCode == GroupCode && members.has(uid);
|
||||
},
|
||||
GroupCode, [uid], forced
|
||||
);
|
||||
return _members.get(uid);
|
||||
}
|
||||
static async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||
const groupService = napCatCore.session.getGroupService();
|
||||
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
|
||||
const result = await groupService.getNextMemberList(sceneId!, undefined, num);
|
||||
if (result.errCode !== 0) {
|
||||
throw ('获取群成员列表出错,' + result.errMsg);
|
||||
}
|
||||
|
||||
//logDebug(`获取群(${groupQQ})成员列表结果:`, `finish: ${result.result.finish}`); //, Array.from(result.result.infos.values()));
|
||||
return result.result.infos;
|
||||
/*
|
||||
console.log(sceneId);
|
||||
const result = await napCatCore.getGroupService().getNextMemberList(sceneId, num);
|
||||
console.log(result);
|
||||
|
||||
return result;
|
||||
*/
|
||||
}
|
||||
|
||||
static async getGroupNotifies() {
|
||||
// 获取管理员变更
|
||||
// 加群通知,退出通知,需要管理员权限
|
||||
|
||||
}
|
||||
static async GetGroupFileCount(Gids: Array<string>) {
|
||||
return napCatCore.session.getRichMediaService().batchGetGroupFileCount(Gids);
|
||||
}
|
||||
static async getGroupIgnoreNotifies() {
|
||||
}
|
||||
static async getArkJsonGroupShare(GroupCode: string) {
|
||||
let ret = await NTEventDispatch.CallNoListenerEvent
|
||||
<(GroupId: string) => Promise<GeneralCallResult & { arkJson: string }>>(
|
||||
'NodeIKernelGroupService/getGroupRecommendContactArkJson',
|
||||
5000,
|
||||
GroupCode
|
||||
);
|
||||
return ret.arkJson;
|
||||
}
|
||||
//需要异常处理
|
||||
static async uploadGroupBulletinPic(GroupCode: string, imageurl: string) {
|
||||
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
||||
return napCatCore.session.getGroupService().uploadGroupBulletinPic(GroupCode, _Pskey, imageurl);
|
||||
}
|
||||
static async handleGroupRequest(flag: string, operateType: GroupRequestOperateTypes, reason?: string) {
|
||||
let flagitem = flag.split('|');
|
||||
let groupCode = flagitem[0];
|
||||
let seq = flagitem[1];
|
||||
let type = parseInt(flagitem[2]);
|
||||
|
||||
return napCatCore.session.getGroupService().operateSysNotify(
|
||||
false,
|
||||
{
|
||||
'operateType': operateType, // 2 拒绝
|
||||
'targetMsg': {
|
||||
'seq': seq, // 通知序列号
|
||||
'type': type,
|
||||
'groupCode': groupCode,
|
||||
'postscript': reason || ' ' // 仅传空值可能导致处理失败,故默认给个空格
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static async quitGroup(groupQQ: string) {
|
||||
return napCatCore.session.getGroupService().quitGroup(groupQQ);
|
||||
}
|
||||
|
||||
static async kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
|
||||
return napCatCore.session.getGroupService().kickMember(groupQQ, kickUids, refuseForever, kickReason);
|
||||
}
|
||||
|
||||
static async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
|
||||
// timeStamp为秒数, 0为解除禁言
|
||||
return napCatCore.session.getGroupService().setMemberShutUp(groupQQ, memList);
|
||||
}
|
||||
|
||||
static async banGroup(groupQQ: string, shutUp: boolean) {
|
||||
return napCatCore.session.getGroupService().setGroupShutUp(groupQQ, shutUp);
|
||||
}
|
||||
|
||||
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
||||
return napCatCore.session.getGroupService().modifyMemberCardName(groupQQ, memberUid, cardName);
|
||||
}
|
||||
|
||||
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
|
||||
return napCatCore.session.getGroupService().modifyMemberRole(groupQQ, memberUid, role);
|
||||
}
|
||||
|
||||
static async setGroupName(groupQQ: string, groupName: string) {
|
||||
return napCatCore.session.getGroupService().modifyGroupName(groupQQ, groupName, false);
|
||||
}
|
||||
|
||||
// 头衔不可用
|
||||
static async setGroupTitle(groupQQ: string, uid: string, title: string) {
|
||||
|
||||
}
|
||||
|
||||
static async publishGroupBulletin(groupQQ: string, content: string, picInfo: { id: string, width: number, height: number } | undefined = undefined, pinned: number = 0, confirmRequired: number = 0,) {
|
||||
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com');
|
||||
//text是content内容url编码
|
||||
let data = {
|
||||
text: encodeURI(content),
|
||||
picInfo: picInfo,
|
||||
oldFeedsId: '',
|
||||
pinned: pinned,
|
||||
confirmRequired: confirmRequired
|
||||
};
|
||||
return napCatCore.session.getGroupService().publishGroupBulletin(groupQQ, _Pskey!, data);
|
||||
}
|
||||
static async getGroupRemainAtTimes(GroupCode: string) {
|
||||
napCatCore.session.getGroupService().getGroupRemainAtTimes(GroupCode);
|
||||
}
|
||||
static async getMemberExtInfo(groupCode: string, uin: string) {
|
||||
// 仅NTQQ 9.9.11 24568测试 容易炸开谨慎使用
|
||||
return napCatCore.session.getGroupService().getMemberExtInfo(
|
||||
{
|
||||
groupCode: groupCode,
|
||||
sourceType: MemberExtSourceType.TITLETYPE,
|
||||
beginUin: '0',
|
||||
dataTime: '0',
|
||||
uinList: [uin],
|
||||
uinNum: '',
|
||||
seq: '',
|
||||
groupType: '',
|
||||
richCardNameVer: '',
|
||||
memberExtFilter: {
|
||||
memberLevelInfoUin: 1,
|
||||
memberLevelInfoPoint: 1,
|
||||
memberLevelInfoActiveDay: 1,
|
||||
memberLevelInfoLevel: 1,
|
||||
memberLevelInfoName: 1,
|
||||
levelName: 1,
|
||||
dataTime: 1,
|
||||
userShowFlag: 1,
|
||||
sysShowFlag: 1,
|
||||
timeToUpdate: 1,
|
||||
nickName: 1,
|
||||
specialTitle: 1,
|
||||
levelNameNew: 1,
|
||||
userShowFlagNew: 1,
|
||||
msgNeedField: 1,
|
||||
cmdUinFlagExt3Grocery: 1,
|
||||
memberIcon: 1,
|
||||
memberInfoSeq: 1
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export * from './file';
|
||||
export * from './friend';
|
||||
export * from './group';
|
||||
export * from './msg';
|
||||
export * from './user';
|
||||
export * from './webapi';
|
||||
export * from './sign';
|
||||
export * from './system';
|
||||
@@ -1,317 +0,0 @@
|
||||
import { GetFileListParam, Peer, RawMessage, SendMessageElement, SendMsgElementConstructor } from '@/core/entities';
|
||||
import { friends, groups, selfInfo } from '@/core/data';
|
||||
import { log, logWarn } from '@/common/utils/log';
|
||||
import { sleep } from '@/common/utils/helper';
|
||||
import { napCatCore, NTQQUserApi } from '@/core';
|
||||
import { onGroupFileInfoUpdateParamType } from '@/core/listeners';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
import { MessageUnique } from '../../../common/utils/MessageUnique';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { requireMinNTQQBuild } from '@/common/utils/QQBasicInfo';
|
||||
|
||||
async function LoadMessageIdList(Peer: Peer, msgId: string) {
|
||||
let msgList = await NTQQMsgApi.getMsgHistory(Peer, msgId, 50);
|
||||
for (let j = 0; j < msgList.msgList.length; j++) {
|
||||
let shortId = MessageUnique.createMsg(Peer, msgList.msgList[j].msgId);
|
||||
}
|
||||
}
|
||||
async function loadMessageUnique() {
|
||||
if (groups.size > 100) {
|
||||
logWarn('[性能检测] 群数量大于100,可能会导致性能问题');
|
||||
}
|
||||
let predict = (groups.size + friends.size / 2) / 5;
|
||||
predict = predict < 20 ? 20 : predict;
|
||||
predict = predict > 50 ? 50 : predict;
|
||||
//let waitpromise: Array<Promise<{ msgList: RawMessage[]; }>> = [];
|
||||
predict = Math.floor(predict * 50);
|
||||
MessageUnique.resize(predict);
|
||||
let RecentContact = await NTQQUserApi.getRecentContactListSnapShot(predict);
|
||||
let LoadMessageIdDo: Array<Promise<void>> = new Array<Promise<void>>();
|
||||
if (RecentContact?.info?.changedList && RecentContact?.info?.changedList?.length > 0) {
|
||||
for (let i = 0; i < RecentContact.info.changedList.length; i++) {
|
||||
let Peer: Peer = { chatType: RecentContact.info.changedList[i].chatType, peerUid: RecentContact.info.changedList[i].peerUid, guildId: '' };
|
||||
LoadMessageIdDo.push(LoadMessageIdList(Peer, RecentContact.info.changedList[i].msgId));
|
||||
}
|
||||
}
|
||||
await Promise.all(LoadMessageIdDo).then(() => {
|
||||
log(`[消息序列] 加载 ${predict} 条历史消息记录完成`);
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
napCatCore.onLoginSuccess(async () => {
|
||||
await sleep(100);
|
||||
// NTQQMsgApi.CheckSendMode().then().catch();
|
||||
loadMessageUnique().then().catch();
|
||||
//下面的代码还没摸清 不要使用
|
||||
//let data = await napCatCore.session.getMsgService().sendSsoCmdReqByContend("LightAppSvc.mini_app_growguard.ReportExecute","1124343");
|
||||
//console.log(data);
|
||||
});
|
||||
}, 100);
|
||||
//歇菜LocalMsg压根不写Db
|
||||
// setTimeout(async () => {
|
||||
// let ele: MessageElement = { extBufForUI: '0x', ...SendMsgElementConstructor.text('测试消息') };
|
||||
// let MsgId = await NTQQMsgApi.getMsgUniqueEx();
|
||||
// let peer = { chatType: 2, peerUid: '', guildId: '' };
|
||||
// console.log(await napCatCore.session.getTestPerformanceService().insertMsg(
|
||||
// {
|
||||
// peer: peer,
|
||||
// msgTime: Math.floor(Date.now() / 1000).toString(),
|
||||
// msgId: MsgId,
|
||||
// msgSeq: '56564',
|
||||
// batchNums: 1,
|
||||
// timesPerBatch: 1,
|
||||
// numPerTime: 1
|
||||
// }, [ele]
|
||||
// ));
|
||||
// console.log(await NTQQMsgApi.multiForwardMsg(peer, peer, [MsgId]));
|
||||
// }, 25000)
|
||||
|
||||
export class NTQQMsgApi {
|
||||
static async FetchLongMsg(peer: Peer, msgId: string) {
|
||||
return napCatCore.session.getMsgService().fetchLongMsg(peer, msgId);
|
||||
}
|
||||
static async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
|
||||
//console.log(peer, msgSeq, emojiId, emojiType, count);
|
||||
//注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged M likiowa
|
||||
return napCatCore.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, "", false, 20)
|
||||
}
|
||||
// static napCatCore: NapCatCore | null = null;
|
||||
// enum BaseEmojiType {
|
||||
// NORMAL_EMOJI,
|
||||
// SUPER_EMOJI,
|
||||
// RANDOM_SUPER_EMOJI,
|
||||
// CHAIN_SUPER_EMOJI,
|
||||
// EMOJI_EMOJI
|
||||
// }
|
||||
static async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set: boolean = true) {
|
||||
// nt_qq//global//nt_data//Emoji//emoji-resource//sysface_res/apng/ 下可以看到所有QQ表情预览
|
||||
// nt_qq\global\nt_data\Emoji\emoji-resource\face_config.json 里面有所有表情的id, 自带表情id是QSid, 标准emoji表情id是QCid
|
||||
// 其实以官方文档为准是最好的,https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType
|
||||
emojiId = emojiId.toString();
|
||||
return napCatCore.session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiId.length > 3 ? '2' : '1', set);
|
||||
}
|
||||
static async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
} | undefined> {
|
||||
return napCatCore.session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId);
|
||||
}
|
||||
static async ForwardMsg(peer: Peer, msgIds: string[]) {
|
||||
return napCatCore.session.getMsgService().forwardMsg(msgIds, peer, [peer], new Map());
|
||||
}
|
||||
static async getLastestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) {
|
||||
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||
chatInfo: peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: [],
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: isReverseOrder,//此参数有点离谱 注意不是本次查询的排序 而是全部消历史信息的排序 默认false 从新消息拉取到旧消息
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: count,
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
static async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) {
|
||||
if (!peer) throw new Error('peer is not allowed');
|
||||
if (!msgIds) throw new Error('msgIds is not allowed');
|
||||
//Mlikiowa: 参数不合规会导致NC异常崩溃 原因是TX未对进入参数判断 对应Android标记@NotNull AndroidJADX分析可得
|
||||
return await napCatCore.session.getMsgService().getMsgsByMsgId(peer, msgIds);
|
||||
}
|
||||
static async getSingleMsg(peer: Peer, seq: string) {
|
||||
return await napCatCore.session.getMsgService().getSingleMsg(peer, seq);
|
||||
}
|
||||
static async fetchFavEmojiList(num: number) {
|
||||
return napCatCore.session.getMsgService().fetchFavEmojiList("", num, true, true)
|
||||
}
|
||||
static async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) {
|
||||
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||
chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa
|
||||
filterMsgType: [],
|
||||
filterSendersUid: [],
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
||||
return await napCatCore.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
||||
}
|
||||
static async setMsgRead(peer: Peer) {
|
||||
return napCatCore.session.getMsgService().setMsgRead(peer);
|
||||
}
|
||||
static async getGroupFileList(GroupCode: string, params: GetFileListParam) {
|
||||
let data = await NTEventDispatch.CallNormalEvent<
|
||||
(GroupCode: string, params: GetFileListParam) => Promise<unknown>,
|
||||
(groupFileListResult: onGroupFileInfoUpdateParamType) => void
|
||||
>(
|
||||
'NodeIKernelRichMediaService/getGroupFileList',
|
||||
'NodeIKernelMsgListener/onGroupFileInfoUpdate',
|
||||
1,
|
||||
5000,
|
||||
(groupFileListResult: onGroupFileInfoUpdateParamType) => {
|
||||
//Developer Mlikiowa Todo: 此处有问题 无法判断是否成功
|
||||
return true;
|
||||
},
|
||||
GroupCode,
|
||||
params
|
||||
);
|
||||
return data[1].item;
|
||||
}
|
||||
static async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) {
|
||||
// 消息时间从旧到新
|
||||
return napCatCore.session.getMsgService().getMsgsIncludeSelf(peer, msgId, count, isReverseOrder);
|
||||
}
|
||||
static async recallMsg(peer: Peer, msgIds: string[]) {
|
||||
await napCatCore.session.getMsgService().recallMsg({
|
||||
chatType: peer.chatType,
|
||||
peerUid: peer.peerUid
|
||||
}, msgIds);
|
||||
}
|
||||
static async sendMsgV2(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
function generateMsgId() {
|
||||
const timestamp = Math.floor(Date.now() / 1000);
|
||||
const random = Math.floor(Math.random() * Math.pow(2, 32));
|
||||
const buffer = Buffer.alloc(8);
|
||||
buffer.writeUInt32BE(timestamp, 0);
|
||||
buffer.writeUInt32BE(random, 4);
|
||||
const msgId = BigInt("0x" + buffer.toString('hex')).toString();
|
||||
return msgId;
|
||||
}
|
||||
// 此处有采用Hack方法 利用数据返回正确得到对应消息
|
||||
// 与之前 Peer队列 MsgSeq队列 真正的MsgId并发不同
|
||||
// 谨慎采用 目前测试暂无问题 Developer.Mlikiowa
|
||||
let msgId: string;
|
||||
try {
|
||||
msgId = await NTQQMsgApi.getMsgUnique(peer.chatType, await NTQQMsgApi.getServerTime());
|
||||
} catch (error) {
|
||||
//if (!napCatCore.session.getMsgService()['generateMsgUniqueId'])
|
||||
//兜底识别策略V2
|
||||
msgId = generateMsgId().toString();
|
||||
}
|
||||
let data = await NTEventDispatch.CallNormalEvent<
|
||||
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
|
||||
(msgList: RawMessage[]) => void
|
||||
>(
|
||||
'NodeIKernelMsgService/sendMsg',
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
1,
|
||||
timeout,
|
||||
(msgRecords: RawMessage[]) => {
|
||||
for (let msgRecord of msgRecords) {
|
||||
if (msgRecord.msgId === msgId && msgRecord.sendStatus === 2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
msgId,
|
||||
peer,
|
||||
msgElements,
|
||||
new Map()
|
||||
);
|
||||
let retMsg = data[1].find(msgRecord => {
|
||||
if (msgRecord.msgId === msgId) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return retMsg;
|
||||
}
|
||||
static sendMsgEx(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
//return NTQQMsgApi.sendMsgV1(peer, msgElements, waitComplete, timeout);
|
||||
}
|
||||
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
//唉? !我有个想法
|
||||
let msgId = await NTQQMsgApi.getMsgUnique(peer.chatType, await NTQQMsgApi.getServerTime());
|
||||
peer.guildId = msgId;
|
||||
let data = await NTEventDispatch.CallNormalEvent<
|
||||
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
|
||||
(msgList: RawMessage[]) => void
|
||||
>(
|
||||
'NodeIKernelMsgService/sendMsg',
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
1,
|
||||
timeout,
|
||||
(msgRecords: RawMessage[]) => {
|
||||
for (let msgRecord of msgRecords) {
|
||||
if (msgRecord.guildId === msgId && msgRecord.sendStatus === 2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
"0",
|
||||
peer,
|
||||
msgElements,
|
||||
new Map()
|
||||
);
|
||||
let retMsg = data[1].find(msgRecord => {
|
||||
if (msgRecord.guildId === msgId) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return retMsg;
|
||||
}
|
||||
static async getMsgUnique(chatType: number, time: string) {
|
||||
if (requireMinNTQQBuild('26702')) {
|
||||
return napCatCore.session.getMsgService().generateMsgUniqueId(chatType, time);
|
||||
}
|
||||
return napCatCore.session.getMsgService().getMsgUniqueId(time);
|
||||
}
|
||||
static async getServerTime() {
|
||||
return napCatCore.session.getMSFService().getServerTime();
|
||||
}
|
||||
static async getServerTimeV2() {
|
||||
return NTEventDispatch.CallNoListenerEvent<() => string>('NodeIKernelMsgService/getServerTime', 5000);
|
||||
}
|
||||
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||||
return napCatCore.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], new Map());
|
||||
}
|
||||
static async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<RawMessage> {
|
||||
const msgInfos = msgIds.map(id => {
|
||||
return { msgId: id, senderShowName: selfInfo.nick };
|
||||
});
|
||||
let data = await NTEventDispatch.CallNormalEvent<
|
||||
(msgInfo: typeof msgInfos, srcPeer: Peer, destPeer: Peer, comment: Array<any>, attr: Map<any, any>,) => Promise<unknown>,
|
||||
(msgList: RawMessage[]) => void
|
||||
>(
|
||||
'NodeIKernelMsgService/multiForwardMsgWithComment',
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
1,
|
||||
5000,
|
||||
(msgRecords: RawMessage[]) => {
|
||||
for (let msgRecord of msgRecords) {
|
||||
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == selfInfo.uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
msgInfos,
|
||||
srcPeer,
|
||||
destPeer,
|
||||
[],
|
||||
new Map()
|
||||
);
|
||||
for (let msg of data[1]) {
|
||||
const arkElement = msg.elements.find(ele => ele.arkElement);
|
||||
if (!arkElement) {
|
||||
continue;
|
||||
}
|
||||
const forwardData: any = JSON.parse(arkElement.arkElement.bytesData);
|
||||
if (forwardData.app != 'com.tencent.multimsg') {
|
||||
continue;
|
||||
}
|
||||
if (msg.peerUid == destPeer.peerUid && msg.senderUid == selfInfo.uid) {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
throw new Error('转发消息超时');
|
||||
}
|
||||
static async markallMsgAsRead() {
|
||||
return napCatCore.session.getMsgService().setAllC2CAndGroupMsgRead();
|
||||
}
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
import { logDebug } from '@/common/utils/log';
|
||||
import { NTQQUserApi } from './user';
|
||||
import { selfInfo } from '../data';
|
||||
import { RequestUtil } from '@/common/utils/request';
|
||||
import { WebApi } from './webapi';
|
||||
import { checkFileReceived, checkFileReceived2, uri2local } from '@/common/utils/file';
|
||||
import fs from 'node:fs'
|
||||
import { sleep } from '@/common/utils/helper';
|
||||
export interface IdMusicSignPostData {
|
||||
type: 'qq' | '163',
|
||||
id: string | number,
|
||||
}
|
||||
|
||||
export interface CustomMusicSignPostData {
|
||||
type: 'custom',
|
||||
url: string,
|
||||
audio: string,
|
||||
title: string,
|
||||
image?: string,
|
||||
singer?: string
|
||||
}
|
||||
// let t = await napCatCore.session.getGroupService().shareDigest({
|
||||
// appId: "100497308",
|
||||
// appType: 1,
|
||||
// msgStyle: 0,
|
||||
// recvUin: "726067488",
|
||||
// sendType: 1,
|
||||
// clientInfo: {
|
||||
// platform: 1
|
||||
// },
|
||||
// richMsg: {
|
||||
// usingArk: true,
|
||||
// title: "Bot测试title",
|
||||
// summary: "Bot测试summary",
|
||||
// url: "https://www.bilibili.com",
|
||||
// pictureUrl: "https://y.qq.com/music/photo_new/T002R300x300M0000035DC6W4ZpSqf_1.jpg?max_age=2592000",
|
||||
// brief: "Bot测试brief",
|
||||
// }
|
||||
// });
|
||||
// {
|
||||
// errCode: 0,
|
||||
// errMsg: '',
|
||||
// rsp: {
|
||||
// sendType: 1,
|
||||
// recvUin: '726067488',
|
||||
// recvOpenId: '',
|
||||
// errCode: 901501,
|
||||
// errMsg: 'imagent service_error:150_OIDB_NO_PRIV',
|
||||
// extInfo: {
|
||||
// wording: '消息下发失败(错误码:901501)',
|
||||
// jumpResult: 0,
|
||||
// jumpUrl: '',
|
||||
// level: 0,
|
||||
// subLevel: 0,
|
||||
// developMsg: 'imagent error'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// export class MusicSign {
|
||||
// private readonly url: string;
|
||||
|
||||
// constructor(url: string) {
|
||||
// this.url = url;
|
||||
// }
|
||||
|
||||
// sign(postData: CustomMusicSignPostData | IdMusicSignPostData): Promise<any> {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// fetch(this.url, {
|
||||
// method: 'POST', // 指定请求方法为 POST
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json' // 设置请求头,指明发送的数据类型为 JSON
|
||||
// },
|
||||
// body: JSON.stringify(postData) // 将 JavaScript 对象转换为 JSON 字符串作为请求体
|
||||
// })
|
||||
// .then(response => {
|
||||
// if (!response.ok) {
|
||||
// reject(response.statusText); // 请求失败,返回错误信息
|
||||
// }
|
||||
// return response.json(); // 解析 JSON 格式的响应体
|
||||
// })
|
||||
// .then(data => {
|
||||
// logDebug('音乐消息生成成功', data);
|
||||
// resolve(data);
|
||||
// })
|
||||
// .catch(error => {
|
||||
// reject(error);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
export interface MiniAppLuaJsonType {
|
||||
prompt: string,
|
||||
title: string,
|
||||
preview: string,
|
||||
jumpUrl: string,
|
||||
tag: string,
|
||||
tagIcon: string,
|
||||
source: string,
|
||||
sourcelogo: string,
|
||||
}
|
||||
export async function SignMiniApp(CardData: MiniAppLuaJsonType) {
|
||||
// {
|
||||
// "app": "com.tencent.miniapp.lua",
|
||||
// "bizsrc": "tianxuan.imgJumpArk",
|
||||
// "view": "miniapp",
|
||||
// "prompt": "hi! 这里有我的日常故事,只想讲给你听",
|
||||
// "config": {
|
||||
// "type": "normal",
|
||||
// "forward": 1,
|
||||
// "autosize": 0
|
||||
// },
|
||||
// "meta": {
|
||||
// "miniapp": {
|
||||
// "title": "hi! 这里有我的日常故事,只想讲给你听",
|
||||
// "preview": "https:\/\/tianquan.gtimg.cn\/qqAIAgent\/item\/7\/square.png",
|
||||
// "jumpUrl": "https:\/\/club.vip.qq.com\/transfer?open_kuikly_info=%7B%22version%22%3A%20%221%22%2C%22src_type%22%3A%20%22web%22%2C%22kr_turbo_display%22%3A%20%221%22%2C%22page_name%22%3A%20%22vas_ai_persona_moments%22%2C%22bundle_name%22%3A%20%22vas_ai_persona_moments%22%7D&page_name=vas_ai_persona_moments&enteranceId=share&robot_uin=3889008584",
|
||||
// "tag": "QQ智能体",
|
||||
// "tagIcon": "https:\/\/tianquan.gtimg.cn\/shoal\/qqAIAgent\/3e9d70c9-d98c-45b8-80b4-79d82971b514.png",
|
||||
// "source": "QQ智能体",
|
||||
// "sourcelogo": "https:\/\/tianquan.gtimg.cn\/shoal\/qqAIAgent\/3e9d70c9-d98c-45b8-80b4-79d82971b514.png"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// token : function(url,skey){
|
||||
// var str = skey || cookie('skey') || cookie('rv2') || '',
|
||||
// hash = 5381;
|
||||
// if(url){
|
||||
// var hostname = uri(url).hostname;
|
||||
// if(hostname.indexOf('qun.qq.com') > -1 || (hostname.indexOf('qzone.qq.com') > -1 && hostname.indexOf('qun.qzone.qq.com') === -1)){
|
||||
// str = cookie('p_skey') || str;
|
||||
// }
|
||||
// }
|
||||
// for(var i = 0, len = str.length; i < len; ++i){
|
||||
// hash += (hash << 5) + str.charAt(i).charCodeAt();
|
||||
// }
|
||||
// return hash & 0x7fffffff;
|
||||
// },
|
||||
//
|
||||
|
||||
// function signToken(skey: string) {
|
||||
// let hash = 5381;
|
||||
// for (let i = 0, len = skey.length; i < len; ++i) {
|
||||
// hash += (hash << 5) + skey.charCodeAt(i);
|
||||
// }
|
||||
// return hash & 0x7fffffff;
|
||||
// }
|
||||
let signCard = {
|
||||
"app": "com.tencent.miniapp.lua",
|
||||
"bizsrc": "tianxuan.imgJumpArk",
|
||||
"view": "miniapp",
|
||||
"prompt": CardData.prompt,
|
||||
"config": {
|
||||
"type": "normal",
|
||||
"forward": 1,
|
||||
"autosize": 0
|
||||
},
|
||||
"meta": {
|
||||
"miniapp": {
|
||||
"title": CardData.title,
|
||||
"preview": (CardData.preview as string).replace(/\\/g, "\\/\\/"),
|
||||
"jumpUrl": (CardData.jumpUrl as string).replace(/\\/g, "\\/\\/"),
|
||||
"tag": CardData.tag,
|
||||
"tagIcon": (CardData.tagIcon as string).replace(/\\/g, "\\/\\/"),
|
||||
"source": CardData.source,
|
||||
"sourcelogo": (CardData.sourcelogo as string).replace(/\\/g, "\\/\\/")
|
||||
}
|
||||
}
|
||||
};
|
||||
// let signCard = {
|
||||
// "app": "com.tencent.eventshare.lua",
|
||||
// "prompt": "Bot Test",
|
||||
// "bizsrc": "tianxuan.business",
|
||||
// "meta": {
|
||||
// "eventshare": {
|
||||
// "button1URL": "https://www.bilibili.com",
|
||||
// "button1disable": false,
|
||||
// "button1title": "点我前往",
|
||||
// "button2URL": "",
|
||||
// "button2disable": false,
|
||||
// "button2title": "",
|
||||
// "buttonNum": 1,
|
||||
// "jumpURL": "https://www.bilibili.com",
|
||||
// "preview": "https://tianquan.gtimg.cn/shoal/card/9930bc4e-4a92-4da3-814f-8094a2421d9c.png",
|
||||
// "tag": "QQ集卡",
|
||||
// "tagIcon": "https://tianquan.gtimg.cn/shoal/card/c034854b-102d-40be-a545-5ca90a7c49c9.png",
|
||||
// "title": "Bot Test"
|
||||
// }
|
||||
// },
|
||||
// "config": {
|
||||
// "autosize": 0,
|
||||
// "collect": 0,
|
||||
// "ctime": 1716568575,
|
||||
// "forward": 1,
|
||||
// "height": 336,
|
||||
// "reply": 0,
|
||||
// "round": 1,
|
||||
// "type": "normal",
|
||||
// "width": 263
|
||||
// },
|
||||
// "view": "eventshare",
|
||||
// "ver": "0.0.0.1"
|
||||
// };
|
||||
let data = (await NTQQUserApi.getQzoneCookies());
|
||||
const Bkn = WebApi.genBkn(data.p_skey);
|
||||
|
||||
const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + selfInfo.uin + '; uin=o' + selfInfo.uin;
|
||||
|
||||
let signurl = "https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=" + Bkn + "&ark=" + encodeURIComponent(JSON.stringify(signCard));
|
||||
let signed_ark = "";
|
||||
try {
|
||||
let retData = await RequestUtil.HttpGetJson<{ code: number, data: { signed_ark: string } }>(signurl, 'GET', undefined, { Cookie: CookieValue });
|
||||
//logDebug('MiniApp JSON 消息生成成功', retData);
|
||||
signed_ark = retData.data.signed_ark;
|
||||
} catch (error) {
|
||||
logDebug('MiniApp JSON 消息生成失败', error);
|
||||
}
|
||||
return signed_ark;
|
||||
}
|
||||
export async function SignMusicInternal(songname: string, singer: string, cover: string, songmid: string, songmusic: string) {
|
||||
//curl -X POST 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003' -H 'Content-Type: application/json' -H 'Cookie: uin=o10086' -d '{"app":"com.tencent.qqreader.share","config":{"ctime":1718634110,"forward":1,"token":"9a63343c32d5a16bcde653eb97faa25d","type":"normal"},"extra":{"app_type":1,"appid":100497308,"msg_seq":14386738075403815000.0,"uin":1733139081},"meta":{"music":{"action":"","android_pkg_name":"","app_type":1,"appid":100497308,"ctime":1718634110,"desc":"周杰伦","jumpUrl":"https://i.y.qq.com/v8/playsong.html?songmid=0039MnYb0qxYhV&type=0","musicUrl":"http://ws.stream.qqmusic.qq.com/http://isure6.stream.qqmusic.qq.com/M800002202B43Cq4V4.mp3?fromtag=810033622&guid=br_xzg&trace=23fe7bcbe2336bbf&uin=553&vkey=CF0F5CE8B0FA16F3001F8A88D877A217EB5E4F00BDCEF1021EB6C48969CA33C6303987AEECE9CC840122DD2F917A59D6130D8A8CA4577C87","preview":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","cover":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","sourceMsgId":"0","source_icon":"https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0","source_url":"","tag":"QQ音乐","title":"晴天","uin":10086}},"prompt":"[分享]晴天","ver":"0.0.0.1","view":"music"}'
|
||||
let signurl = 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003';
|
||||
//let = "https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg";
|
||||
let signCard = {
|
||||
app: "com.tencent.qqreader.share",
|
||||
config: {
|
||||
ctime: 1718634110,
|
||||
forward: 1,
|
||||
token: "9a63343c32d5a16bcde653eb97faa25d",
|
||||
type: "normal"
|
||||
},
|
||||
extra: {
|
||||
app_type: 1,
|
||||
appid: 100497308,
|
||||
msg_seq: 14386738075403815000.0,
|
||||
uin: 1733139081
|
||||
},
|
||||
meta: {
|
||||
music:
|
||||
{
|
||||
action: "",
|
||||
android_pkg_name: "",
|
||||
app_type: 1,
|
||||
appid: 100497308,
|
||||
ctime: 1718634110,
|
||||
desc: singer,
|
||||
jumpUrl: "https://i.y.qq.com/v8/playsong.html?songmid=" + songmid + "&type=0",
|
||||
musicUrl: songmusic,
|
||||
preview: cover,
|
||||
cover: cover,
|
||||
sourceMsgId: "0",
|
||||
source_icon: "https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0",
|
||||
source_url: "",
|
||||
tag: "QQ音乐",
|
||||
title: songname,
|
||||
uin: 10086
|
||||
}
|
||||
},
|
||||
prompt: "[分享]" + songname,
|
||||
ver: "0.0.0.1",
|
||||
view: "music"
|
||||
}
|
||||
//console.log(JSON.stringify(signCard, null, 2));
|
||||
let data = await RequestUtil.HttpGetJson<{ code: number, data: { arkResult: string } }>
|
||||
(signurl, 'POST', signCard, { 'Cookie': 'uin=o10086', 'Content-Type': 'application/json' });
|
||||
return data;
|
||||
}
|
||||
//注意处理错误
|
||||
export async function CreateMusicThridWay0(id: string = '', mid: string = '') {
|
||||
if (mid == '') {
|
||||
let MusicInfo = await RequestUtil.HttpGetJson
|
||||
<{ songinfo?: { data?: { track_info: { mid: string } } } }>
|
||||
(
|
||||
'https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"songinfo":{"method":"get_song_detail_yqq","param":{"song_type":0,"song_mid":"","song_id":' + id + '},"module":"music.pf_song_detail_svr"}}',
|
||||
'GET',
|
||||
undefined
|
||||
);
|
||||
mid = MusicInfo.songinfo?.data?.track_info.mid!;
|
||||
}
|
||||
//第三方接口 存在速率限制 现在勉强用
|
||||
let MusicReal = await RequestUtil.HttpGetJson
|
||||
<{ code: number, data?: { name: string, singer: string, url: string, cover: string } }>
|
||||
('https://api.leafone.cn/api/qqmusic?id=' + mid + '&type=8', 'GET', undefined);
|
||||
//console.log(MusicReal);
|
||||
return { ...MusicReal.data, mid: mid };
|
||||
}
|
||||
export async function CreateMusicThridWay1(id: string = '', mid: string = '') {
|
||||
|
||||
}
|
||||
//转换外域名为 https://qq.ugcimg.cn/v1/cpqcbu4b8870i61bde6k7cbmjgejq8mr3in82qir4qi7ielffv5slv8ck8g42novtmev26i233ujtuab6tvu2l2sjgtupfr389191v00s1j5oh5325j5eqi40774jv1i/khovifoh7jrqd6eahoiv7koh8o
|
||||
//https://cgi.connect.qq.com/qqconnectopen/openapi/change_image_url?url=https://th.bing.com/th?id=OSK.b8ed36f1fb1889de6dc84fd81c187773&w=46&h=46&c=11&rs=1&qlt=80&o=6&dpr=2&pid=SANGAM
|
||||
|
||||
//外域名不行得走qgroup中转
|
||||
//https://proxy.gtimg.cn/tx_tls_gate=y.qq.com/music/photo_new/T002R800x800M000000y5gq7449K9I.jpg
|
||||
|
||||
//可外域名
|
||||
//https://pic.ugcimg.cn/500955bdd6657ecc8e82e02d2df06800/jpg1
|
||||
|
||||
//QQ音乐gtimg接口
|
||||
//https://y.gtimg.cn/music/photo_new/T002R800x800M000000y5gq7449K9I.jpg?max_age=2592000
|
||||
|
||||
//还有一处公告上传可以上传高质量图片 持久为qq域名
|
||||
export async function SignMusicWrapper(id: string = '') {
|
||||
let MusicInfo = await CreateMusicThridWay0(id)!;
|
||||
let MusicCard = await SignMusicInternal(MusicInfo.name!, MusicInfo.singer!, MusicInfo.cover!, MusicInfo.mid!, "https://ws.stream.qqmusic.qq.com/" + MusicInfo.url!);
|
||||
return MusicCard;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { GeneralCallResult, NTQQFileApi, NTQQUserApi, napCatCore } from '@/core';
|
||||
export class NTQQSystemApi {
|
||||
static async hasOtherRunningQQProcess() {
|
||||
return napCatCore.util.hasOtherRunningQQProcess();
|
||||
}
|
||||
static async ORCImage(filePath: string) {
|
||||
return napCatCore.session.getNodeMiscService().wantWinScreenOCR(filePath);
|
||||
}
|
||||
static async translateEnWordToZn(words: string[]) {
|
||||
return napCatCore.session.getRichMediaService().translateEnWordToZn(words);
|
||||
}
|
||||
//调用会超时 没灯用 (好像是通知listener的) onLineDev
|
||||
static async getOnlineDev() {
|
||||
return napCatCore.session.getMsgService().getOnLineDev();
|
||||
}
|
||||
//1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50
|
||||
static async getArkJsonCollection(cid: string) {
|
||||
let ret = await NTEventDispatch.CallNoListenerEvent
|
||||
<(cid: string) => Promise<GeneralCallResult & { arkJson: string }>>(
|
||||
'NodeIKernelCollectionService/collectionArkShare',
|
||||
5000,
|
||||
'1717662698058'
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
static async BootMiniApp(appfile: string, params: string) {
|
||||
await napCatCore.session.getNodeMiscService().setMiniAppVersion('2.16.4');
|
||||
let c = await napCatCore.session.getNodeMiscService().getMiniAppPath();
|
||||
|
||||
return napCatCore.session.getNodeMiscService().startNewMiniApp(appfile, params);
|
||||
}
|
||||
}
|
||||
@@ -1,357 +0,0 @@
|
||||
import { ModifyProfileParams, SelfInfo, User, UserDetailInfoByUin, UserDetailInfoByUinV2 } from '@/core/entities';
|
||||
import { friends, groupMembers, selfInfo } from '@/core/data';
|
||||
import { CacheClassFuncAsync, CacheClassFuncAsyncExtend } from '@/common/utils/helper';
|
||||
import { napCatCore, NTQQFriendApi } from '@/core';
|
||||
import { NodeIKernelProfileListener, ProfileListener } from '@/core/listeners';
|
||||
import { RequestUtil } from '@/common/utils/request';
|
||||
import { logWarn } from '@/common/utils/log';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { NodeIKernelProfileService, ProfileBizType, UserDetailSource } from '@/core/services';
|
||||
import { requireMinNTQQBuild } from '@/common/utils/QQBasicInfo';
|
||||
|
||||
export class NTQQUserApi {
|
||||
static async getProfileLike(uid: string) {
|
||||
return napCatCore.session.getProfileLikeService().getBuddyProfileLike({
|
||||
friendUids: [
|
||||
uid
|
||||
],
|
||||
basic: 1,
|
||||
vote: 1,
|
||||
favorite: 0,
|
||||
userProfile: 1,
|
||||
type: 2,
|
||||
start: 0,
|
||||
limit: 20
|
||||
});
|
||||
}
|
||||
static async setLongNick(longNick: string) {
|
||||
return napCatCore.session.getProfileService().setLongNick(longNick);
|
||||
}
|
||||
static async setSelfOnlineStatus(status: number, extStatus: number, batteryStatus: number) {
|
||||
return napCatCore.session.getMsgService().setStatus({ status: status, extStatus: extStatus, batteryStatus: batteryStatus });
|
||||
}
|
||||
static async getBuddyRecommendContactArkJson(uin: string, sencenID = '') {
|
||||
return napCatCore.session.getBuddyService().getBuddyRecommendContactArkJson(uin, sencenID);
|
||||
}
|
||||
static async like(uid: string, count = 1): Promise<{ result: number, errMsg: string, succCounts: number }> {
|
||||
return napCatCore.session.getProfileLikeService().setBuddyProfileLike({
|
||||
friendUid: uid,
|
||||
sourceId: 71,
|
||||
doLikeCount: count,
|
||||
doLikeTollCount: 0
|
||||
});
|
||||
}
|
||||
|
||||
static async setQQAvatar(filePath: string) {
|
||||
type setQQAvatarRet = { result: number, errMsg: string };
|
||||
const ret = await napCatCore.session.getProfileService().setHeader(filePath) as setQQAvatarRet;
|
||||
return { result: ret?.result, errMsg: ret?.errMsg };
|
||||
}
|
||||
static async setGroupAvatar(gc: string, filePath: string) {
|
||||
return napCatCore.session.getGroupService().setHeader(gc, filePath);
|
||||
}
|
||||
|
||||
static async fetchUserDetailInfos(uids: string[]) {
|
||||
//26702 以上使用新接口 .Dev Mlikiowa
|
||||
type EventService = NodeIKernelProfileService['fetchUserDetailInfo'];
|
||||
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
|
||||
let retData: User[] = [];
|
||||
let [_retData, _retListener] = await NTEventDispatch.CallNormalEvent
|
||||
<EventService, EventListener>
|
||||
(
|
||||
'NodeIKernelProfileService/fetchUserDetailInfo',
|
||||
'NodeIKernelProfileListener/onUserDetailInfoChanged',
|
||||
uids.length,
|
||||
5000,
|
||||
(profile) => {
|
||||
if (uids.includes(profile.uid)) {
|
||||
let RetUser: User = {
|
||||
...profile.simpleInfo.coreInfo,
|
||||
...profile.simpleInfo.status,
|
||||
...profile.simpleInfo.vasInfo,
|
||||
...profile.commonExt,
|
||||
...profile.simpleInfo.baseInfo,
|
||||
qqLevel: profile.commonExt.qqLevel,
|
||||
pendantId: ""
|
||||
};
|
||||
retData.push(RetUser);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
"BuddyProfileStore",
|
||||
uids,
|
||||
UserDetailSource.KSERVER,
|
||||
[
|
||||
ProfileBizType.KALL
|
||||
]
|
||||
);
|
||||
|
||||
return retData;
|
||||
}
|
||||
static async fetchUserDetailInfo(uid: string) {
|
||||
type EventService = NodeIKernelProfileService['fetchUserDetailInfo'];
|
||||
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
|
||||
let [_retData, profile] = await NTEventDispatch.CallNormalEvent
|
||||
<EventService, EventListener>
|
||||
(
|
||||
'NodeIKernelProfileService/fetchUserDetailInfo',
|
||||
'NodeIKernelProfileListener/onUserDetailInfoChanged',
|
||||
1,
|
||||
5000,
|
||||
(profile) => {
|
||||
if (profile.uid === uid) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
"BuddyProfileStore",
|
||||
[
|
||||
uid
|
||||
],
|
||||
UserDetailSource.KSERVER,
|
||||
[
|
||||
ProfileBizType.KALL
|
||||
]
|
||||
);
|
||||
let RetUser: User = {
|
||||
...profile.simpleInfo.coreInfo,
|
||||
...profile.simpleInfo.status,
|
||||
...profile.simpleInfo.vasInfo,
|
||||
...profile.commonExt,
|
||||
...profile.simpleInfo.baseInfo,
|
||||
qqLevel: profile.commonExt.qqLevel,
|
||||
pendantId: ""
|
||||
};
|
||||
return RetUser;
|
||||
}
|
||||
static async getUserDetailInfo(uid: string) {
|
||||
if (requireMinNTQQBuild('26702')) {
|
||||
return this.fetchUserDetailInfo(uid);
|
||||
}
|
||||
return this.getUserDetailInfoOld(uid);
|
||||
}
|
||||
static async getUserDetailInfoOld(uid: string) {
|
||||
type EventService = NodeIKernelProfileService['getUserDetailInfoWithBizInfo'];
|
||||
type EventListener = NodeIKernelProfileListener['onProfileDetailInfoChanged'];
|
||||
let [_retData, profile] = await NTEventDispatch.CallNormalEvent
|
||||
<EventService, EventListener>
|
||||
(
|
||||
'NodeIKernelProfileService/getUserDetailInfoWithBizInfo',
|
||||
'NodeIKernelProfileListener/onProfileDetailInfoChanged',
|
||||
2,
|
||||
5000,
|
||||
(profile: User) => {
|
||||
if (profile.uid === uid) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
uid,
|
||||
[0]
|
||||
);
|
||||
return profile;
|
||||
}
|
||||
static async modifySelfProfile(param: ModifyProfileParams) {
|
||||
return napCatCore.session.getProfileService().modifyDesktopMiniProfile(param);
|
||||
}
|
||||
//需要异常处理
|
||||
@CacheClassFuncAsync(1800 * 1000)
|
||||
static async getCookies(domain: string) {
|
||||
const ClientKeyData = await NTQQUserApi.forceFetchClientKey();
|
||||
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2F' + domain + '%2F' + selfInfo.uin + '%2Finfocenter&keyindex=19%27'
|
||||
let cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
|
||||
return cookies;
|
||||
}
|
||||
@CacheClassFuncAsync(1800 * 1000)
|
||||
static async getPSkey(domainList: string[]) {
|
||||
return await napCatCore.session.getTipOffService().getPskey(domainList, true);
|
||||
}
|
||||
static async getRobotUinRange(): Promise<Array<any>> {
|
||||
const robotUinRanges = await napCatCore.session.getRobotService().getRobotUinRange({
|
||||
justFetchMsgConfig: '1',
|
||||
type: 1,
|
||||
version: 0,
|
||||
aioKeywordVersion: 0
|
||||
});
|
||||
// console.log(robotUinRanges?.response?.robotUinRanges);
|
||||
return robotUinRanges?.response?.robotUinRanges;
|
||||
}
|
||||
//需要异常处理
|
||||
@CacheClassFuncAsync(1800 * 1000)
|
||||
static async getQzoneCookies() {
|
||||
const ClientKeyData = await NTQQUserApi.forceFetchClientKey();
|
||||
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + selfInfo.uin + '%2Finfocenter&keyindex=19%27'
|
||||
let cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
|
||||
return cookies;
|
||||
}
|
||||
//需要异常处理
|
||||
@CacheClassFuncAsync(1800 * 1000)
|
||||
static async getSkey(): Promise<string | undefined> {
|
||||
const ClientKeyData = await NTQQUserApi.forceFetchClientKey();
|
||||
if (ClientKeyData.result !== 0) {
|
||||
throw new Error('getClientKey Error');
|
||||
}
|
||||
const clientKey = ClientKeyData.clientKey;
|
||||
const keyIndex = ClientKeyData.keyIndex;
|
||||
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin + '&clientkey=' + clientKey + '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=19%27';
|
||||
let cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
|
||||
const skey = cookies['skey'];
|
||||
if (!skey) {
|
||||
throw new Error('getSkey Skey is Empty');
|
||||
}
|
||||
return skey;
|
||||
}
|
||||
@CacheClassFuncAsyncExtend(3600 * 1000, 'Uin2Uid', (Uin: string, Uid: string | undefined) => {
|
||||
if (Uid && Uid.indexOf('u_') != -1) {
|
||||
return true
|
||||
}
|
||||
logWarn("uin转换到uid时异常", Uin, Uid);
|
||||
return false;
|
||||
})
|
||||
static async getUidByUin(Uin: string) {
|
||||
//此代码仅临时使用,后期会被废弃
|
||||
if (requireMinNTQQBuild('26702')) {
|
||||
return await NTQQUserApi.getUidByUinV2(Uin);
|
||||
}
|
||||
return await NTQQUserApi.getUidByUinV1(Uin);
|
||||
}
|
||||
@CacheClassFuncAsyncExtend(3600 * 1000, 'Uid2Uin', (Uid: string | undefined, Uin: number | undefined) => {
|
||||
if (Uin && Uin != 0 && !isNaN(Uin)) {
|
||||
return true
|
||||
}
|
||||
logWarn("uid转换到uin时异常", Uid, Uin);
|
||||
return false;
|
||||
})
|
||||
static async getUinByUid(Uid: string) {
|
||||
//此代码仅临时使用,后期会被废弃
|
||||
if (requireMinNTQQBuild('26702')) {
|
||||
return await NTQQUserApi.getUinByUidV2(Uid);
|
||||
}
|
||||
return await NTQQUserApi.getUinByUidV1(Uid);
|
||||
}
|
||||
|
||||
//后期改成流水线处理
|
||||
static async getUidByUinV2(Uin: string) {
|
||||
let uid = (await napCatCore.session.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])).get(Uin);
|
||||
if (uid) return uid;
|
||||
uid = (await napCatCore.session.getGroupService().getUidByUins([Uin])).uids.get(Uin);
|
||||
if (uid) return uid;
|
||||
uid = (await napCatCore.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
|
||||
if (uid) return uid;
|
||||
console.log((await NTQQFriendApi.getBuddyIdMapCache(true)));
|
||||
uid = (await NTQQFriendApi.getBuddyIdMapCache(true)).getValue(Uin);//从Buddy缓存获取Uid
|
||||
if (uid) return uid;
|
||||
uid = (await NTQQFriendApi.getBuddyIdMap(true)).getValue(Uin);
|
||||
if (uid) return uid;
|
||||
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUinV2(Uin)).detail.uid;//从QQ Native 特殊转换
|
||||
if (unveifyUid.indexOf("*") == -1) uid = unveifyUid;
|
||||
//if (uid) return uid;
|
||||
return uid;
|
||||
}
|
||||
//后期改成流水线处理
|
||||
static async getUinByUidV2(Uid: string) {
|
||||
let uin = (await napCatCore.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
|
||||
if (uin) return uin;
|
||||
uin = (await napCatCore.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
|
||||
if (uin) return uin;
|
||||
uin = (await napCatCore.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
|
||||
if (uin) return uin;
|
||||
uin = (await NTQQFriendApi.getBuddyIdMapCache(true)).getKey(Uid);//从Buddy缓存获取Uin
|
||||
if (uin) return uin;
|
||||
uin = (await NTQQFriendApi.getBuddyIdMap(true)).getKey(Uid);
|
||||
if (uin) return uin;
|
||||
uin = (await NTQQUserApi.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
|
||||
return uin;
|
||||
}
|
||||
|
||||
static async getUidByUinV1(Uin: string) {
|
||||
// 通用转换开始尝试
|
||||
let uid = (await napCatCore.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
|
||||
// Uid 好友转
|
||||
if (!uid) {
|
||||
Array.from(friends.values()).forEach((t) => {
|
||||
if (t.uin == Uin) {
|
||||
uid = t.uid;
|
||||
}
|
||||
});
|
||||
}
|
||||
//Uid 群友列表转
|
||||
if (!uid) {
|
||||
for (let groupMembersList of groupMembers.values()) {
|
||||
for (let GroupMember of groupMembersList.values()) {
|
||||
if (GroupMember.uin == Uin) {
|
||||
uid = GroupMember.uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!uid) {
|
||||
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
|
||||
if (unveifyUid.indexOf("*") == -1) {
|
||||
uid = unveifyUid;
|
||||
}
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
static async getUinByUidV1(Uid: string) {
|
||||
let ret = await NTEventDispatch.CallNoListenerEvent
|
||||
<(Uin: string[]) => Promise<{ uinInfo: Map<string, string> }>>(
|
||||
'NodeIKernelUixConvertService/getUin',
|
||||
5000,
|
||||
[Uid]
|
||||
);
|
||||
let uin = ret.uinInfo.get(Uid);
|
||||
if (!uin) {
|
||||
//从Buddy缓存获取Uin
|
||||
Array.from(friends.values()).forEach((t) => {
|
||||
if (t.uid == Uid) {
|
||||
uin = t.uin;
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!uin) {
|
||||
uin = (await NTQQUserApi.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
|
||||
}
|
||||
|
||||
// if (!uin) {
|
||||
// uin = (await NTQQFriendApi.getFriends(false)).find((t) => { t.uid == Uid })?.uin; //从QQ Native 缓存转换
|
||||
// }
|
||||
// if (!uin) {
|
||||
// uin = (await NTQQFriendApi.getFriends(true)).find((t) => { t.uid == Uid })?.uin; //从QQ Native 非缓存转换
|
||||
// }
|
||||
return uin;
|
||||
}
|
||||
static async getRecentContactListSnapShot(count: number) {
|
||||
return await napCatCore.session.getRecentContactService().getRecentContactListSnapShot(count);
|
||||
}
|
||||
static async getRecentContactListSyncLimit(count: number) {
|
||||
return await napCatCore.session.getRecentContactService().getRecentContactListSyncLimit(count);
|
||||
}
|
||||
static async getRecentContactListSync() {
|
||||
return await napCatCore.session.getRecentContactService().getRecentContactListSync();
|
||||
}
|
||||
static async getRecentContactList() {
|
||||
return await napCatCore.session.getRecentContactService().getRecentContactList();
|
||||
}
|
||||
static async getUserDetailInfoByUinV2(Uin: string) {
|
||||
return await NTEventDispatch.CallNoListenerEvent
|
||||
<(Uin: string) => Promise<UserDetailInfoByUinV2>>(
|
||||
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||
5000,
|
||||
Uin
|
||||
);
|
||||
}
|
||||
static async getUserDetailInfoByUin(Uin: string) {
|
||||
return NTEventDispatch.CallNoListenerEvent
|
||||
<(Uin: string) => Promise<UserDetailInfoByUin>>(
|
||||
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||
5000,
|
||||
Uin
|
||||
);
|
||||
}
|
||||
@CacheClassFuncAsync(3600 * 1000, 'ClientKey')
|
||||
static async forceFetchClientKey() {
|
||||
return await napCatCore.session.getTicketService().forceFetchClientKey('');
|
||||
}
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
import { selfInfo } from '@/core/data';
|
||||
import { log, logDebug } from '@/common/utils/log';
|
||||
import { NTQQUserApi } from './user';
|
||||
import { RequestUtil } from '@/common/utils/request';
|
||||
import { CacheClassFuncAsync } from '@/common/utils/helper';
|
||||
export enum WebHonorType {
|
||||
ALL = 'all',
|
||||
TALKACTIVE = 'talkative',
|
||||
PERFROMER = 'performer',
|
||||
LEGEND = 'legend',
|
||||
STORONGE_NEWBI = 'strong_newbie',
|
||||
EMOTION = 'emotion'
|
||||
}
|
||||
export interface WebApiGroupMember {
|
||||
uin: number
|
||||
role: number
|
||||
g: number
|
||||
join_time: number
|
||||
last_speak_time: number
|
||||
lv: {
|
||||
point: number
|
||||
level: number
|
||||
}
|
||||
card: string
|
||||
tags: string
|
||||
flag: number
|
||||
nick: string
|
||||
qage: number
|
||||
rm: number
|
||||
}
|
||||
interface WebApiGroupMemberRet {
|
||||
ec: number
|
||||
errcode: number
|
||||
em: string
|
||||
cache: number
|
||||
adm_num: number
|
||||
levelname: any
|
||||
mems: WebApiGroupMember[]
|
||||
count: number
|
||||
svr_time: number
|
||||
max_count: number
|
||||
search_count: number
|
||||
extmode: number
|
||||
}
|
||||
export interface WebApiGroupNoticeFeed {
|
||||
u: number//发送者
|
||||
fid: string//fid
|
||||
pubt: number//时间
|
||||
msg: {
|
||||
text: string
|
||||
text_face: string
|
||||
title: string,
|
||||
pics?: {
|
||||
id: string,
|
||||
w: string,
|
||||
h: string
|
||||
}[]
|
||||
}
|
||||
type: number
|
||||
fn: number
|
||||
cn: number
|
||||
vn: number
|
||||
settings: {
|
||||
is_show_edit_card: number
|
||||
remind_ts: number
|
||||
tip_window_type: number
|
||||
confirm_required: number
|
||||
}
|
||||
read_num: number
|
||||
is_read: number
|
||||
is_all_confirm: number
|
||||
}
|
||||
export interface WebApiGroupNoticeRet {
|
||||
ec: number
|
||||
em: string
|
||||
ltsm: number
|
||||
srv_code: number
|
||||
read_only: number
|
||||
role: number
|
||||
feeds: WebApiGroupNoticeFeed[]
|
||||
group: {
|
||||
group_id: number
|
||||
class_ext: number
|
||||
}
|
||||
sta: number,
|
||||
gln: number
|
||||
tst: number,
|
||||
ui: any
|
||||
server_time: number
|
||||
svrt: number
|
||||
ad: number
|
||||
}
|
||||
interface GroupEssenceMsg {
|
||||
group_code: string
|
||||
msg_seq: number
|
||||
msg_random: number
|
||||
sender_uin: string
|
||||
sender_nick: string
|
||||
sender_time: number
|
||||
add_digest_uin: string
|
||||
add_digest_nick: string
|
||||
add_digest_time: number
|
||||
msg_content: any[]
|
||||
can_be_removed: true
|
||||
}
|
||||
export interface GroupEssenceMsgRet {
|
||||
retcode: number
|
||||
retmsg: string
|
||||
data: {
|
||||
msg_list: GroupEssenceMsg[]
|
||||
is_end: boolean
|
||||
group_role: number
|
||||
config_page_url: string
|
||||
}
|
||||
}
|
||||
export class WebApi {
|
||||
static async shareDigest(groupCode: string, msgSeq: string, msgRandom: string, targetGroupCode: string) {
|
||||
const CookiesObject = await NTQQUserApi.getCookies('qun.qq.com');
|
||||
const CookieValue = Object.entries(CookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const Bkn = WebApi.genBkn(CookiesObject.skey);
|
||||
let ret: any = undefined;
|
||||
const data = 'group_code=' + groupCode + '&msg_seq=' + msgSeq + '&msg_random=' + msgRandom + '&target_group_code=' + targetGroupCode;
|
||||
const url = 'https://qun.qq.com/cgi-bin/group_digest/share_digest?bkn=' + Bkn + "&" + data;
|
||||
//console.log(url);
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': CookieValue });
|
||||
return ret;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@CacheClassFuncAsync(3600 * 1000, 'webapi_get_group_members')
|
||||
static async getGroupEssenceMsg(GroupCode: string, page_start: string) {
|
||||
const CookiesObject = await NTQQUserApi.getCookies('qun.qq.com');
|
||||
const CookieValue = Object.entries(CookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const Bkn = WebApi.genBkn(CookiesObject.skey);
|
||||
const url = 'https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=' + Bkn + '&group_code=' + GroupCode + '&page_start=' + page_start + '&page_limit=20';
|
||||
let ret;
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>(url, 'GET', '', { 'Cookie': CookieValue });
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
//console.log(url, CookieValue);
|
||||
if (ret.retcode !== 0) {
|
||||
return undefined;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@CacheClassFuncAsync(3600 * 1000, 'webapi_get_group_members')
|
||||
static async getGroupMembers(GroupCode: string, cached: boolean = true): Promise<WebApiGroupMember[]> {
|
||||
//logDebug('webapi 获取群成员', GroupCode);
|
||||
let MemberData: Array<WebApiGroupMember> = new Array<WebApiGroupMember>();
|
||||
try {
|
||||
const CookiesObject = await NTQQUserApi.getCookies('qun.qq.com');
|
||||
const CookieValue = Object.entries(CookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const Bkn = WebApi.genBkn(CookiesObject.skey);
|
||||
const retList: Promise<WebApiGroupMemberRet>[] = [];
|
||||
const fastRet = await RequestUtil.HttpGetJson<WebApiGroupMemberRet>('https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?st=0&end=40&sort=1&gc=' + GroupCode + '&bkn=' + Bkn, 'POST', '', { 'Cookie': CookieValue });
|
||||
if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) {
|
||||
return [];
|
||||
} else {
|
||||
for (const key in fastRet.mems) {
|
||||
MemberData.push(fastRet.mems[key]);
|
||||
}
|
||||
}
|
||||
//初始化获取PageNum
|
||||
const PageNum = Math.ceil(fastRet.count / 40);
|
||||
//遍历批量请求
|
||||
for (let i = 2; i <= PageNum; i++) {
|
||||
const ret: Promise<WebApiGroupMemberRet> = RequestUtil.HttpGetJson<WebApiGroupMemberRet>('https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?st=' + (i - 1) * 40 + '&end=' + i * 40 + '&sort=1&gc=' + GroupCode + '&bkn=' + Bkn, 'POST', '', { 'Cookie': CookieValue });
|
||||
retList.push(ret);
|
||||
}
|
||||
//批量等待
|
||||
for (let i = 1; i <= PageNum; i++) {
|
||||
const ret = await (retList[i]);
|
||||
if (!ret?.count || ret?.errcode !== 0 || !ret?.mems) {
|
||||
continue;
|
||||
}
|
||||
for (const key in ret.mems) {
|
||||
MemberData.push(ret.mems[key]);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return MemberData;
|
||||
}
|
||||
return MemberData;
|
||||
}
|
||||
// public static async addGroupDigest(groupCode: string, msgSeq: string) {
|
||||
// const url = `https://qun.qq.com/cgi-bin/group_digest/cancel_digest?random=665&X-CROSS-ORIGIN=fetch&group_code=${groupCode}&msg_seq=${msgSeq}&msg_random=444021292`;
|
||||
// const res = await this.request(url);
|
||||
// return await res.json();
|
||||
// }
|
||||
|
||||
// public async getGroupDigest(groupCode: string) {
|
||||
// const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?random=665&X-CROSS-ORIGIN=fetch&group_code=${groupCode}&page_start=0&page_limit=20`;
|
||||
// const res = await this.request(url);
|
||||
// return await res.json();
|
||||
// }
|
||||
static async setGroupNotice(GroupCode: string, Content: string = '') {
|
||||
//https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${bkn}
|
||||
//qid=${群号}&bkn=${bkn}&text=${内容}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}
|
||||
|
||||
const CookiesObject = await NTQQUserApi.getCookies('qun.qq.com');
|
||||
const CookieValue = Object.entries(CookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const Bkn = WebApi.genBkn(CookiesObject.skey);
|
||||
let ret: any = undefined;
|
||||
const data = 'qid=' + GroupCode + '&bkn=' + Bkn + '&text=' + Content + '&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}';
|
||||
const url = 'https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=' + Bkn;
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetJson<any>(url, 'GET', '', { 'Cookie': CookieValue });
|
||||
return ret;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
static async getGrouptNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet> {
|
||||
const CookiesObject = await NTQQUserApi.getCookies('qun.qq.com');
|
||||
const CookieValue = Object.entries(CookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const Bkn = WebApi.genBkn(CookiesObject.skey);
|
||||
let ret: WebApiGroupNoticeRet | undefined = undefined;
|
||||
//console.log(CookieValue);
|
||||
const url = 'https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=' + Bkn + '&qid=' + GroupCode + '&ft=23&ni=1&n=1&i=1&log_read=1&platform=1&s=-1&n=20';
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(url, 'GET', '', { 'Cookie': CookieValue });
|
||||
if (ret?.ec !== 0) {
|
||||
return undefined;
|
||||
}
|
||||
return ret;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
static genBkn(sKey: string) {
|
||||
sKey = sKey || '';
|
||||
let hash = 5381;
|
||||
|
||||
for (let i = 0; i < sKey.length; i++) {
|
||||
const code = sKey.charCodeAt(i);
|
||||
hash = hash + (hash << 5) + code;
|
||||
}
|
||||
|
||||
return (hash & 0x7FFFFFFF).toString();
|
||||
}
|
||||
|
||||
@CacheClassFuncAsync(3600 * 1000, 'GroupHonorInfo')
|
||||
static async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
||||
const CookiesObject = await NTQQUserApi.getCookies('qun.qq.com');
|
||||
const CookieValue = Object.entries(CookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||
const Bkn = WebApi.genBkn(CookiesObject.skey);
|
||||
async function getDataInternal(Internal_groupCode: string, Internal_type: number) {
|
||||
let url = 'https://qun.qq.com/interactive/honorlist?gc=' + Internal_groupCode + '&type=' + Internal_type.toString();
|
||||
let res = '';
|
||||
let resJson;
|
||||
try {
|
||||
res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': CookieValue });
|
||||
const match = res.match(/window\.__INITIAL_STATE__=(.*?);/);
|
||||
if (match) {
|
||||
resJson = JSON.parse(match[1].trim());
|
||||
}
|
||||
if (Internal_type === 1) {
|
||||
return resJson?.talkativeList;
|
||||
} else {
|
||||
return resJson?.actorList;
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug('获取当前群荣耀失败', url, e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let HonorInfo: any = { group_id: groupCode };
|
||||
|
||||
if (getType === WebHonorType.TALKACTIVE || getType === WebHonorType.ALL) {
|
||||
try {
|
||||
let RetInternal = await getDataInternal(groupCode, 1);
|
||||
if (!RetInternal) {
|
||||
throw new Error('获取龙王信息失败');
|
||||
}
|
||||
HonorInfo.current_talkative = {
|
||||
user_id: RetInternal[0]?.uin,
|
||||
avatar: RetInternal[0]?.avatar,
|
||||
nickname: RetInternal[0]?.name,
|
||||
day_count: 0,
|
||||
description: RetInternal[0]?.desc
|
||||
}
|
||||
HonorInfo.talkative_list = [];
|
||||
for (const talkative_ele of RetInternal) {
|
||||
HonorInfo.talkative_list.push({
|
||||
user_id: talkative_ele?.uin,
|
||||
avatar: talkative_ele?.avatar,
|
||||
description: talkative_ele?.desc,
|
||||
day_count: 0,
|
||||
nickname: talkative_ele?.name
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug(e);
|
||||
}
|
||||
}
|
||||
if (getType === WebHonorType.PERFROMER || getType === WebHonorType.ALL) {
|
||||
try {
|
||||
let RetInternal = await getDataInternal(groupCode, 2);
|
||||
if (!RetInternal) {
|
||||
throw new Error('获取群聊之火失败');
|
||||
}
|
||||
HonorInfo.performer_list = [];
|
||||
for (const performer_ele of RetInternal) {
|
||||
HonorInfo.performer_list.push({
|
||||
user_id: performer_ele?.uin,
|
||||
nickname: performer_ele?.name,
|
||||
avatar: performer_ele?.avatar,
|
||||
description: performer_ele?.desc
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug(e);
|
||||
}
|
||||
}
|
||||
if (getType === WebHonorType.PERFROMER || getType === WebHonorType.ALL) {
|
||||
try {
|
||||
let RetInternal = await getDataInternal(groupCode, 3);
|
||||
if (!RetInternal) {
|
||||
throw new Error('获取群聊炽焰失败');
|
||||
}
|
||||
HonorInfo.legend_list = [];
|
||||
for (const legend_ele of RetInternal) {
|
||||
HonorInfo.legend_list.push({
|
||||
user_id: legend_ele?.uin,
|
||||
nickname: legend_ele?.name,
|
||||
avatar: legend_ele?.avatar,
|
||||
desc: legend_ele?.description
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug('获取群聊炽焰失败', e);
|
||||
}
|
||||
}
|
||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||
try {
|
||||
let RetInternal = await getDataInternal(groupCode, 6);
|
||||
if (!RetInternal) {
|
||||
throw new Error('获取快乐源泉失败');
|
||||
}
|
||||
HonorInfo.emotion_list = [];
|
||||
for (const emotion_ele of RetInternal) {
|
||||
HonorInfo.emotion_list.push({
|
||||
user_id: emotion_ele?.uin,
|
||||
nickname: emotion_ele?.name,
|
||||
avatar: emotion_ele?.avatar,
|
||||
desc: emotion_ele?.description
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug('获取快乐源泉失败', e);
|
||||
}
|
||||
}
|
||||
//冒尖小春笋好像已经被tx扬了
|
||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||
HonorInfo.strong_newbie_list = [];
|
||||
}
|
||||
return HonorInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,484 +0,0 @@
|
||||
import QQWrapper, { NodeIQQNTWrapperEngine, NodeIQQNTWrapperSession, NodeQQNTWrapperUtil } from '@/core/wrapper';
|
||||
import { DeviceList } from '@/onebot11/main';
|
||||
import {
|
||||
NodeIKernelLoginService,
|
||||
NodeIKernelBuddyService,
|
||||
QuickLoginResult, passwordLoginArgType
|
||||
} from '@/core/services';
|
||||
import {
|
||||
BuddyListener,
|
||||
GroupListener,
|
||||
LoginListener, MsgListener,
|
||||
ProfileListener, SessionListener
|
||||
} from '@/core/listeners';
|
||||
import { DependsAdapter, DispatcherAdapter, GlobalAdapter, NodeIGlobalAdapter } from '@/core/adapters';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import fs from 'node:fs';
|
||||
import { getFullQQVesion, QQVersionAppid, QQVersionQua, requireMinNTQQBuild } from '@/common/utils/QQBasicInfo';
|
||||
import { hostname, systemVersion } from '@/common/utils/system';
|
||||
import { genSessionConfig } from '@/core/sessionConfig';
|
||||
import { sleep } from '@/common/utils/helper';
|
||||
import crypto from 'node:crypto';
|
||||
import { groupMembers, groups, selfInfo, stat } from '@/core/data';
|
||||
import { GroupMember, RawMessage } from '@/core/entities';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import {
|
||||
enableConsoleLog,
|
||||
enableFileLog,
|
||||
log,
|
||||
logDebug,
|
||||
logError,
|
||||
setLogLevel,
|
||||
setLogSelfInfo
|
||||
} from '@/common/utils/log';
|
||||
import { napCatConfig } from '@/core/utils/config';
|
||||
import { NTQQFriendApi } from './apis';
|
||||
|
||||
export interface OnLoginSuccess {
|
||||
(uin: string, uid: string): void | Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
export class NapCatCore {
|
||||
public readonly session: NodeIQQNTWrapperSession;
|
||||
public readonly util: NodeQQNTWrapperUtil;
|
||||
public readonly engine: NodeIQQNTWrapperEngine;
|
||||
private readonly loginListener: LoginListener;
|
||||
|
||||
private loginService: NodeIKernelLoginService;
|
||||
private onLoginSuccessFuncList: OnLoginSuccess[] = [];
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.engine = new QQWrapper.NodeIQQNTWrapperEngine();
|
||||
this.util = new QQWrapper.NodeQQNTWrapperUtil();
|
||||
this.loginService = new QQWrapper.NodeIKernelLoginService();
|
||||
this.session = new QQWrapper.NodeIQQNTWrapperSession();
|
||||
this.loginListener = new LoginListener();
|
||||
this.loginListener.onUserLoggedIn = (userid: string) => {
|
||||
logError('当前账号(' + userid + ')已登录,无法重复登录');
|
||||
};
|
||||
this.initConfig();
|
||||
this.loginListener.onQRCodeLoginSucceed = (arg) => {
|
||||
this.initSession(arg.uin, arg.uid).then((r) => {
|
||||
selfInfo.uin = arg.uin;
|
||||
selfInfo.uid = arg.uid;
|
||||
napCatConfig.read();
|
||||
setLogLevel(napCatConfig.fileLogLevel, napCatConfig.consoleLogLevel);
|
||||
enableFileLog(napCatConfig.fileLog);
|
||||
enableConsoleLog(napCatConfig.consoleLog);
|
||||
setLogSelfInfo(selfInfo);
|
||||
const dataPath = path.resolve(this.dataPath, './NapCat/data');
|
||||
fs.mkdirSync(dataPath, { recursive: true });
|
||||
logDebug('本账号数据/缓存目录:', dataPath);
|
||||
this.initDataListener();
|
||||
this.onLoginSuccessFuncList.map(cb => {
|
||||
new Promise((resolve, reject) => {
|
||||
const result = cb(arg.uin, arg.uid);
|
||||
if (result instanceof Promise) {
|
||||
result.then(resolve).catch(reject);
|
||||
}
|
||||
}).then();
|
||||
});
|
||||
}).catch((e) => {
|
||||
logError('initSession failed', e);
|
||||
throw new Error(`启动失败: ${JSON.stringify(e)}`);
|
||||
});
|
||||
};
|
||||
// todo: 登录失败处理
|
||||
this.loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
|
||||
logError('登录失败(onQRCodeSessionFailed)', errMsg);
|
||||
if (errType == 1 && errCode == 3) {
|
||||
// 二维码过期刷新
|
||||
}
|
||||
this.loginService.getQRCodePicture();
|
||||
};
|
||||
this.loginListener.onLoginFailed = (args) => {
|
||||
logError('登录失败(onLoginFailed)', args);
|
||||
};
|
||||
|
||||
this.loginListener = new Proxy(this.loginListener, this.proxyHandler);
|
||||
// 初始化流程:initConfig, login, initSession, loginSuccess | initDataListener
|
||||
this.loginService.addKernelLoginListener(new QQWrapper.NodeIKernelLoginListener(this.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 initConfig() {
|
||||
this.engine.initWithDeskTopConfig({
|
||||
base_path_prefix: '',
|
||||
platform_type: 3,
|
||||
app_type: 4,
|
||||
app_version: getFullQQVesion(),
|
||||
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 QQWrapper.NodeIGlobalAdapter(new GlobalAdapter()));
|
||||
this.loginService.initConfig({
|
||||
machineId: '',
|
||||
appid: QQVersionAppid,
|
||||
platVer: systemVersion,
|
||||
commonPath: this.dataPathGlobal,
|
||||
clientVer: getFullQQVesion(),
|
||||
hostName: hostname
|
||||
});
|
||||
}
|
||||
|
||||
private initSession(uin: string, uid: string): Promise<number> {
|
||||
return new Promise(async (res, rej) => {
|
||||
|
||||
const sessionConfig = await genSessionConfig(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 QQWrapper.NodeIDependsAdapter(new DependsAdapter()),
|
||||
new QQWrapper.NodeIDispatcherAdapter(new DispatcherAdapter()),
|
||||
new QQWrapper.NodeIKernelSessionListener(sessionListener)
|
||||
);
|
||||
try {
|
||||
this.session.startNT(0);
|
||||
} catch (__) { /* Empty */
|
||||
try {
|
||||
this.session.startNT();
|
||||
} catch (e) {
|
||||
rej('init failed ' + e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
private initDataListener() {
|
||||
// 消息相关
|
||||
interface LineDevice {
|
||||
instanceId: number
|
||||
clientType: number
|
||||
devUid: string
|
||||
}
|
||||
interface KickedOffLineInfo {
|
||||
appId: number
|
||||
instanceId: number
|
||||
sameDevice: boolean
|
||||
tipsDesc: string
|
||||
tipsTitle: string
|
||||
kickedType: number
|
||||
securityKickedType: number
|
||||
}
|
||||
const msgListener = new MsgListener();
|
||||
msgListener.onLineDev = (Devices: LineDevice[]) => {
|
||||
DeviceList.splice(0, DeviceList.length);
|
||||
Devices.map((Device: LineDevice) => {
|
||||
let DeviceData = {
|
||||
app_id: Device.devUid,
|
||||
device_name: Device.clientType.toString(),
|
||||
device_kind: Device.clientType.toString(),
|
||||
};
|
||||
DeviceList.push(DeviceData);
|
||||
// if (Device.clientType === 2) {
|
||||
// log('账号设备(' + Device.devUid + ') 在线状态变更');
|
||||
// }
|
||||
});
|
||||
};
|
||||
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
|
||||
// 下线通知
|
||||
log('[KickedOffLine] [' + Info.tipsTitle + '] ' + Info.tipsDesc);
|
||||
};
|
||||
// msgListener.onMsgInfoListUpdate = (msgInfoList: RawMessage[]) => {
|
||||
// stat.packet_received += 1;
|
||||
// msgInfoList.map(msg => {
|
||||
// console.log("onMsgInfoListUpdate", msg);
|
||||
// if (msg.recallTime === '0') { // 不是撤回消息才入库/更新
|
||||
// dbUtil.addMsg(msg).then().catch();
|
||||
// }
|
||||
// else {
|
||||
// // 撤回的消息
|
||||
// dbUtil.getMsgByLongId(msg.msgId).then(existMsg => {
|
||||
// if (existMsg) {
|
||||
// existMsg.recallTime = msg.recallTime;
|
||||
// dbUtil.updateMsg(existMsg).then();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
msgListener.onAddSendMsg = (msg: RawMessage) => {
|
||||
stat.packet_sent += 1;
|
||||
stat.message_sent += 1;
|
||||
stat.last_message_time = Math.floor(Date.now() / 1000);
|
||||
};
|
||||
msgListener.onRecvMsg = (msgList: RawMessage[]) => {
|
||||
// console.log(JSON.stringify(msgList[0],null,2));
|
||||
stat.packet_received += 1;
|
||||
stat.message_received += msgList.length;
|
||||
stat.last_message_time = Math.floor(Date.now() / 1000);
|
||||
};
|
||||
msgListener.onRecvSysMsg = (...args) => {
|
||||
stat.packet_received += 1;
|
||||
};
|
||||
this.addListener(msgListener);
|
||||
// 好友相关
|
||||
const buddyListener = new BuddyListener();
|
||||
|
||||
|
||||
this.addListener(buddyListener);
|
||||
// 刷新一次好友列表 26702版本以下需要手动刷新一次获取 高版本NTQQ自带缓存
|
||||
if (!requireMinNTQQBuild('26702')) {
|
||||
this.session.getBuddyService().getBuddyList(true).then(arg => {
|
||||
// console.log('getBuddyList', arg);
|
||||
});
|
||||
} else {
|
||||
// NTQQFriendApi.getBuddyV2(true).then((res) => {
|
||||
// res.forEach((item) => {
|
||||
// CachedIdMap.set(item.uid!, item.uin!);
|
||||
// });
|
||||
// }).catch();
|
||||
}
|
||||
interface SelfStatusInfo {
|
||||
uid: string
|
||||
status: number
|
||||
extStatus: number
|
||||
termType: number
|
||||
netType: number
|
||||
iconType: number
|
||||
customStatus: any
|
||||
setTime: string
|
||||
}
|
||||
const profileListener = new ProfileListener();
|
||||
profileListener.onProfileDetailInfoChanged = (profile) => {
|
||||
if (profile.uid === selfInfo.uid) {
|
||||
Object.assign(selfInfo, profile);
|
||||
}
|
||||
};
|
||||
profileListener.onSelfStatusChanged = (Info: SelfStatusInfo) => {
|
||||
// if (Info.status == 20) {
|
||||
// log("账号状态变更为离线")
|
||||
// }
|
||||
};
|
||||
this.addListener(profileListener);
|
||||
|
||||
// 群相关
|
||||
const groupListener = new GroupListener();
|
||||
groupListener.onGroupListUpdate = (updateType, groupList) => {
|
||||
// console.log("onGroupListUpdate", updateType, groupList)
|
||||
groupList.map(g => {
|
||||
const existGroup = groups.get(g.groupCode);
|
||||
//群成员数量变化 应该刷新缓存
|
||||
if (existGroup && g.memberCount === existGroup.memberCount) {
|
||||
Object.assign(existGroup, g);
|
||||
}
|
||||
else {
|
||||
groups.set(g.groupCode, g);
|
||||
// 获取群成员
|
||||
}
|
||||
const sceneId = this.session.getGroupService().createMemberListScene(g.groupCode, 'groupMemberList_MainWindow');
|
||||
this.session.getGroupService().getNextMemberList(sceneId!, undefined, 3000).then(r => {
|
||||
// console.log(`get group ${g.groupCode} members`, r);
|
||||
// r.result.infos.forEach(member => {
|
||||
// });
|
||||
// groupMembers.set(g.groupCode, r.result.infos);
|
||||
});
|
||||
});
|
||||
};
|
||||
groupListener.onMemberListChange = (arg) => {
|
||||
// todo: 应该加一个内部自己维护的成员变动callback,用于判断成员变化通知
|
||||
const groupCode = arg.sceneId.split('_')[0];
|
||||
if (groupMembers.has(groupCode)) {
|
||||
const existMembers = groupMembers.get(groupCode)!;
|
||||
arg.infos.forEach((member, uid) => {
|
||||
//console.log('onMemberListChange', member);
|
||||
const existMember = existMembers.get(uid);
|
||||
if (existMember) {
|
||||
Object.assign(existMember, member);
|
||||
}
|
||||
else {
|
||||
existMembers!.set(uid, member);
|
||||
}
|
||||
//移除成员
|
||||
if (member.isDelete) {
|
||||
existMembers.delete(uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
groupMembers.set(groupCode, arg.infos);
|
||||
}
|
||||
// console.log('onMemberListChange', groupCode, arg);
|
||||
};
|
||||
groupListener.onMemberInfoChange = (groupCode, changeType, members) => {
|
||||
//console.log('onMemberInfoChange', groupCode, changeType, members);
|
||||
if (changeType === 0 && members.get(selfInfo.uid)?.isDelete) {
|
||||
// 自身退群或者被踢退群 5s用于Api操作 之后不再出现
|
||||
setTimeout(() => {
|
||||
groups.delete(groupCode);
|
||||
}, 5000);
|
||||
|
||||
}
|
||||
const existMembers = groupMembers.get(groupCode);
|
||||
if (existMembers) {
|
||||
members.forEach((member, uid) => {
|
||||
const existMember = existMembers.get(uid);
|
||||
if (existMember) {
|
||||
// 检查管理变动
|
||||
member.isChangeRole = this.checkAdminEvent(groupCode, member, existMember);
|
||||
// 更新成员信息
|
||||
Object.assign(existMember, member);
|
||||
}
|
||||
else {
|
||||
existMembers.set(uid, member);
|
||||
}
|
||||
//移除成员
|
||||
if (member.isDelete) {
|
||||
existMembers.delete(uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
groupMembers.set(groupCode, members);
|
||||
}
|
||||
};
|
||||
this.addListener(groupListener);
|
||||
}
|
||||
|
||||
addListener(
|
||||
listener: BuddyListener | GroupListener | MsgListener | ProfileListener
|
||||
): number {
|
||||
// 根据listener的类型,找到对应的service,然后调用addListener方法
|
||||
// logDebug('addListener', listener.constructor.name);
|
||||
|
||||
// proxy listener,调用 listener 不存在的方法时不会报错
|
||||
|
||||
listener = new Proxy(listener, this.proxyHandler);
|
||||
switch (listener.constructor.name) {
|
||||
case 'BuddyListener': {
|
||||
return this.session.getBuddyService().addKernelBuddyListener(new QQWrapper.NodeIKernelBuddyListener(listener as BuddyListener));
|
||||
}
|
||||
case 'GroupListener': {
|
||||
return this.session.getGroupService().addKernelGroupListener(new QQWrapper.NodeIKernelGroupListener(listener as GroupListener));
|
||||
}
|
||||
case 'MsgListener': {
|
||||
return this.session.getMsgService().addKernelMsgListener(new QQWrapper.NodeIKernelMsgListener(listener as MsgListener));
|
||||
}
|
||||
case 'ProfileListener': {
|
||||
return this.session.getProfileService().addKernelProfileListener(new QQWrapper.NodeIKernelProfileListener(listener as ProfileListener));
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
onLoginSuccess(func: OnLoginSuccess) {
|
||||
NTEventDispatch.init({
|
||||
ListenerMap: QQWrapper,
|
||||
WrapperSession: this.session,
|
||||
});
|
||||
this.onLoginSuccessFuncList.push(func);
|
||||
}
|
||||
|
||||
async quickLogin(uin: string): Promise<QuickLoginResult> {
|
||||
const loginList = await this.loginService.getLoginList();
|
||||
|
||||
if (loginList.result !== 0) throw new Error('没有可快速登录的QQ号');
|
||||
const currentLogin = loginList.LocalLoginInfoList.find((item) => item.uin === uin);
|
||||
if (!currentLogin || !currentLogin?.isQuickLogin) throw new Error(`${uin}快速登录不可用`);
|
||||
|
||||
await sleep(1000);
|
||||
const loginRet = await this.loginService.quickLoginWithUin(uin);
|
||||
if (!loginRet.result) {
|
||||
throw new Error('快速登录失败 ' + loginRet.loginErrorInfo.errMsg);
|
||||
}
|
||||
return loginRet;
|
||||
}
|
||||
|
||||
async qrLogin(cb: (url: string, base64: string, buffer: Buffer) => Promise<void>) {
|
||||
return new Promise<{ url: string, base64: string, buffer: Buffer }>((resolve, reject) => {
|
||||
this.loginListener.onQRCodeGetPicture = (arg) => {
|
||||
const base64Data = arg.pngBase64QrcodeData.split('data:image/png;base64,')[1];
|
||||
const buffer = Buffer.from(base64Data, 'base64');
|
||||
cb(arg.qrcodeUrl, arg.pngBase64QrcodeData, buffer);
|
||||
};
|
||||
this.loginService.getQRCodePicture();
|
||||
});
|
||||
}
|
||||
|
||||
async passwordLogin(uin: string, password: string, proofSig?: string, proofRand?: string, proofSid?: string) {
|
||||
const passwordMd5 = crypto.createHash('md5').update(password).digest('hex');
|
||||
const loginArg: passwordLoginArgType = {
|
||||
uin,
|
||||
passwordMd5,
|
||||
step: proofSig && proofRand && proofSid ? 1 : 0,
|
||||
newDeviceLoginSig: '',
|
||||
proofWaterSig: proofSig || '',
|
||||
proofWaterRand: proofRand || '',
|
||||
proofWaterSid: proofSid || ''
|
||||
};
|
||||
|
||||
await this.loginService.getLoginList();
|
||||
await sleep(1000);
|
||||
|
||||
const ret = await this.loginService.passwordLogin(loginArg);
|
||||
|
||||
switch (ret.result) {
|
||||
case '0': { // Success
|
||||
break;
|
||||
}
|
||||
case '140022008': { // CAPTCHA required
|
||||
break;
|
||||
}
|
||||
case '4': // Mobile verify required
|
||||
case '140022013': // Incorrect password
|
||||
default:
|
||||
}
|
||||
}
|
||||
async getQuickLoginList() {
|
||||
const loginList = await this.loginService.getLoginList();
|
||||
return loginList;
|
||||
}
|
||||
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean {
|
||||
if (memberNew.role !== memberOld?.role) {
|
||||
log(`群 ${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员'}`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const napCatCore = new NapCatCore();
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import {
|
||||
type Friend,
|
||||
type Group,
|
||||
type GroupMember,
|
||||
type SelfInfo,
|
||||
type BuddyCategoryType,
|
||||
FriendV2
|
||||
} from './entities';
|
||||
import { isNumeric } from '@/common/utils/helper';
|
||||
import { LimitedHashTable } from '@/common/utils/MessageUnique';
|
||||
import { NTQQGroupApi } from '@/core/apis';
|
||||
|
||||
export const selfInfo: SelfInfo = {
|
||||
uid: '',
|
||||
uin: '',
|
||||
nick: '',
|
||||
online: true
|
||||
};
|
||||
export const groups: Map<string, Group> = new Map<string, Group>();
|
||||
|
||||
export function deleteGroup(groupQQ: string) {
|
||||
groups.delete(groupQQ);
|
||||
groupMembers.delete(groupQQ);
|
||||
}
|
||||
|
||||
// 群号 -> 群成员map(uid=>GroupMember)
|
||||
export const groupMembers: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>();
|
||||
|
||||
export const friends: Map<string, Friend> = new Map<string, Friend>();
|
||||
|
||||
//转换列表
|
||||
//export const CachedIdMap = new LimitedHashTable<string, string>(1000);
|
||||
|
||||
export async function getGroup(qq: string | number): Promise<Group | undefined> {
|
||||
let group = groups.get(qq.toString());
|
||||
if (!group) {
|
||||
try {
|
||||
const _groups = await NTQQGroupApi.getGroups();
|
||||
if (_groups.length) {
|
||||
_groups.forEach(g => {
|
||||
groups.set(g.groupCode, g);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
group = groups.get(qq.toString());
|
||||
return group;
|
||||
}
|
||||
|
||||
export async function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number) {
|
||||
groupQQ = groupQQ.toString();
|
||||
memberUinOrUid = memberUinOrUid.toString();
|
||||
let members = groupMembers.get(groupQQ);
|
||||
if (!members) {
|
||||
try {
|
||||
members = await NTQQGroupApi.getGroupMembers(groupQQ);
|
||||
// 更新群成员列表
|
||||
groupMembers.set(groupQQ, members);
|
||||
}
|
||||
catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// log('getGroupMember', members);
|
||||
const getMember = () => {
|
||||
let member: GroupMember | undefined = undefined;
|
||||
if (isNumeric(memberUinOrUid)) {
|
||||
member = Array.from(members!.values()).find(member => member.uin === memberUinOrUid);
|
||||
} else {
|
||||
member = members!.get(memberUinOrUid);
|
||||
}
|
||||
return member;
|
||||
};
|
||||
let member = getMember();
|
||||
if (!member) {
|
||||
members = await NTQQGroupApi.getGroupMembers(groupQQ);
|
||||
member = getMember();
|
||||
}
|
||||
return member;
|
||||
}
|
||||
// 考虑优化 移入QQ缓存或使用Api直接获取
|
||||
export const tempGroupCodeMap: Record<string, string> = {}; // peerUid => 群号
|
||||
|
||||
// 保留 需要频繁读写
|
||||
export const stat = {
|
||||
packet_received: 0,
|
||||
packet_sent: 0,
|
||||
message_received: 0,
|
||||
message_sent: 0,
|
||||
last_message_time: 0,
|
||||
// 以下字段无用, 全部为0
|
||||
disconnect_times: 0,
|
||||
lost_times: 0,
|
||||
packet_lost: 0,
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
import { ChatType } from './msg';
|
||||
|
||||
export interface CacheScanResult {
|
||||
result: number;
|
||||
size: [ // 单位为字节
|
||||
string, // 系统总存储空间
|
||||
string, // 系统可用存储空间
|
||||
string, // 系统已用存储空间
|
||||
string, // QQ总大小
|
||||
string, // 「聊天与文件」大小
|
||||
string, // 未知
|
||||
string, // 「缓存数据」大小
|
||||
string, // 「其他数据」大小
|
||||
string, // 未知
|
||||
]
|
||||
}
|
||||
|
||||
export interface ChatCacheList {
|
||||
pageCount: number;
|
||||
infos: ChatCacheListItem[]
|
||||
};
|
||||
|
||||
export interface ChatCacheListItem {
|
||||
chatType: ChatType;
|
||||
basicChatCacheInfo: ChatCacheListItemBasic;
|
||||
guildChatCacheInfo: unknown[]; // TODO: 没用过频道所以不知道这里边的详细内容
|
||||
}
|
||||
|
||||
export interface ChatCacheListItemBasic {
|
||||
chatSize: string;
|
||||
chatTime: string;
|
||||
uid: string;
|
||||
uin: string;
|
||||
remarkName: string;
|
||||
nickName: string;
|
||||
chatType?: ChatType;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
|
||||
export enum CacheFileType {
|
||||
IMAGE = 0,
|
||||
VIDEO = 1,
|
||||
AUDIO = 2,
|
||||
DOCUMENT = 3,
|
||||
OTHER = 4,
|
||||
}
|
||||
|
||||
export interface CacheFileList {
|
||||
infos: CacheFileListItem[],
|
||||
}
|
||||
|
||||
export interface CacheFileListItem {
|
||||
fileSize: string;
|
||||
fileTime: string;
|
||||
fileKey: string;
|
||||
elementId: string;
|
||||
elementIdStr: string;
|
||||
fileType: CacheFileType;
|
||||
path: string;
|
||||
fileName: string;
|
||||
senderId: string;
|
||||
previewPath: string;
|
||||
senderName: string;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
@@ -1,404 +0,0 @@
|
||||
import {
|
||||
AtType,
|
||||
ElementType, FaceIndex, FaceType, PicElement,
|
||||
PicType,
|
||||
SendArkElement,
|
||||
SendFaceElement,
|
||||
SendFileElement, SendMarkdownElement, SendMarketFaceElement,
|
||||
SendPicElement,
|
||||
SendPttElement,
|
||||
SendReplyElement,
|
||||
sendShareLocationElement,
|
||||
SendTextElement,
|
||||
SendVideoElement,
|
||||
viedo_type
|
||||
} from './index';
|
||||
import { promises as fs } from 'node:fs';
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import { NTQQFileApi } from '@/core/apis/file';
|
||||
import { calculateFileMD5, isGIF } from '@/common/utils/file';
|
||||
import { log, logDebug, logError } from '@/common/utils/log';
|
||||
import { defaultVideoThumb, getVideoInfo } from '@/common/utils/video';
|
||||
import { encodeSilk } from '@/common/utils/audio';
|
||||
import { isNull } from '@/common/utils/helper';
|
||||
import faceConfig from './face_config.json';
|
||||
import * as pathLib from 'node:path';
|
||||
import { SignMiniApp } from '../apis';
|
||||
|
||||
export const mFaceCache = new Map<string, string>(); // emojiId -> faceName
|
||||
|
||||
|
||||
export class SendMsgElementConstructor {
|
||||
static location(): sendShareLocationElement {
|
||||
return {
|
||||
elementType: ElementType.SHARELOCATION,
|
||||
elementId: '',
|
||||
shareLocationElement: {
|
||||
text: "测试",
|
||||
ext: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
static text(content: string): SendTextElement {
|
||||
return {
|
||||
elementType: ElementType.TEXT,
|
||||
elementId: '',
|
||||
textElement: {
|
||||
content,
|
||||
atType: AtType.notAt,
|
||||
atUid: '',
|
||||
atTinyId: '',
|
||||
atNtUid: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static at(atUid: string, atNtUid: string, atType: AtType, atName: string): SendTextElement {
|
||||
return {
|
||||
elementType: ElementType.TEXT,
|
||||
elementId: '',
|
||||
textElement: {
|
||||
content: `@${atName}`,
|
||||
atType,
|
||||
atUid,
|
||||
atTinyId: '',
|
||||
atNtUid,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static reply(msgSeq: string, msgId: string, senderUin: string, senderUinStr: string): SendReplyElement {
|
||||
return {
|
||||
elementType: ElementType.REPLY,
|
||||
elementId: '',
|
||||
replyElement: {
|
||||
replayMsgSeq: msgSeq, // raw.msgSeq
|
||||
replayMsgId: msgId, // raw.msgId
|
||||
senderUin: senderUin,
|
||||
senderUinStr: senderUinStr,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static async pic(picPath: string, summary: string = '', subType: 0 | 1 = 0): Promise<SendPicElement> {
|
||||
const { md5, fileName, path, fileSize } = await NTQQFileApi.uploadFile(picPath, ElementType.PIC, subType);
|
||||
if (fileSize === 0) {
|
||||
throw '文件异常,大小为0';
|
||||
}
|
||||
const imageSize = await NTQQFileApi.getImageSize(picPath);
|
||||
const picElement: any = {
|
||||
md5HexStr: md5,
|
||||
fileSize: fileSize.toString(),
|
||||
picWidth: imageSize?.width,
|
||||
picHeight: imageSize?.height,
|
||||
fileName: fileName,
|
||||
sourcePath: path,
|
||||
original: true,
|
||||
picType: isGIF(picPath) ? PicType.gif : PicType.jpg,
|
||||
picSubType: subType,
|
||||
fileUuid: '',
|
||||
fileSubId: '',
|
||||
thumbFileSize: 0,
|
||||
summary
|
||||
};
|
||||
//logDebug('图片信息', picElement);
|
||||
return {
|
||||
elementType: ElementType.PIC,
|
||||
elementId: '',
|
||||
picElement,
|
||||
};
|
||||
}
|
||||
|
||||
static async file(filePath: string, fileName: string = '', folderId: string = ''): Promise<SendFileElement> {
|
||||
const { md5, fileName: _fileName, path, fileSize } = await NTQQFileApi.uploadFile(filePath, ElementType.FILE);
|
||||
if (fileSize === 0) {
|
||||
throw '文件异常,大小为0';
|
||||
}
|
||||
const element: SendFileElement = {
|
||||
elementType: ElementType.FILE,
|
||||
elementId: '',
|
||||
fileElement: {
|
||||
fileName: fileName || _fileName,
|
||||
folderId: folderId,
|
||||
'filePath': path!,
|
||||
'fileSize': (fileSize).toString(),
|
||||
}
|
||||
};
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
static async video(filePath: string, fileName: string = '', diyThumbPath: string = '', videotype: viedo_type = viedo_type.VIDEO_FORMAT_MP4): Promise<SendVideoElement> {
|
||||
const { fileName: _fileName, path, fileSize, md5 } = await NTQQFileApi.uploadFile(filePath, ElementType.VIDEO);
|
||||
if (fileSize === 0) {
|
||||
throw '文件异常,大小为0';
|
||||
}
|
||||
let thumb = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`);
|
||||
thumb = pathLib.dirname(thumb);
|
||||
// log("thumb 目录", thumb)
|
||||
let videoInfo = {
|
||||
width: 1920, height: 1080,
|
||||
time: 15,
|
||||
format: 'mp4',
|
||||
size: fileSize,
|
||||
filePath
|
||||
};
|
||||
try {
|
||||
videoInfo = await getVideoInfo(path);
|
||||
//logDebug('视频信息', videoInfo);
|
||||
} catch (e) {
|
||||
logError('获取视频信息失败', e);
|
||||
}
|
||||
const createThumb = new Promise<string>((resolve, reject) => {
|
||||
const thumbFileName = `${md5}_0.png`;
|
||||
const thumbPath = pathLib.join(thumb, thumbFileName);
|
||||
ffmpeg(filePath)
|
||||
.on('end', () => {
|
||||
})
|
||||
.on('error', (err) => {
|
||||
logDebug('获取视频封面失败,使用默认封面', err);
|
||||
if (diyThumbPath) {
|
||||
fs.copyFile(diyThumbPath, thumbPath).then(() => {
|
||||
resolve(thumbPath);
|
||||
}).catch(reject);
|
||||
} else {
|
||||
fs.writeFile(thumbPath, defaultVideoThumb).then(() => {
|
||||
resolve(thumbPath);
|
||||
}).catch(reject);
|
||||
}
|
||||
})
|
||||
.screenshots({
|
||||
timestamps: [0],
|
||||
filename: thumbFileName,
|
||||
folder: thumb,
|
||||
size: videoInfo.width + 'x' + videoInfo.height
|
||||
}).on('end', () => {
|
||||
resolve(thumbPath);
|
||||
});
|
||||
});
|
||||
const thumbPath = new Map();
|
||||
const _thumbPath = await createThumb;
|
||||
const thumbSize = (await fs.stat(_thumbPath)).size;
|
||||
// log("生成缩略图", _thumbPath)
|
||||
thumbPath.set(0, _thumbPath);
|
||||
const thumbMd5 = await calculateFileMD5(_thumbPath);
|
||||
const element: SendVideoElement = {
|
||||
elementType: ElementType.VIDEO,
|
||||
elementId: '',
|
||||
videoElement: {
|
||||
fileName: fileName || _fileName,
|
||||
filePath: path,
|
||||
videoMd5: md5,
|
||||
thumbMd5,
|
||||
fileTime: videoInfo.time,
|
||||
thumbPath: thumbPath,
|
||||
thumbSize,
|
||||
thumbWidth: videoInfo.width,
|
||||
thumbHeight: videoInfo.height,
|
||||
fileSize: '' + fileSize,
|
||||
//fileFormat: videotype
|
||||
// fileUuid: "",
|
||||
// transferStatus: 0,
|
||||
// progress: 0,
|
||||
// invalidState: 0,
|
||||
// fileSubId: "",
|
||||
// fileBizId: null,
|
||||
// originVideoMd5: "",
|
||||
// fileFormat: 2,
|
||||
// import_rich_media_context: null,
|
||||
// sourceVideoCodecFormat: 2
|
||||
}
|
||||
};
|
||||
return element;
|
||||
}
|
||||
|
||||
static async ptt(pttPath: string): Promise<SendPttElement> {
|
||||
const { converted, path: silkPath, duration } = await encodeSilk(pttPath);
|
||||
// log("生成语音", silkPath, duration);
|
||||
if (!silkPath) {
|
||||
throw '语音转换失败, 请检查语音文件是否正常';
|
||||
}
|
||||
const { md5, fileName, path, fileSize } = await NTQQFileApi.uploadFile(silkPath!, ElementType.PTT);
|
||||
if (fileSize === 0) {
|
||||
throw '文件异常,大小为0';
|
||||
}
|
||||
if (converted) {
|
||||
fs.unlink(silkPath).then();
|
||||
}
|
||||
return {
|
||||
elementType: ElementType.PTT,
|
||||
elementId: '',
|
||||
pttElement: {
|
||||
fileName: fileName,
|
||||
filePath: path,
|
||||
md5HexStr: md5,
|
||||
fileSize: fileSize,
|
||||
// duration: Math.max(1, Math.round(fileSize / 1024 / 3)), // 一秒钟大概是3kb大小, 小于1秒的按1秒算
|
||||
duration: duration || 1,
|
||||
formatType: 1,
|
||||
voiceType: 1,
|
||||
voiceChangeType: 0,
|
||||
canConvert2Text: true,
|
||||
waveAmplitudes: [
|
||||
0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17,
|
||||
],
|
||||
fileSubId: '',
|
||||
playState: 1,
|
||||
autoConvertText: 0,
|
||||
}
|
||||
};
|
||||
}
|
||||
// NodeIQQNTWrapperSession sendMsg [
|
||||
// "0",
|
||||
// {
|
||||
// "peerUid": "u_e_RIxgTs2NaJ68h0PwOPSg",
|
||||
// "chatType": 1,
|
||||
// "guildId": ""
|
||||
// },
|
||||
// [
|
||||
// {
|
||||
// "elementId": "0",
|
||||
// "elementType": 6,
|
||||
// "faceElement": {
|
||||
// "faceIndex": 0,
|
||||
// "faceType": 5,
|
||||
// "msgType": 0,
|
||||
// "pokeType": 1,
|
||||
// "pokeStrength": 0
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// {}
|
||||
// ]
|
||||
static face(faceId: number): SendFaceElement {
|
||||
// 从face_config.json中获取表情名称
|
||||
const sysFaces = faceConfig.sysface;
|
||||
const emojiFaces = faceConfig.emoji;
|
||||
const face: any = sysFaces.find((face) => face.QSid === faceId.toString());
|
||||
faceId = parseInt(faceId.toString());
|
||||
// let faceType = parseInt(faceId.toString().substring(0, 1));
|
||||
let faceType = 1;
|
||||
if (faceId >= 222) {
|
||||
faceType = 2;
|
||||
}
|
||||
if (face.AniStickerType) {
|
||||
faceType = 3;
|
||||
}
|
||||
return {
|
||||
elementType: ElementType.FACE,
|
||||
elementId: '',
|
||||
faceElement: {
|
||||
faceIndex: faceId,
|
||||
faceType,
|
||||
faceText: face.QDes,
|
||||
stickerId: face.AniStickerId,
|
||||
stickerType: face.AniStickerType,
|
||||
packId: face.AniStickerPackId,
|
||||
sourceType: 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static mface(emojiPackageId: number, emojiId: string, key: string, faceName: string): SendMarketFaceElement {
|
||||
return {
|
||||
elementType: ElementType.MFACE,
|
||||
marketFaceElement: {
|
||||
emojiPackageId,
|
||||
emojiId,
|
||||
key,
|
||||
faceName: faceName || mFaceCache.get(emojiId) || '[商城表情]',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static dice(resultId: number | null): SendFaceElement {
|
||||
// 实际测试并不能控制结果
|
||||
|
||||
// 随机1到6
|
||||
// if (isNull(resultId)) resultId = Math.floor(Math.random() * 6) + 1;
|
||||
return {
|
||||
elementType: ElementType.FACE,
|
||||
elementId: '',
|
||||
faceElement: {
|
||||
faceIndex: FaceIndex.dice,
|
||||
faceType: FaceType.dice,
|
||||
'faceText': '[骰子]',
|
||||
'packId': '1',
|
||||
'stickerId': '33',
|
||||
'sourceType': 1,
|
||||
'stickerType': 2,
|
||||
// resultId: resultId.toString(),
|
||||
'surpriseId': '',
|
||||
// "randomType": 1,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 猜拳(石头剪刀布)表情
|
||||
static rps(resultId: number | null): SendFaceElement {
|
||||
// 实际测试并不能控制结果
|
||||
// if (isNull(resultId)) resultId = Math.floor(Math.random() * 3) + 1;
|
||||
return {
|
||||
elementType: ElementType.FACE,
|
||||
elementId: '',
|
||||
faceElement: {
|
||||
'faceIndex': FaceIndex.RPS,
|
||||
'faceText': '[包剪锤]',
|
||||
'faceType': 3,
|
||||
'packId': '1',
|
||||
'stickerId': '34',
|
||||
'sourceType': 1,
|
||||
'stickerType': 2,
|
||||
// 'resultId': resultId.toString(),
|
||||
'surpriseId': '',
|
||||
// "randomType": 1,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ark(data: any): SendArkElement {
|
||||
if (typeof data !== 'string') {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
return {
|
||||
elementType: ElementType.ARK,
|
||||
elementId: '',
|
||||
arkElement: {
|
||||
bytesData: data,
|
||||
linkInfo: null,
|
||||
subElementType: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static markdown(content: string): SendMarkdownElement {
|
||||
return {
|
||||
elementType: ElementType.MARKDOWN,
|
||||
elementId: '',
|
||||
markdownElement: {
|
||||
content
|
||||
}
|
||||
};
|
||||
}
|
||||
static async miniapp(): Promise<SendArkElement> {
|
||||
let ret = await SignMiniApp({
|
||||
prompt: "Bot Test",
|
||||
title: "Bot Test",
|
||||
preview: "https://tianquan.gtimg.cn/qqAIAgent/item/7/square.png",
|
||||
jumpUrl: "https://www.bilibili.com/",
|
||||
tag: "Bot Test",
|
||||
tagIcon: "https://tianquan.gtimg.cn/shoal/qqAIAgent/3e9d70c9-d98c-45b8-80b4-79d82971b514.png",
|
||||
source: "Bot Test",
|
||||
sourcelogo: "https://tianquan.gtimg.cn/shoal/qqAIAgent/3e9d70c9-d98c-45b8-80b4-79d82971b514.png"
|
||||
});
|
||||
return {
|
||||
elementType: ElementType.ARK,
|
||||
elementId: '',
|
||||
arkElement: {
|
||||
bytesData: ret,
|
||||
linkInfo: null,
|
||||
subElementType: null
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,64 +0,0 @@
|
||||
import { QQLevel, Sex } from './user';
|
||||
export enum GroupListUpdateType {
|
||||
REFRESHALL,
|
||||
GETALL,
|
||||
MODIFIED,
|
||||
REMOVE
|
||||
}
|
||||
export interface Group {
|
||||
groupCode: string,
|
||||
createTime?: string,//高版本才有
|
||||
maxMember: number,
|
||||
memberCount: number,
|
||||
groupName: string,
|
||||
groupStatus: number,
|
||||
memberRole: number,
|
||||
isTop: boolean,
|
||||
toppedTimestamp: string,
|
||||
privilegeFlag: number, //65760
|
||||
isConf: boolean,
|
||||
hasModifyConfGroupFace: boolean,
|
||||
hasModifyConfGroupName: boolean,
|
||||
remarkName: string,
|
||||
hasMemo: boolean,
|
||||
groupShutupExpireTime: string, //"0",
|
||||
personShutupExpireTime: string, //"0",
|
||||
discussToGroupUin: string, //"0",
|
||||
discussToGroupMaxMsgSeq: number,
|
||||
discussToGroupTime: number,
|
||||
groupFlagExt: number, //1073938496,
|
||||
authGroupType: number, //0,
|
||||
groupCreditLevel: number, //0,
|
||||
groupFlagExt3: number, //0,
|
||||
groupOwnerId: {
|
||||
memberUin: string, //"0",
|
||||
memberUid: string, //"u_fbf8N7aeuZEnUiJAbQ9R8Q"
|
||||
}
|
||||
}
|
||||
|
||||
export enum GroupMemberRole {
|
||||
normal = 2,
|
||||
admin = 3,
|
||||
owner = 4
|
||||
}
|
||||
|
||||
export interface GroupMember {
|
||||
memberSpecialTitle?: string;
|
||||
avatarPath: string;
|
||||
cardName: string;
|
||||
cardType: number;
|
||||
isDelete: boolean;
|
||||
nick: string;
|
||||
qid: string;
|
||||
remark: string;
|
||||
role: GroupMemberRole; // 群主:4, 管理员:3,群员:2
|
||||
shutUpTime: number; // 禁言时间,单位是什么暂时不清楚
|
||||
uid: string; // 加密的字符串
|
||||
uin: string; // QQ号
|
||||
isRobot: boolean;
|
||||
sex?: Sex
|
||||
qqLevel?: QQLevel
|
||||
isChangeRole: boolean;
|
||||
joinTime: string;
|
||||
lastSpeakTime: string;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export * from './user';
|
||||
export * from './group';
|
||||
export * from './msg';
|
||||
export * from './notify';
|
||||
export * from './cache';
|
||||
export * from './constructor';
|
||||
|
||||
@@ -1,787 +0,0 @@
|
||||
import { GroupMemberRole } from './group';
|
||||
|
||||
|
||||
export interface Peer {
|
||||
chatType: ChatType;
|
||||
peerUid: string; // 如果是群聊uid为群号,私聊uid就是加密的字符串
|
||||
guildId?: string;
|
||||
}
|
||||
export interface KickedOffLineInfo {
|
||||
appId: number
|
||||
instanceId: number
|
||||
sameDevice: boolean
|
||||
tipsDesc: string
|
||||
tipsTitle: string
|
||||
kickedType: number
|
||||
securityKickedType: number
|
||||
}
|
||||
export interface GetFileListParam {
|
||||
sortType: number
|
||||
fileCount: number
|
||||
startIndex: number
|
||||
sortOrder: number
|
||||
showOnlinedocFolder: number
|
||||
}
|
||||
export enum ElementType {
|
||||
UNKNOWN = 0,
|
||||
TEXT = 1,
|
||||
PIC = 2,
|
||||
FILE = 3,
|
||||
PTT = 4,
|
||||
VIDEO = 5,
|
||||
FACE = 6,
|
||||
REPLY = 7,
|
||||
WALLET = 9,
|
||||
GreyTip = 8,//Poke别叫戳一搓了 官方名字拍一拍 戳一戳是另一个名字
|
||||
ARK = 10,
|
||||
MFACE = 11,
|
||||
LIVEGIFT = 12,
|
||||
STRUCTLONGMSG = 13,
|
||||
MARKDOWN = 14,
|
||||
GIPHY = 15,
|
||||
MULTIFORWARD = 16,
|
||||
INLINEKEYBOARD = 17,
|
||||
INTEXTGIFT = 18,
|
||||
CALENDAR = 19,
|
||||
YOLOGAMERESULT = 20,
|
||||
AVRECORD = 21,
|
||||
FEED = 22,
|
||||
TOFURECORD = 23,
|
||||
ACEBUBBLE = 24,
|
||||
ACTIVITY = 25,
|
||||
TOFU = 26,
|
||||
FACEBUBBLE = 27,
|
||||
SHARELOCATION = 28,
|
||||
TASKTOPMSG = 29,
|
||||
RECOMMENDEDMSG = 43,
|
||||
ACTIONBAR = 44
|
||||
}
|
||||
export interface ActionBarElement {
|
||||
rows: InlineKeyboardRow[];
|
||||
botAppid: string;
|
||||
}
|
||||
export interface SendActionBarElement {
|
||||
elementType: ElementType.ACTIONBAR;
|
||||
elementId: string;
|
||||
actionBarElement: ActionBarElement;
|
||||
}
|
||||
export interface RecommendedMsgElement {
|
||||
rows: InlineKeyboardRow[];
|
||||
botAppid: string;
|
||||
}
|
||||
export interface SendRecommendedMsgElement {
|
||||
elementType: ElementType.RECOMMENDEDMSG;
|
||||
elementId: string;
|
||||
recommendedMsgElement: RecommendedMsgElement;
|
||||
}
|
||||
export interface InlineKeyboardButton {
|
||||
id: string;
|
||||
label: string;
|
||||
visitedLabel: string;
|
||||
unsupportTips: string;
|
||||
data: string;
|
||||
specifyRoleIds: string[];
|
||||
specifyTinyids: string[];
|
||||
style: number;
|
||||
type: number;
|
||||
clickLimit: number;
|
||||
atBotShowChannelList: boolean;
|
||||
permissionType: number;
|
||||
}
|
||||
export interface InlineKeyboardRow {
|
||||
buttons: InlineKeyboardButton[];
|
||||
}
|
||||
export interface TofuElementContent {
|
||||
color: string;
|
||||
tittle: string;
|
||||
}
|
||||
export interface TaskTopMsgElement {
|
||||
msgTitle: string;
|
||||
msgSummary: string;
|
||||
iconUrl: string;
|
||||
topMsgType: number;
|
||||
}
|
||||
export interface SendTaskTopMsgElement {
|
||||
elementType: ElementType.TASKTOPMSG;
|
||||
elementId: string;
|
||||
taskTopMsgElement: TaskTopMsgElement;
|
||||
}
|
||||
export interface TofuRecordElement {
|
||||
type: number;
|
||||
busiid: string;
|
||||
busiuuid: string;
|
||||
descriptionContent: string;
|
||||
contentlist: TofuElementContent[],
|
||||
background: string;
|
||||
icon: string;
|
||||
uinlist: string[],
|
||||
uidlist: string[],
|
||||
busiExtra: string;
|
||||
updateTime: string;
|
||||
dependedmsgid: string;
|
||||
msgtime: string;
|
||||
onscreennotify: boolean;
|
||||
}
|
||||
export interface SendTofuRecordElement {
|
||||
elementType: ElementType.TOFURECORD;
|
||||
elementId: string;
|
||||
tofuRecordElement: TofuRecordElement;
|
||||
}
|
||||
|
||||
export interface FaceBubbleElement {
|
||||
faceCount: number;
|
||||
faceSummary: string;
|
||||
faceFlag: number;
|
||||
content: string;
|
||||
oldVersionStr: string;
|
||||
faceType: number;
|
||||
others: string;
|
||||
yellowFaceInfo: {
|
||||
index: number;
|
||||
buf: string;
|
||||
compatibleText: string;
|
||||
text: string;
|
||||
}
|
||||
}
|
||||
export interface SendFaceBubbleElement {
|
||||
elementType: ElementType.FACEBUBBLE;
|
||||
elementId: string;
|
||||
faceBubbleElement: FaceBubbleElement;
|
||||
|
||||
}
|
||||
export interface AvRecordElement {
|
||||
type: number;
|
||||
time: string;
|
||||
text: string;
|
||||
mainType: number;
|
||||
hasRead: boolean;
|
||||
extraType: number;
|
||||
}
|
||||
export interface SendavRecordElement {
|
||||
elementType: ElementType.AVRECORD;
|
||||
elementId: string;
|
||||
avRecordElement: AvRecordElement;
|
||||
}
|
||||
export interface YoloUserInfo {
|
||||
uid: string;
|
||||
result: number;
|
||||
rank: number;
|
||||
bizId: string
|
||||
}
|
||||
export interface SendInlineKeyboardElement {
|
||||
elementType: ElementType.INLINEKEYBOARD;
|
||||
elementId: string;
|
||||
inlineKeyboardElement: {
|
||||
rows: number;
|
||||
botAppid: string;
|
||||
}
|
||||
|
||||
}
|
||||
export interface YoloGameResultElement {
|
||||
UserInfo: YoloUserInfo[];
|
||||
}
|
||||
export interface SendYoloGameResultElement {
|
||||
elementType: ElementType.YOLOGAMERESULT;
|
||||
yoloGameResultElement: YoloGameResultElement
|
||||
}
|
||||
export interface GiphyElement {
|
||||
id: string;
|
||||
isClip: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
export interface SendGiphyElement {
|
||||
elementType: ElementType.GIPHY;
|
||||
elementId: string;
|
||||
giphyElement: GiphyElement;
|
||||
}
|
||||
export interface SendWalletElement {
|
||||
elementType: ElementType.UNKNOWN;//不做 设置位置
|
||||
elementId: string;
|
||||
walletElement: {}
|
||||
}
|
||||
export interface CalendarElement {
|
||||
summary: string;
|
||||
msg: string;
|
||||
expireTimeMs: string;
|
||||
schemaType: number;
|
||||
schema: string
|
||||
}
|
||||
export interface SendCalendarElement {
|
||||
elementType: ElementType.CALENDAR;
|
||||
elementId: string;
|
||||
calendarElement: CalendarElement;
|
||||
}
|
||||
export interface SendliveGiftElement {
|
||||
elementType: ElementType.LIVEGIFT;
|
||||
elementId: string;
|
||||
liveGiftElement: {}
|
||||
}
|
||||
export interface SendTextElement {
|
||||
elementType: ElementType.TEXT;
|
||||
elementId: string;
|
||||
textElement: {
|
||||
content: string;
|
||||
atType: number;
|
||||
atUid: string;
|
||||
atTinyId: string;
|
||||
atNtUid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SendPttElement {
|
||||
elementType: ElementType.PTT;
|
||||
elementId: string;
|
||||
pttElement: {
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
md5HexStr: string;
|
||||
fileSize: number;
|
||||
duration: number; // 单位是秒
|
||||
formatType: number;
|
||||
voiceType: number;
|
||||
voiceChangeType: number;
|
||||
canConvert2Text: boolean;
|
||||
waveAmplitudes: number[];
|
||||
fileSubId: string;
|
||||
playState: number;
|
||||
autoConvertText: number;
|
||||
};
|
||||
}
|
||||
|
||||
export enum PicType {
|
||||
gif = 2000,
|
||||
jpg = 1000
|
||||
}
|
||||
|
||||
export enum PicSubType {
|
||||
normal = 0, // 普通图片,大图
|
||||
face = 1 // 表情包小图
|
||||
}
|
||||
|
||||
export interface SendPicElement {
|
||||
elementType: ElementType.PIC;
|
||||
elementId: string;
|
||||
picElement:PicElement
|
||||
}
|
||||
export interface ReplyElement {
|
||||
replayMsgSeq: string;
|
||||
replayMsgId: string;
|
||||
senderUin: string;
|
||||
senderUinStr: string;
|
||||
}
|
||||
export interface SendReplyElement {
|
||||
elementType: ElementType.REPLY;
|
||||
elementId: string;
|
||||
replyElement: ReplyElement
|
||||
}
|
||||
|
||||
export interface SendFaceElement {
|
||||
elementType: ElementType.FACE;
|
||||
elementId: string;
|
||||
faceElement: FaceElement;
|
||||
}
|
||||
|
||||
export interface SendMarketFaceElement {
|
||||
elementType: ElementType.MFACE;
|
||||
marketFaceElement: MarketFaceElement;
|
||||
}
|
||||
export interface SendstructLongMsgElement {
|
||||
elementType: ElementType.STRUCTLONGMSG;
|
||||
elementId: string;
|
||||
structLongMsgElement: StructLongMsgElement;
|
||||
}
|
||||
export interface StructLongMsgElement {
|
||||
xmlContent: string;
|
||||
resId: string;
|
||||
}
|
||||
export interface SendactionBarElement {
|
||||
elementType: ElementType.ACTIONBAR;
|
||||
elementId: string;
|
||||
actionBarElement: {
|
||||
rows: number;
|
||||
botAppid: string;
|
||||
}
|
||||
}
|
||||
export interface ShareLocationElement {
|
||||
text: string;
|
||||
ext: string;
|
||||
}
|
||||
export interface sendShareLocationElement {
|
||||
elementType: ElementType.SHARELOCATION;
|
||||
elementId: string;
|
||||
shareLocationElement?: ShareLocationElement;
|
||||
}
|
||||
|
||||
export interface FileElement {
|
||||
fileMd5?: string;
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
fileSize: string;
|
||||
picHeight?: number;
|
||||
picWidth?: number;
|
||||
folderId?: string;
|
||||
picThumbPath?: Map<number, string>;
|
||||
file10MMd5?: string;
|
||||
fileSha?: string;
|
||||
fileSha3?: string;
|
||||
fileUuid?: string;
|
||||
fileSubId?: string;
|
||||
thumbFileSize?: number;
|
||||
fileBizId?: number
|
||||
}
|
||||
|
||||
export interface SendFileElement {
|
||||
elementType: ElementType.FILE;
|
||||
elementId: string;
|
||||
fileElement: FileElement;
|
||||
}
|
||||
|
||||
export interface SendVideoElement {
|
||||
elementType: ElementType.VIDEO;
|
||||
elementId: string;
|
||||
videoElement: VideoElement;
|
||||
}
|
||||
|
||||
export interface SendArkElement {
|
||||
elementType: ElementType.ARK;
|
||||
elementId: string;
|
||||
arkElement: ArkElement;
|
||||
}
|
||||
|
||||
export interface SendMarkdownElement {
|
||||
elementType: ElementType.MARKDOWN;
|
||||
elementId: string;
|
||||
markdownElement: MarkdownElement;
|
||||
}
|
||||
export type SendMessageElement = SendTextElement | SendPttElement |
|
||||
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
|
||||
SendVideoElement | SendArkElement | SendMarkdownElement | sendShareLocationElement;
|
||||
|
||||
export interface TextElement {
|
||||
content: string;
|
||||
atType: number;
|
||||
atUid: string;
|
||||
atTinyId: string;
|
||||
atNtUid: string;
|
||||
}
|
||||
export interface MessageElement {
|
||||
elementType: ElementType,
|
||||
elementId: string,
|
||||
extBufForUI: string,//"0x",
|
||||
textElement?: TextElement;
|
||||
faceElement?: FaceElement,
|
||||
marketFaceElement?: MarkdownElement,
|
||||
replyElement?: ReplyElement,
|
||||
picElement?: PicElement,
|
||||
pttElement?: PttElement,
|
||||
videoElement?: VideoElement,
|
||||
grayTipElement?: GrayTipElement,
|
||||
arkElement?: ArkElement,
|
||||
fileElement?: FileElement,
|
||||
liveGiftElement?: null,
|
||||
markdownElement?: MarkdownElement,
|
||||
structLongMsgElement?: StructLongMsgElement,
|
||||
multiForwardMsgElement?: MultiForwardMsgElement,
|
||||
giphyElement?: GiphyElement,
|
||||
walletElement?: null,
|
||||
inlineKeyboardElement?: InlineKeyboardElement,
|
||||
textGiftElement?: null,//????
|
||||
calendarElement?: CalendarElement,
|
||||
yoloGameResultElement?: YoloGameResultElement,
|
||||
avRecordElement?: AvRecordElement,
|
||||
structMsgElement?: null,
|
||||
faceBubbleElement?: FaceBubbleElement,
|
||||
shareLocationElement?: ShareLocationElement,
|
||||
tofuRecordElement?: TofuRecordElement,
|
||||
taskTopMsgElement?: TaskTopMsgElement,
|
||||
recommendedMsgElement?: RecommendedMsgElement,
|
||||
actionBarElement?:ActionBarElement
|
||||
|
||||
}
|
||||
export enum AtType {
|
||||
notAt = 0,
|
||||
atAll = 1,
|
||||
atUser = 2
|
||||
}
|
||||
|
||||
export enum ChatType {
|
||||
friend = 1,
|
||||
group = 2,
|
||||
chatDevice = 8, //移动设备?
|
||||
temp = 100
|
||||
|
||||
}
|
||||
// 来自Android分析
|
||||
export enum ChatType2 {
|
||||
KCHATTYPEADELIE = 42,
|
||||
KCHATTYPEBUDDYNOTIFY = 5,
|
||||
KCHATTYPEC2C = 1,
|
||||
KCHATTYPECIRCLE = 113,
|
||||
KCHATTYPEDATALINE = 8,
|
||||
KCHATTYPEDATALINEMQQ = 134,
|
||||
KCHATTYPEDISC = 3,
|
||||
KCHATTYPEFAV = 41,
|
||||
KCHATTYPEGAMEMESSAGE = 105,
|
||||
KCHATTYPEGAMEMESSAGEFOLDER = 116,
|
||||
KCHATTYPEGROUP = 2,
|
||||
KCHATTYPEGROUPBLESS = 133,
|
||||
KCHATTYPEGROUPGUILD = 9,
|
||||
KCHATTYPEGROUPHELPER = 7,
|
||||
KCHATTYPEGROUPNOTIFY = 6,
|
||||
KCHATTYPEGUILD = 4,
|
||||
KCHATTYPEGUILDMETA = 16,
|
||||
KCHATTYPEMATCHFRIEND = 104,
|
||||
KCHATTYPEMATCHFRIENDFOLDER = 109,
|
||||
KCHATTYPENEARBY = 106,
|
||||
KCHATTYPENEARBYASSISTANT = 107,
|
||||
KCHATTYPENEARBYFOLDER = 110,
|
||||
KCHATTYPENEARBYHELLOFOLDER = 112,
|
||||
KCHATTYPENEARBYINTERACT = 108,
|
||||
KCHATTYPEQQNOTIFY = 132,
|
||||
KCHATTYPERELATEACCOUNT = 131,
|
||||
KCHATTYPESERVICEASSISTANT = 118,
|
||||
KCHATTYPESERVICEASSISTANTSUB = 201,
|
||||
KCHATTYPESQUAREPUBLIC = 115,
|
||||
KCHATTYPESUBSCRIBEFOLDER = 30,
|
||||
KCHATTYPETEMPADDRESSBOOK = 111,
|
||||
KCHATTYPETEMPBUSSINESSCRM = 102,
|
||||
KCHATTYPETEMPC2CFROMGROUP = 100,
|
||||
KCHATTYPETEMPC2CFROMUNKNOWN = 99,
|
||||
KCHATTYPETEMPFRIENDVERIFY = 101,
|
||||
KCHATTYPETEMPNEARBYPRO = 119,
|
||||
KCHATTYPETEMPPUBLICACCOUNT = 103,
|
||||
KCHATTYPETEMPWPA = 117,
|
||||
KCHATTYPEUNKNOWN = 0,
|
||||
KCHATTYPEWEIYUN = 40,
|
||||
}
|
||||
|
||||
export interface PttElement {
|
||||
canConvert2Text: boolean;
|
||||
duration: number; // 秒数
|
||||
fileBizId: null;
|
||||
fileId: number; // 0
|
||||
fileName: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6.amr"
|
||||
filePath: string; // "/Users//Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/nt_qq_a6b15c9820595d25a56c1633ce19ad40/nt_data/Ptt/2023-11/Ori/e4d09c784d5a2abcb2f9980bdc7acfe6.amr"
|
||||
fileSize: string; // "4261"
|
||||
fileSubId: string; // "0"
|
||||
fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV"
|
||||
formatType: string; // 1
|
||||
invalidState: number; // 0
|
||||
md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6"
|
||||
playState: number; // 0
|
||||
progress: number; // 0
|
||||
text: string; // ""
|
||||
transferStatus: number; // 0
|
||||
translateStatus: number; // 0
|
||||
voiceChangeType: number; // 0
|
||||
voiceType: number; // 0
|
||||
waveAmplitudes: number[];
|
||||
}
|
||||
|
||||
export interface ArkElement {
|
||||
bytesData: string;
|
||||
linkInfo: null;
|
||||
subElementType: null;
|
||||
}
|
||||
|
||||
export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn';
|
||||
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn';
|
||||
|
||||
export interface PicElement {
|
||||
md5HexStr?: string;
|
||||
fileSize: number | string;//number
|
||||
picWidth: number;
|
||||
picHeight: number;
|
||||
fileName: string;
|
||||
sourcePath: string;
|
||||
original: boolean;
|
||||
picType: PicType;
|
||||
picSubType?: PicSubType;
|
||||
fileUuid: string;
|
||||
fileSubId: string;
|
||||
thumbFileSize: number;
|
||||
summary: string;
|
||||
thumbPath: Map<number, string>;
|
||||
originImageMd5?: string;
|
||||
originImageUrl?: string; // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
||||
};
|
||||
|
||||
export enum GrayTipElementSubType {
|
||||
INVITE_NEW_MEMBER = 12,
|
||||
MEMBER_NEW_TITLE = 17
|
||||
}
|
||||
|
||||
export interface GrayTipElement {
|
||||
subElementType: GrayTipElementSubType;
|
||||
revokeElement: {
|
||||
operatorRole: string;
|
||||
operatorUid: string;
|
||||
operatorNick: string;
|
||||
operatorRemark: string;
|
||||
operatorMemRemark?: string;
|
||||
wording: string; // 自定义的撤回提示语
|
||||
}
|
||||
aioOpGrayTipElement: TipAioOpGrayTipElement;
|
||||
groupElement: TipGroupElement;
|
||||
xmlElement: {
|
||||
content: string;
|
||||
templId: string;
|
||||
};
|
||||
jsonGrayTipElement: {
|
||||
busiId?: number;
|
||||
jsonStr: string;
|
||||
};
|
||||
}
|
||||
|
||||
export enum FaceType {
|
||||
normal = 1, // 小黄脸
|
||||
normal2 = 2, // 新小黄脸, 从faceIndex 222开始?
|
||||
dice = 3 // 骰子
|
||||
}
|
||||
export enum FaceIndex {
|
||||
dice = 358,
|
||||
RPS = 359 // 石头剪刀布
|
||||
}
|
||||
export interface FaceElement {
|
||||
faceIndex: number;
|
||||
faceType: FaceType;
|
||||
faceText?: string;
|
||||
packId?: string;
|
||||
stickerId?: string;
|
||||
sourceType?: number;
|
||||
stickerType?: number;
|
||||
resultId?: string;
|
||||
surpriseId?: string;
|
||||
randomType?: number;
|
||||
}
|
||||
|
||||
export interface MarketFaceElement {
|
||||
emojiPackageId: number;
|
||||
faceName: string;
|
||||
emojiId: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export interface VideoElement {
|
||||
filePath: string;
|
||||
fileName: string;
|
||||
videoMd5?: string;
|
||||
thumbMd5?: string
|
||||
fileTime?: number; // second
|
||||
thumbSize?: number; // byte
|
||||
fileFormat?: viedo_type; // 2表示mp4 参考下面条目
|
||||
fileSize?: string; // byte
|
||||
thumbWidth?: number;
|
||||
thumbHeight?: number;
|
||||
busiType?: 0; //
|
||||
subBusiType?: 0; // 未知
|
||||
thumbPath?: Map<number, any>;
|
||||
transferStatus?: 0; // 未知
|
||||
progress?: 0; // 下载进度?
|
||||
invalidState?: 0; // 未知
|
||||
fileUuid?: string; // 可以用于下载链接?
|
||||
fileSubId?: string;
|
||||
fileBizId?: null;
|
||||
originVideoMd5?: string;
|
||||
import_rich_media_context?: null;
|
||||
sourceVideoCodecFormat?: number;
|
||||
}
|
||||
// export enum busiType{
|
||||
// public static final int CREATOR_SHARE_ADV_XWORLD = 21;
|
||||
// public static final int MINI_APP_MINI_GAME = 11;
|
||||
// public static final int OFFICIAL_ACCOUNT_ADV = 4;
|
||||
// public static final int OFFICIAL_ACCOUNT_ADV_GAME = 8;
|
||||
// public static final int OFFICIAL_ACCOUNT_ADV_SHOP = 9;
|
||||
// public static final int OFFICIAL_ACCOUNT_ADV_VIP = 7;
|
||||
// public static final int OFFICIAL_ACCOUNT_LAYER_MASK_ADV = 14;
|
||||
// public static final int OFFICIAL_ACCOUNT_SPORT = 13;
|
||||
// public static final int OFFICIAL_ACCOUNT_TIAN_QI = 10;
|
||||
// public static final int PC_QQTAB_ADV = 18;
|
||||
// public static final int QIQIAOBAN_SDK = 15;
|
||||
// public static final int QQ_CPS = 16;
|
||||
// public static final int QQ_WALLET_CPS = 17;
|
||||
// public static final int QZONE_FEEDS = 0;
|
||||
// public static final int QZONE_PHOTO_TAIL = 2;
|
||||
// public static final int QZONE_VIDEO_LAYER = 1;
|
||||
// public static final int REWARD_GIFT_ADV = 6;
|
||||
// public static final int REWARD_GROUPGIFT_ADV = 12;
|
||||
// public static final int REWARD_PERSONAL_ADV = 5;
|
||||
// public static final int WEISEE_OFFICIAL_ACCOUNT = 3;
|
||||
// public static final int X_WORLD_CREATOR_ADV = 20;
|
||||
// public static final int X_WORLD_QZONE_LAYER = 22;
|
||||
// public static final int X_WORLD_VIDEO_ADV = 19;
|
||||
|
||||
// }
|
||||
// export enum CategoryBusiType {
|
||||
// _KCateBusiTypeDefault = 0,
|
||||
// _kCateBusiTypeFaceCluster = 1,
|
||||
// _kCateBusiTypeLabelCluster = 4,
|
||||
// _kCateBusiTypeMonthCluster = 16,
|
||||
// _kCateBusiTypePoiCluster = 2,
|
||||
// _kCateBusiTypeYearCluster = 8,
|
||||
// }
|
||||
export enum viedo_type {
|
||||
VIDEO_FORMAT_AFS = 7,
|
||||
VIDEO_FORMAT_AVI = 1,
|
||||
VIDEO_FORMAT_MKV = 4,
|
||||
VIDEO_FORMAT_MOD = 9,
|
||||
VIDEO_FORMAT_MOV = 8,
|
||||
VIDEO_FORMAT_MP4 = 2,
|
||||
VIDEO_FORMAT_MTS = 11,
|
||||
VIDEO_FORMAT_RM = 6,
|
||||
VIDEO_FORMAT_RMVB = 5,
|
||||
VIDEO_FORMAT_TS = 10,
|
||||
VIDEO_FORMAT_WMV = 3,
|
||||
}
|
||||
export interface MarkdownElement {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface InlineKeyboardElementRowButton {
|
||||
id: string;
|
||||
label: string;
|
||||
visitedLabel: string;
|
||||
style: 1; // 未知
|
||||
type: 2; // 未知
|
||||
clickLimit: 0; // 未知
|
||||
unsupportTips: string;
|
||||
data: string;
|
||||
atBotShowChannelList: boolean;
|
||||
permissionType: number;
|
||||
specifyRoleIds: [];
|
||||
specifyTinyids: [];
|
||||
isReply: false;
|
||||
anchor: 0;
|
||||
enter: false;
|
||||
subscribeDataTemplateIds: []
|
||||
}
|
||||
|
||||
export interface InlineKeyboardElement {
|
||||
rows: [{
|
||||
buttons: InlineKeyboardElementRowButton[]
|
||||
}];
|
||||
}
|
||||
|
||||
export interface TipAioOpGrayTipElement { // 这是什么提示来着?
|
||||
operateType: number;
|
||||
peerUid: string;
|
||||
fromGrpCodeOfTmpChat: string;
|
||||
}
|
||||
|
||||
export enum TipGroupElementType {
|
||||
memberIncrease = 1,
|
||||
kicked = 3, // 被移出群
|
||||
ban = 8
|
||||
}
|
||||
// public final class MemberAddShowType {
|
||||
// public static final int KOTHERADD = 0;
|
||||
// public static final int KOTHERADDBYOTHERQRCODE = 2;
|
||||
// public static final int KOTHERADDBYYOURQRCODE = 3;
|
||||
// public static final int KOTHERINVITEOTHER = 5;
|
||||
// public static final int KOTHERINVITEYOU = 6;
|
||||
// public static final int KYOUADD = 1;
|
||||
// public static final int KYOUADDBYOTHERQRCODE = 4;
|
||||
// public static final int KYOUALREADYMEMBER = 8;
|
||||
// public static final int KYOUINVITEOTHER = 7;
|
||||
// }
|
||||
export interface TipGroupElement {
|
||||
type: TipGroupElementType; // 1是表示有人加入群; 自己加入群也会收到这个
|
||||
role: 0; // 暂时不知
|
||||
groupName: string; // 暂时获取不到
|
||||
memberUid: string;
|
||||
memberNick: string;
|
||||
memberRemark: string;
|
||||
adminUid: string;
|
||||
adminNick: string;
|
||||
adminRemark: string;
|
||||
createGroup: null;
|
||||
memberAdd?: {
|
||||
showType: 1;
|
||||
otherAdd: null;
|
||||
otherAddByOtherQRCode: null;
|
||||
otherAddByYourQRCode: null;
|
||||
youAddByOtherQRCode: null;
|
||||
otherInviteOther: null;
|
||||
otherInviteYou: null;
|
||||
youInviteOther: null
|
||||
};
|
||||
shutUp?: {
|
||||
curTime: string;
|
||||
duration: string; // 禁言时间,秒
|
||||
admin: {
|
||||
uid: string;
|
||||
card: string;
|
||||
name: string;
|
||||
role: GroupMemberRole
|
||||
};
|
||||
member: {
|
||||
uid: string
|
||||
card: string;
|
||||
name: string;
|
||||
role: GroupMemberRole
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface MultiForwardMsgElement {
|
||||
xmlContent: string; // xml格式的消息内容
|
||||
resId: string;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export interface RawMessage {
|
||||
parentMsgPeer: Peer;
|
||||
parentMsgIdList:string[];
|
||||
id?: number;//扩展字段 用于处理OB11 ID
|
||||
guildId: string;
|
||||
msgRandom: string;
|
||||
|
||||
|
||||
msgId: string;
|
||||
|
||||
// 时间戳,秒
|
||||
msgTime: string;
|
||||
|
||||
msgSeq: string;
|
||||
msgType: number;
|
||||
subMsgType: number;
|
||||
senderUid: string;
|
||||
senderUin: string; // 发送者QQ号
|
||||
peerUid: string; // 群号 或者 QQ uid
|
||||
peerUin: string; // 群号 或者 发送者QQ号
|
||||
sendNickName: string;
|
||||
sendMemberName?: string; // 发送者群名片
|
||||
chatType: ChatType;
|
||||
sendStatus?: number; // 消息状态,别人发的2是已撤回,自己发的2是已发送
|
||||
recallTime: string; // 撤回时间, "0"是没有撤回
|
||||
records: RawMessage[];
|
||||
elements: {
|
||||
elementId: string;
|
||||
elementType: ElementType;
|
||||
replyElement: {
|
||||
sourceMsgIdInRecords: string;
|
||||
senderUid: string; // 原消息发送者QQ号
|
||||
sourceMsgIsIncPic: boolean; // 原消息是否有图片
|
||||
sourceMsgText: string;
|
||||
replayMsgSeq: string; // 源消息的msgSeq,可以通过这个找到源消息的msgId
|
||||
};
|
||||
textElement: {
|
||||
atType: AtType;
|
||||
atUid: string; // QQ号
|
||||
content: string;
|
||||
atNtUid: string; // uid号
|
||||
};
|
||||
picElement: PicElement;
|
||||
pttElement: PttElement;
|
||||
arkElement: ArkElement;
|
||||
grayTipElement: GrayTipElement;
|
||||
faceElement: FaceElement;
|
||||
videoElement: VideoElement;
|
||||
fileElement: FileElement;
|
||||
marketFaceElement: MarketFaceElement;
|
||||
inlineKeyboardElement: InlineKeyboardElement;
|
||||
markdownElement: MarkdownElement;
|
||||
multiForwardMsgElement: MultiForwardMsgElement;
|
||||
}[];
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
export enum GroupNotifyTypes {
|
||||
INVITE_ME = 1,
|
||||
INVITED_JOIN = 4, // 有人接受了邀请入群
|
||||
JOIN_REQUEST = 7,
|
||||
ADMIN_SET = 8,
|
||||
KICK_MEMBER = 9,
|
||||
MEMBER_EXIT = 11, // 主动退出
|
||||
ADMIN_UNSET = 12,
|
||||
ADMIN_UNSET_OTHER = 13, // 其他人取消管理员
|
||||
}
|
||||
|
||||
export interface GroupNotifies {
|
||||
doubt: boolean;
|
||||
nextStartSeq: string;
|
||||
notifies: GroupNotify[];
|
||||
}
|
||||
|
||||
export enum GroupNotifyStatus {
|
||||
IGNORE = 0,
|
||||
WAIT_HANDLE = 1,
|
||||
APPROVE = 2,
|
||||
REJECT = 3
|
||||
}
|
||||
|
||||
export interface GroupNotify {
|
||||
time: number; // 自己添加的字段,时间戳,毫秒, 用于判断收到短时间内收到重复的notify
|
||||
seq: string; // 唯一标识符,转成数字再除以1000应该就是时间戳?
|
||||
type: GroupNotifyTypes;
|
||||
status: GroupNotifyStatus; // 0是已忽略?,1是未处理,2是已同意
|
||||
group: { groupCode: string; groupName: string };
|
||||
user1: { uid: string; nickName: string }; // 被设置管理员的人
|
||||
user2: { uid: string; nickName: string }; // 操作者
|
||||
actionUser: { uid: string; nickName: string }; //未知
|
||||
actionTime: string;
|
||||
invitationExt: {
|
||||
srcType: number; // 0?未知
|
||||
groupCode: string; waitStatus: number
|
||||
};
|
||||
postscript: string; // 加群用户填写的验证信息
|
||||
repeatSeqs: [];
|
||||
warningTips: string
|
||||
}
|
||||
|
||||
export enum GroupRequestOperateTypes {
|
||||
approve = 1,
|
||||
reject = 2
|
||||
}
|
||||
export enum BuddyReqType {
|
||||
KMEINITIATOR,
|
||||
KPEERINITIATOR,
|
||||
KMEAGREED,
|
||||
KMEAGREEDANDADDED,
|
||||
KPEERAGREED,
|
||||
KPEERAGREEDANDADDED,
|
||||
KPEERREFUSED,
|
||||
KMEREFUSED,
|
||||
KMEIGNORED,
|
||||
KMEAGREEANYONE,
|
||||
KMESETQUESTION,
|
||||
KMEAGREEANDADDFAILED,
|
||||
KMSGINFO,
|
||||
KMEINITIATORWAITPEERCONFIRM
|
||||
}
|
||||
export interface FriendRequest {
|
||||
isInitiator?: boolean;
|
||||
isDecide: boolean;
|
||||
friendUid: string;
|
||||
reqType: BuddyReqType,
|
||||
reqTime: string; // 时间戳;秒
|
||||
extWords: string; // 申请人填写的验证消息
|
||||
isUnread: boolean;
|
||||
friendNick: string;
|
||||
sourceId: number;
|
||||
groupCode: string
|
||||
}
|
||||
|
||||
export interface FriendRequestNotify {
|
||||
unreadNums: number;
|
||||
buddyReqs: FriendRequest[];
|
||||
}
|
||||
export enum MemberExtSourceType {
|
||||
DEFAULTTYPE = 0,
|
||||
TITLETYPE = 1,
|
||||
NEWGROUPTYPE = 2,
|
||||
}
|
||||
export interface GroupExtParam {
|
||||
groupCode: string
|
||||
seq: string
|
||||
beginUin: string
|
||||
dataTime: string
|
||||
uinList: Array<string>
|
||||
uinNum: string
|
||||
groupType: string
|
||||
richCardNameVer: string
|
||||
sourceType: MemberExtSourceType
|
||||
memberExtFilter: {
|
||||
memberLevelInfoUin: number
|
||||
memberLevelInfoPoint: number
|
||||
memberLevelInfoActiveDay: number
|
||||
memberLevelInfoLevel: number
|
||||
memberLevelInfoName: number
|
||||
levelName: number
|
||||
dataTime: number
|
||||
userShowFlag: number
|
||||
sysShowFlag: number
|
||||
timeToUpdate: number
|
||||
nickName: number
|
||||
specialTitle: number
|
||||
levelNameNew: number
|
||||
userShowFlagNew: number
|
||||
msgNeedField: number
|
||||
cmdUinFlagExt3Grocery: number
|
||||
memberIcon: number
|
||||
memberInfoSeq: number
|
||||
}
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
export enum Sex {
|
||||
male = 1,
|
||||
female = 2,
|
||||
unknown = 255,
|
||||
}
|
||||
export interface BuddyCategoryType {
|
||||
categoryId: number;
|
||||
categroyName: string;
|
||||
categroyMbCount: number;
|
||||
buddyList: User[];
|
||||
}
|
||||
export interface CoreInfo {
|
||||
uid: string;
|
||||
uin: string;
|
||||
nick: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface BaseInfo {
|
||||
qid: string;
|
||||
longNick: string;
|
||||
birthday_year: number;
|
||||
birthday_month: number;
|
||||
birthday_day: number;
|
||||
age: number;
|
||||
sex: number;
|
||||
eMail: string;
|
||||
phoneNum: string;
|
||||
categoryId: number;
|
||||
richTime: number;
|
||||
richBuffer: string;
|
||||
}
|
||||
|
||||
interface MusicInfo {
|
||||
buf: string;
|
||||
}
|
||||
|
||||
interface VideoBizInfo {
|
||||
cid: string;
|
||||
tvUrl: string;
|
||||
synchType: string;
|
||||
}
|
||||
|
||||
interface VideoInfo {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ExtOnlineBusinessInfo {
|
||||
buf: string;
|
||||
customStatus: any;
|
||||
videoBizInfo: VideoBizInfo;
|
||||
videoInfo: VideoInfo;
|
||||
}
|
||||
|
||||
interface ExtBuffer {
|
||||
buf: string;
|
||||
}
|
||||
|
||||
interface UserStatus {
|
||||
uid: string;
|
||||
uin: string;
|
||||
status: number;
|
||||
extStatus: number;
|
||||
batteryStatus: number;
|
||||
termType: number;
|
||||
netType: number;
|
||||
iconType: number;
|
||||
customStatus: any;
|
||||
setTime: string;
|
||||
specialFlag: number;
|
||||
abiFlag: number;
|
||||
eNetworkType: number;
|
||||
showName: string;
|
||||
termDesc: string;
|
||||
musicInfo: MusicInfo;
|
||||
extOnlineBusinessInfo: ExtOnlineBusinessInfo;
|
||||
extBuffer: ExtBuffer;
|
||||
}
|
||||
|
||||
interface PrivilegeIcon {
|
||||
jumpUrl: string;
|
||||
openIconList: any[];
|
||||
closeIconList: any[];
|
||||
}
|
||||
|
||||
interface VasInfo {
|
||||
vipFlag: boolean;
|
||||
yearVipFlag: boolean;
|
||||
svipFlag: boolean;
|
||||
vipLevel: number;
|
||||
bigClub: boolean;
|
||||
bigClubLevel: number;
|
||||
nameplateVipType: number;
|
||||
grayNameplateFlag: number;
|
||||
superVipTemplateId: number;
|
||||
diyFontId: number;
|
||||
pendantId: number;
|
||||
pendantDiyId: number;
|
||||
faceId: number;
|
||||
vipFont: number;
|
||||
vipFontType: number;
|
||||
magicFont: number;
|
||||
fontEffect: number;
|
||||
newLoverDiamondFlag: number;
|
||||
extendNameplateId: number;
|
||||
diyNameplateIDs: any[];
|
||||
vipStartFlag: number;
|
||||
vipDataFlag: number;
|
||||
gameNameplateId: string;
|
||||
gameLastLoginTime: string;
|
||||
gameRank: number;
|
||||
gameIconShowFlag: boolean;
|
||||
gameCardId: string;
|
||||
vipNameColorId: string;
|
||||
privilegeIcon: PrivilegeIcon;
|
||||
}
|
||||
|
||||
interface RelationFlags {
|
||||
topTime: string;
|
||||
isBlock: boolean;
|
||||
isMsgDisturb: boolean;
|
||||
isSpecialCareOpen: boolean;
|
||||
isSpecialCareZone: boolean;
|
||||
ringId: string;
|
||||
isBlocked: boolean;
|
||||
recommendImgFlag: number;
|
||||
disableEmojiShortCuts: number;
|
||||
qidianMasterFlag: number;
|
||||
qidianCrewFlag: number;
|
||||
qidianCrewFlag2: number;
|
||||
isHideQQLevel: number;
|
||||
isHidePrivilegeIcon: number;
|
||||
}
|
||||
|
||||
|
||||
interface CommonExt {
|
||||
constellation: number;
|
||||
shengXiao: number;
|
||||
kBloodType: number;
|
||||
homeTown: string;
|
||||
makeFriendCareer: number;
|
||||
pos: string;
|
||||
college: string;
|
||||
country: string;
|
||||
province: string;
|
||||
city: string;
|
||||
postCode: string;
|
||||
address: string;
|
||||
regTime: number;
|
||||
interest: string;
|
||||
labels: any[];
|
||||
qqLevel: QQLevel;
|
||||
}
|
||||
|
||||
interface Pic {
|
||||
picId: string;
|
||||
picTime: number;
|
||||
picUrlMap: Record<string, string>;
|
||||
}
|
||||
|
||||
interface PhotoWall {
|
||||
picList: Pic[];
|
||||
}
|
||||
|
||||
export interface SimpleInfo {
|
||||
uid?: string;
|
||||
uin?: string;
|
||||
coreInfo: CoreInfo;
|
||||
baseInfo: BaseInfo;
|
||||
status: UserStatus | null;
|
||||
vasInfo: VasInfo | null;
|
||||
relationFlags: RelationFlags | null;
|
||||
otherFlags: any | null;
|
||||
intimate: any | null;
|
||||
}
|
||||
export interface FriendV2 extends SimpleInfo {
|
||||
categoryId?: number;
|
||||
categroyName?: string;
|
||||
}
|
||||
export interface UserDetailInfoListenerArg {
|
||||
uid: string;
|
||||
uin: string;
|
||||
simpleInfo: SimpleInfo;
|
||||
commonExt: CommonExt;
|
||||
photoWall: PhotoWall;
|
||||
}
|
||||
export interface ModifyProfileParams {
|
||||
nick: string,
|
||||
longNick: string,
|
||||
sex: Sex,
|
||||
birthday: { birthday_year: string, birthday_month: string, birthday_day: string },
|
||||
location: any//undefined
|
||||
}
|
||||
|
||||
export interface BuddyProfileLikeReq {
|
||||
friendUids: string[];
|
||||
basic: number;
|
||||
vote: number;
|
||||
favorite: number;
|
||||
userProfile: number;
|
||||
type: number;
|
||||
start: number;
|
||||
limit: number;
|
||||
}
|
||||
export interface QQLevel {
|
||||
crownNum: number;
|
||||
sunNum: number;
|
||||
moonNum: number;
|
||||
starNum: number
|
||||
}
|
||||
export interface User {
|
||||
uid: string; // 加密的字符串
|
||||
uin: string; // QQ号
|
||||
nick: string;
|
||||
avatarUrl?: string;
|
||||
longNick?: string; // 签名
|
||||
remark?: string;
|
||||
sex?: Sex;
|
||||
qqLevel?: QQLevel;
|
||||
qid?: string
|
||||
birthday_year?: number;
|
||||
birthday_month?: number;
|
||||
birthday_day?: number;
|
||||
topTime?: string;
|
||||
constellation?: number;
|
||||
shengXiao?: number;
|
||||
kBloodType?: number;
|
||||
homeTown?: string; //"0-0-0";
|
||||
makeFriendCareer?: number;
|
||||
pos?: string;
|
||||
eMail?: string
|
||||
phoneNum?: string;
|
||||
college?: string;
|
||||
country?: string;
|
||||
province?: string;
|
||||
city?: string;
|
||||
postCode?: string;
|
||||
address?: string;
|
||||
isBlock?: boolean;
|
||||
isSpecialCareOpen?: boolean;
|
||||
isSpecialCareZone?: boolean;
|
||||
ringId?: string;
|
||||
regTime?: number;
|
||||
interest?: string;
|
||||
labels?: string[];
|
||||
isHideQQLevel?: number;
|
||||
privilegeIcon?: {
|
||||
jumpUrl: string;
|
||||
openIconList: unknown[];
|
||||
closeIconList: unknown[]
|
||||
};
|
||||
photoWall?: {
|
||||
picList: unknown[]
|
||||
};
|
||||
vipFlag?: boolean;
|
||||
yearVipFlag?: boolean;
|
||||
svipFlag?: boolean;
|
||||
vipLevel?: number;
|
||||
status?: number;
|
||||
qidianMasterFlag?: number;
|
||||
qidianCrewFlag?: number;
|
||||
qidianCrewFlag2?: number;
|
||||
extStatus?: number;
|
||||
recommendImgFlag?: number;
|
||||
disableEmojiShortCuts?: number;
|
||||
pendantId?: string;
|
||||
}
|
||||
|
||||
export interface SelfInfo extends User {
|
||||
online?: boolean;
|
||||
}
|
||||
|
||||
export interface Friend extends User { }
|
||||
|
||||
export enum BizKey {
|
||||
KPRIVILEGEICON,
|
||||
KPHOTOWALL
|
||||
}
|
||||
export interface UserDetailInfoByUinV2 {
|
||||
result: number,
|
||||
errMsg: string,
|
||||
detail: {
|
||||
uid: string,
|
||||
uin: string,
|
||||
simpleInfo: SimpleInfo,
|
||||
commonExt: CommonExt,
|
||||
photoWall: null
|
||||
}
|
||||
}
|
||||
export interface UserDetailInfoByUin {
|
||||
result: number,
|
||||
errMsg: string,
|
||||
info: {
|
||||
uid: string,//这个没办法用
|
||||
qid: string,
|
||||
uin: string,
|
||||
nick: string,
|
||||
remark: string,
|
||||
longNick: string,
|
||||
avatarUrl: string,
|
||||
birthday_year: number,
|
||||
birthday_month: number,
|
||||
birthday_day: number,
|
||||
sex: number,//0
|
||||
topTime: string,
|
||||
constellation: number,
|
||||
shengXiao: number,
|
||||
kBloodType: number,
|
||||
homeTown: string,
|
||||
makeFriendCareer: number,
|
||||
pos: string,
|
||||
eMail: string,
|
||||
phoneNum: string,
|
||||
college: string,
|
||||
country: string,
|
||||
province: string,
|
||||
city: string,
|
||||
postCode: string,
|
||||
address: string,
|
||||
isBlock: boolean,
|
||||
isSpecialCareOpen: boolean,
|
||||
isSpecialCareZone: boolean,
|
||||
ringId: string,
|
||||
regTime: number,
|
||||
interest: string,
|
||||
termType: number,
|
||||
labels: any[],
|
||||
qqLevel: { crownNum: number, sunNum: number, moonNum: number, starNum: number },
|
||||
isHideQQLevel: number,
|
||||
privilegeIcon: { jumpUrl: string, openIconList: any[], closeIconList: any[] },
|
||||
isHidePrivilegeIcon: number,
|
||||
photoWall: { picList: any[] },
|
||||
vipFlag: boolean,
|
||||
yearVipFlag: boolean,
|
||||
svipFlag: boolean,
|
||||
vipLevel: number,
|
||||
status: number,
|
||||
qidianMasterFlag: number,
|
||||
qidianCrewFlag: number,
|
||||
qidianCrewFlag2: number,
|
||||
extStatus: number,
|
||||
recommendImgFlag: number,
|
||||
disableEmojiShortCuts: number,
|
||||
pendantId: string,
|
||||
vipNameColorId: string
|
||||
}
|
||||
}
|
||||
50
src/core/src/external/appid.json
vendored
50
src/core/src/external/appid.json
vendored
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"3.1.2-13107": {
|
||||
"appid": 537146866,
|
||||
"qua": "V1_LNX_NQ_3.1.2-13107_RDM_B"
|
||||
},
|
||||
"3.2.10-25765": {
|
||||
"appid": 537234773,
|
||||
"qua": "V1_LNX_NQ_3.2.10_25765_GW_B"
|
||||
},
|
||||
"3.2.12-26702": {
|
||||
"appid": 537237950,
|
||||
"qua": "V1_LNX_NQ_3.2.12_26702_GW_B"
|
||||
},
|
||||
"3.2.12-26740": {
|
||||
"appid": 537237950,
|
||||
"qua": "V1_WIN_NQ_9.9.15_26740_GW_B"
|
||||
},
|
||||
"9.9.11-24815": {
|
||||
"appid": 537226656,
|
||||
"qua": "V1_WIN_NQ_9.9.11_24815_GW_B"
|
||||
},
|
||||
"9.9.12-25493": {
|
||||
"appid": 537231759,
|
||||
"qua": "V1_WIN_NQ_9.9.12_25493_GW_B"
|
||||
},
|
||||
"9.9.12-25765": {
|
||||
"appid": 537234702,
|
||||
"qua": "V1_WIN_NQ_9.9.12_25765_GW_B"
|
||||
},
|
||||
"9.9.12-26299": {
|
||||
"appid": 537234826,
|
||||
"qua": "V1_WIN_NQ_9.9.12_26299_GW_B"
|
||||
},
|
||||
"9.9.12-26339": {
|
||||
"appid": 537234826,
|
||||
"qua": "V1_WIN_NQ_9.9.12_26339_GW_B"
|
||||
},
|
||||
"9.9.12-26466": {
|
||||
"appid": 537234826,
|
||||
"qua": "V1_WIN_NQ_9.9.12_26466_GW_B"
|
||||
},
|
||||
"9.9.15-26702": {
|
||||
"appid": 537237765,
|
||||
"qua": "V1_WIN_NQ_9.9.15_26702_GW_B"
|
||||
},
|
||||
"9.9.15-26740": {
|
||||
"appid": 537237765,
|
||||
"qua": "V1_WIN_NQ_9.9.15_26702_GW_B"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import QQWrapper from './wrapper';
|
||||
|
||||
export * from './adapters';
|
||||
export * from './apis';
|
||||
export * from './entities';
|
||||
export * from './listeners';
|
||||
export * from './services';
|
||||
|
||||
export * as Adapters from './adapters';
|
||||
export * as APIs from './apis';
|
||||
export * as Entities from './entities';
|
||||
export * as Listeners from './listeners';
|
||||
export * as Services from './services';
|
||||
export { QQWrapper as Wrapper };
|
||||
export * as WrapperInterface from './wrapper';
|
||||
export * as SessionConfig from './sessionConfig';
|
||||
|
||||
export { napCatCore } from './core';
|
||||
@@ -1,102 +0,0 @@
|
||||
import { BuddyCategoryType, FriendRequestNotify } from '@/core/entities';
|
||||
|
||||
export type OnBuddyChangeParams = BuddyCategoryType[]
|
||||
|
||||
interface IBuddyListener {
|
||||
onBuddyListChangedV2(arg: unknown): void,//V2版本 还没兼容
|
||||
|
||||
onBuddyListChange(arg: OnBuddyChangeParams): void,
|
||||
|
||||
onBuddyInfoChange(arg: unknown): void,
|
||||
|
||||
onBuddyDetailInfoChange(arg: unknown): void,
|
||||
|
||||
onNickUpdated(arg: unknown): void,
|
||||
|
||||
onBuddyRemarkUpdated(arg: unknown): void,
|
||||
|
||||
onAvatarUrlUpdated(arg: unknown): void,
|
||||
|
||||
onBuddyReqChange(arg: FriendRequestNotify): void,
|
||||
|
||||
onBuddyReqUnreadCntChange(arg: unknown): void,
|
||||
|
||||
onCheckBuddySettingResult(arg: unknown): void,
|
||||
|
||||
onAddBuddyNeedVerify(arg: unknown): void,
|
||||
|
||||
onSmartInfos(arg: unknown): void,
|
||||
|
||||
onSpacePermissionInfos(arg: unknown): void,
|
||||
|
||||
onDoubtBuddyReqChange(arg: unknown): void,
|
||||
|
||||
onDoubtBuddyReqUnreadNumChange(arg: unknown): void,
|
||||
|
||||
onBlockChanged(arg: unknown): void,
|
||||
|
||||
onAddMeSettingChanged(arg: unknown): void,
|
||||
|
||||
onDelBatchBuddyInfos(arg: unknown): void
|
||||
}
|
||||
|
||||
export interface NodeIKernelBuddyListener extends IBuddyListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IBuddyListener): NodeIKernelBuddyListener;
|
||||
}
|
||||
|
||||
export class BuddyListener implements IBuddyListener {
|
||||
onBuddyListChangedV2(arg: unknown): void {
|
||||
//throw new Error('Method not implemented.');
|
||||
}
|
||||
onAddBuddyNeedVerify(arg: unknown) {
|
||||
}
|
||||
|
||||
onAddMeSettingChanged(arg: unknown) {
|
||||
}
|
||||
|
||||
onAvatarUrlUpdated(arg: unknown) {
|
||||
}
|
||||
|
||||
onBlockChanged(arg: unknown) {
|
||||
}
|
||||
|
||||
onBuddyDetailInfoChange(arg: unknown) {
|
||||
}
|
||||
|
||||
onBuddyInfoChange(arg: unknown) {
|
||||
}
|
||||
|
||||
onBuddyListChange(arg: OnBuddyChangeParams): void {
|
||||
}
|
||||
|
||||
onBuddyRemarkUpdated(arg: unknown): void {
|
||||
}
|
||||
|
||||
onBuddyReqChange(arg: FriendRequestNotify): void {
|
||||
}
|
||||
|
||||
onBuddyReqUnreadCntChange(arg: unknown): void {
|
||||
}
|
||||
|
||||
onCheckBuddySettingResult(arg: unknown): void {
|
||||
}
|
||||
|
||||
onDelBatchBuddyInfos(arg: unknown): void {
|
||||
}
|
||||
|
||||
onDoubtBuddyReqChange(arg: unknown): void {
|
||||
}
|
||||
|
||||
onDoubtBuddyReqUnreadNumChange(arg: unknown): void {
|
||||
}
|
||||
|
||||
onNickUpdated(arg: unknown): void {
|
||||
}
|
||||
|
||||
onSmartInfos(arg: unknown): void {
|
||||
}
|
||||
|
||||
onSpacePermissionInfos(arg: unknown): void {
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
export interface IKernelFileAssistantListener {
|
||||
onFileStatusChanged(...args: unknown[]): unknown;
|
||||
|
||||
onSessionListChanged(...args: unknown[]): unknown;
|
||||
|
||||
onSessionChanged(...args: unknown[]): unknown;
|
||||
|
||||
onFileListChanged(...args: unknown[]): unknown;
|
||||
|
||||
onFileSearch(...args: unknown[]): unknown;
|
||||
}
|
||||
export interface NodeIKernelFileAssistantListener extends IKernelFileAssistantListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IKernelFileAssistantListener): NodeIKernelFileAssistantListener;
|
||||
}
|
||||
|
||||
export class KernelFileAssistantListener implements IKernelFileAssistantListener {
|
||||
onFileStatusChanged(...args: unknown[]) { }
|
||||
|
||||
onSessionListChanged(...args: unknown[]) { }
|
||||
|
||||
onSessionChanged(...args: unknown[]) { }
|
||||
|
||||
onFileListChanged(...args: unknown[]) { }
|
||||
|
||||
onFileSearch(...args: unknown[]) { }
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
import { Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/core/entities';
|
||||
|
||||
interface IGroupListener {
|
||||
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): void;
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]): void;
|
||||
|
||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): void;
|
||||
|
||||
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void;
|
||||
|
||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void;
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]): void;
|
||||
|
||||
onGroupAllInfoChange(...args: unknown[]): void;
|
||||
|
||||
onGroupsMsgMaskResult(...args: unknown[]): void;
|
||||
|
||||
onGroupConfMemberChange(...args: unknown[]): void;
|
||||
|
||||
onGroupBulletinChange(...args: unknown[]): void;
|
||||
|
||||
onGetGroupBulletinListResult(...args: unknown[]): void;
|
||||
|
||||
onMemberListChange(arg: {
|
||||
sceneId: string,
|
||||
ids: string[],
|
||||
infos: Map<string, GroupMember>,
|
||||
finish: boolean,
|
||||
hasRobot: boolean
|
||||
}): void;
|
||||
|
||||
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>): void;
|
||||
|
||||
onSearchMemberChange(...args: unknown[]): void;
|
||||
|
||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void;
|
||||
|
||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void;
|
||||
|
||||
onGroupStatisticInfoChange(...args: unknown[]): void;
|
||||
|
||||
onJoinGroupNotify(...args: unknown[]): void;
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]): void;
|
||||
|
||||
onGroupBulletinRemindNotify(...args: unknown[]): void;
|
||||
|
||||
onGroupFirstBulletinNotify(...args: unknown[]): void;
|
||||
|
||||
onJoinGroupNoVerifyFlag(...args: unknown[]): void;
|
||||
|
||||
onGroupArkInviteStateResult(...args: unknown[]): void;
|
||||
// 发现于Win 9.9.9 23159
|
||||
onGroupMemberLevelInfoChange(...args: unknown[]): void;
|
||||
}
|
||||
|
||||
export interface NodeIKernelGroupListener extends IGroupListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IGroupListener): NodeIKernelGroupListener;
|
||||
}
|
||||
|
||||
export class GroupListener implements IGroupListener {
|
||||
// 发现于Win 9.9.9 23159
|
||||
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
||||
|
||||
}
|
||||
onGetGroupBulletinListResult(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupAllInfoChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinRemindNotify(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupArkInviteStateResult(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupConfMemberChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupFirstBulletinNotify(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]) {
|
||||
}
|
||||
|
||||
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
||||
}
|
||||
|
||||
onGroupsMsgMaskResult(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupStatisticInfoChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onJoinGroupNotify(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
|
||||
}
|
||||
|
||||
onMemberListChange(arg: {
|
||||
sceneId: string,
|
||||
ids: string[],
|
||||
infos: Map<string, GroupMember>, // uid -> GroupMember
|
||||
finish: boolean,
|
||||
hasRobot: boolean
|
||||
}) {
|
||||
}
|
||||
|
||||
onSearchMemberChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]) {
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugGroupListener implements IGroupListener {
|
||||
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
||||
console.log('onGroupMemberLevelInfoChange:', ...args);
|
||||
}
|
||||
onGetGroupBulletinListResult(...args: unknown[]) {
|
||||
console.log('onGetGroupBulletinListResult:', ...args);
|
||||
}
|
||||
|
||||
onGroupAllInfoChange(...args: unknown[]) {
|
||||
console.log('onGroupAllInfoChange:', ...args);
|
||||
}
|
||||
|
||||
onGroupBulletinChange(...args: unknown[]) {
|
||||
console.log('onGroupBulletinChange:', ...args);
|
||||
}
|
||||
|
||||
onGroupBulletinRemindNotify(...args: unknown[]) {
|
||||
console.log('onGroupBulletinRemindNotify:', ...args);
|
||||
}
|
||||
|
||||
onGroupArkInviteStateResult(...args: unknown[]) {
|
||||
console.log('onGroupArkInviteStateResult:', ...args);
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
||||
console.log('onGroupBulletinRichMediaDownloadComplete:', ...args);
|
||||
}
|
||||
|
||||
onGroupConfMemberChange(...args: unknown[]) {
|
||||
console.log('onGroupConfMemberChange:', ...args);
|
||||
}
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]) {
|
||||
console.log('onGroupDetailInfoChange:', ...args);
|
||||
}
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]) {
|
||||
console.log('onGroupExtListUpdate:', ...args);
|
||||
}
|
||||
|
||||
onGroupFirstBulletinNotify(...args: unknown[]) {
|
||||
console.log('onGroupFirstBulletinNotify:', ...args);
|
||||
}
|
||||
|
||||
onGroupListUpdate(...args: unknown[]) {
|
||||
console.log('onGroupListUpdate:', ...args);
|
||||
}
|
||||
|
||||
onGroupNotifiesUpdated(...args: unknown[]) {
|
||||
console.log('onGroupNotifiesUpdated:', ...args);
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
||||
console.log('onGroupBulletinRichMediaProgressUpdate:', ...args);
|
||||
}
|
||||
|
||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
||||
console.log('onGroupNotifiesUnreadCountUpdated:', ...args);
|
||||
}
|
||||
|
||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
||||
console.log('onGroupSingleScreenNotifies:');
|
||||
}
|
||||
|
||||
onGroupsMsgMaskResult(...args: unknown[]) {
|
||||
console.log('onGroupsMsgMaskResult:', ...args);
|
||||
}
|
||||
|
||||
onGroupStatisticInfoChange(...args: unknown[]) {
|
||||
console.log('onGroupStatisticInfoChange:', ...args);
|
||||
}
|
||||
|
||||
onJoinGroupNotify(...args: unknown[]) {
|
||||
console.log('onJoinGroupNotify:', ...args);
|
||||
}
|
||||
|
||||
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
||||
console.log('onJoinGroupNoVerifyFlag:', ...args);
|
||||
}
|
||||
|
||||
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
|
||||
console.log('onMemberInfoChange:', groupCode, changeType, members);
|
||||
}
|
||||
|
||||
onMemberListChange(...args: unknown[]) {
|
||||
console.log('onMemberListChange:', ...args);
|
||||
}
|
||||
|
||||
onSearchMemberChange(...args: unknown[]) {
|
||||
console.log('onSearchMemberChange:', ...args);
|
||||
}
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]) {
|
||||
console.log('onShutUpMemberListChanged:', ...args);
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
export interface IKernelLoginListener {
|
||||
onLoginConnected(...args: any[]): void;
|
||||
|
||||
onLoginDisConnected(...args: any[]): void;
|
||||
|
||||
onLoginConnecting(...args: any[]): void;
|
||||
|
||||
onQRCodeGetPicture(...args: any[]): void;
|
||||
|
||||
onQRCodeLoginPollingStarted(...args: any[]): void;
|
||||
|
||||
onQRCodeSessionUserScaned(...args: any[]): void;
|
||||
|
||||
onQRCodeLoginSucceed(...args: any[]): void;
|
||||
|
||||
onQRCodeSessionFailed(...args: any[]): void;
|
||||
|
||||
onLoginFailed(...args: any[]): void;
|
||||
|
||||
onLogoutSucceed(...args: any[]): void;
|
||||
|
||||
onLogoutFailed(...args: any[]): void;
|
||||
|
||||
onUserLoggedIn(...args: any[]): void;
|
||||
|
||||
onQRCodeSessionQuickLoginFailed(...args: any[]): void;
|
||||
|
||||
onPasswordLoginFailed(...args: any[]): void;
|
||||
|
||||
OnConfirmUnusualDeviceFailed(...args: any[]): void;
|
||||
|
||||
onQQLoginNumLimited(...args: any[]): void;
|
||||
|
||||
onLoginState(...args: any[]): void;
|
||||
}
|
||||
|
||||
export interface NodeIKernelLoginListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IKernelLoginListener): NodeIKernelLoginListener;
|
||||
}
|
||||
|
||||
export class LoginListener implements IKernelLoginListener {
|
||||
onLoginConnected(...args: any[]): void {
|
||||
}
|
||||
|
||||
onLoginDisConnected(...args: any[]): void {
|
||||
}
|
||||
|
||||
onLoginConnecting(...args: any[]): void {
|
||||
}
|
||||
|
||||
onQRCodeGetPicture(arg: { pngBase64QrcodeData: string, qrcodeUrl: string }): void {
|
||||
// let base64Data: string = arg.pngBase64QrcodeData
|
||||
// base64Data = base64Data.split("data:image/png;base64,")[1]
|
||||
// let buffer = Buffer.from(base64Data, 'base64')
|
||||
// console.log("onQRCodeGetPicture", arg);
|
||||
}
|
||||
|
||||
onQRCodeLoginPollingStarted(...args: any[]): void {
|
||||
}
|
||||
|
||||
onQRCodeSessionUserScaned(...args: any[]): void {
|
||||
}
|
||||
|
||||
onQRCodeLoginSucceed(arg: QRCodeLoginSucceedResult): void {
|
||||
}
|
||||
|
||||
onQRCodeSessionFailed(...args: any[]): void {
|
||||
}
|
||||
|
||||
onLoginFailed(...args: any[]): void {
|
||||
}
|
||||
|
||||
onLogoutSucceed(...args: any[]): void {
|
||||
}
|
||||
|
||||
onLogoutFailed(...args: any[]): void {
|
||||
}
|
||||
|
||||
onUserLoggedIn(...args: any[]): void {
|
||||
}
|
||||
|
||||
onQRCodeSessionQuickLoginFailed(...args: any[]): void {
|
||||
}
|
||||
|
||||
onPasswordLoginFailed(...args: any[]): void {
|
||||
}
|
||||
|
||||
OnConfirmUnusualDeviceFailed(...args: any[]): void {
|
||||
}
|
||||
|
||||
onQQLoginNumLimited(...args: any[]): void {
|
||||
}
|
||||
|
||||
onLoginState(...args: any[]): void {
|
||||
}
|
||||
}
|
||||
|
||||
export interface QRCodeLoginSucceedResult {
|
||||
account: string;
|
||||
mainAccount: string;
|
||||
uin: string; //拿UIN
|
||||
uid: string; //拿UID
|
||||
nickName: string; //一般是空的 拿不到
|
||||
gender: number;
|
||||
age: number;
|
||||
faceUrl: string;//一般是空的 拿不到
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
import { ChatType, RawMessage } from '@/core/entities';
|
||||
|
||||
export interface OnRichMediaDownloadCompleteParams {
|
||||
fileModelId: string,
|
||||
msgElementId: string,
|
||||
msgId: string,
|
||||
fileId: string,
|
||||
fileProgress: string, // '0'
|
||||
fileSpeed: string, // '0'
|
||||
fileErrCode: string, // '0'
|
||||
fileErrMsg: string,
|
||||
fileDownType: number, // 暂时未知
|
||||
thumbSize: number,
|
||||
filePath: string,
|
||||
totalSize: string,
|
||||
trasferStatus: number,
|
||||
step: number,
|
||||
commonFileInfo: unknown | null,
|
||||
fileSrvErrCode: string,
|
||||
clientMsg: string,
|
||||
businessId: number,
|
||||
userTotalSpacePerDay: unknown | null,
|
||||
userUsedSpacePerDay: unknown | null
|
||||
}
|
||||
export interface onGroupFileInfoUpdateParamType {
|
||||
retCode: number
|
||||
retMsg: string
|
||||
clientWording: string
|
||||
isEnd: boolean
|
||||
item: Array<any>
|
||||
allFileCount: string
|
||||
nextIndex: string
|
||||
reqId: string
|
||||
}
|
||||
// {
|
||||
// sessionType: 1,
|
||||
// chatType: 100,
|
||||
// peerUid: 'u_PVQ3tl6K78xxxx',
|
||||
// groupCode: '809079648',
|
||||
// fromNick: '拾xxxx,
|
||||
// sig: '0x'
|
||||
// }
|
||||
export interface TempOnRecvParams {
|
||||
sessionType: number,//1
|
||||
chatType: ChatType,//100
|
||||
peerUid: string,//uid
|
||||
groupCode: string,//gc
|
||||
fromNick: string,//gc name
|
||||
sig: string,
|
||||
|
||||
}
|
||||
export interface IKernelMsgListener {
|
||||
onAddSendMsg(msgRecord: RawMessage): void;
|
||||
|
||||
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void;
|
||||
|
||||
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void;
|
||||
|
||||
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void;
|
||||
|
||||
onContactUnreadCntUpdate(hashMap: unknown): void;
|
||||
|
||||
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void;
|
||||
|
||||
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void;
|
||||
|
||||
onEmojiDownloadComplete(emojiNotifyInfo: unknown): void;
|
||||
|
||||
onEmojiResourceUpdate(emojiResourceInfo: unknown): void;
|
||||
|
||||
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
|
||||
|
||||
onFileMsgCome(arrayList: unknown): void;
|
||||
|
||||
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
|
||||
|
||||
onFirstViewGroupGuildMapping(arrayList: unknown): void;
|
||||
|
||||
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void;
|
||||
|
||||
onGroupFileInfoAdd(groupItem: unknown): void;
|
||||
|
||||
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType): void;
|
||||
|
||||
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void;
|
||||
|
||||
onGroupTransferInfoAdd(groupItem: unknown): void;
|
||||
|
||||
onGroupTransferInfoUpdate(groupFileListResult: unknown): void;
|
||||
|
||||
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void;
|
||||
|
||||
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void;
|
||||
|
||||
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void;
|
||||
|
||||
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void;
|
||||
|
||||
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void;
|
||||
|
||||
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void;
|
||||
|
||||
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void;
|
||||
|
||||
onInputStatusPush(inputStatusInfo: unknown): void;
|
||||
|
||||
onKickedOffLine(kickedInfo: unknown): void;
|
||||
|
||||
onLineDev(arrayList: unknown): void;
|
||||
|
||||
onLogLevelChanged(j2: unknown): void;
|
||||
|
||||
onMsgAbstractUpdate(arrayList: unknown): void;
|
||||
|
||||
onMsgBoxChanged(arrayList: unknown): void;
|
||||
|
||||
onMsgDelete(contact: unknown, arrayList: unknown): void;
|
||||
|
||||
onMsgEventListUpdate(hashMap: unknown): void;
|
||||
|
||||
onMsgInfoListAdd(arrayList: unknown): void;
|
||||
|
||||
onMsgInfoListUpdate(msgList: RawMessage[]): void;
|
||||
|
||||
onMsgQRCodeStatusChanged(i2: unknown): void;
|
||||
|
||||
onMsgRecall(i2: unknown, str: unknown, j2: unknown): void;
|
||||
|
||||
onMsgSecurityNotify(msgRecord: unknown): void;
|
||||
|
||||
onMsgSettingUpdate(msgSetting: unknown): void;
|
||||
|
||||
onNtFirstViewMsgSyncEnd(): void;
|
||||
|
||||
onNtMsgSyncEnd(): void;
|
||||
|
||||
onNtMsgSyncStart(): void;
|
||||
|
||||
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
|
||||
|
||||
onRecvGroupGuildFlag(i2: unknown): void;
|
||||
|
||||
onRecvMsg(...arrayList: unknown[]): void;
|
||||
|
||||
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void;
|
||||
|
||||
onRecvOnlineFileMsg(arrayList: unknown): void;
|
||||
|
||||
onRecvS2CMsg(arrayList: unknown): void;
|
||||
|
||||
onRecvSysMsg(arrayList: unknown): void;
|
||||
|
||||
onRecvUDCFlag(i2: unknown): void;
|
||||
|
||||
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void;
|
||||
|
||||
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void;
|
||||
|
||||
onRichMediaUploadComplete(fileTransNotifyInfo: unknown): void;
|
||||
|
||||
onSearchGroupFileInfoUpdate(searchGroupFileResult:
|
||||
{
|
||||
result: {
|
||||
retCode: number,
|
||||
retMsg: string,
|
||||
clientWording: string
|
||||
},
|
||||
syncCookie: string,
|
||||
totalMatchCount: number,
|
||||
ownerMatchCount: number,
|
||||
isEnd: boolean,
|
||||
reqId: number,
|
||||
item: Array<{
|
||||
groupCode: string,
|
||||
groupName: string,
|
||||
uploaderUin: string,
|
||||
uploaderName: string,
|
||||
matchUin: string,
|
||||
matchWords: Array<unknown>,
|
||||
fileNameHits: Array<{
|
||||
start: number,
|
||||
end: number
|
||||
}>,
|
||||
fileModelId: string,
|
||||
fileId: string,
|
||||
fileName: string,
|
||||
fileSize: string,
|
||||
busId: number,
|
||||
uploadTime: number,
|
||||
modifyTime: number,
|
||||
deadTime: number,
|
||||
downloadTimes: number,
|
||||
localPath: string
|
||||
}>
|
||||
}): void;
|
||||
|
||||
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void;
|
||||
|
||||
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void;
|
||||
|
||||
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): void;
|
||||
|
||||
onUnreadCntAfterFirstView(hashMap: unknown): void;
|
||||
|
||||
onUnreadCntUpdate(hashMap: unknown): void;
|
||||
|
||||
onUserChannelTabStatusChanged(z: unknown): void;
|
||||
|
||||
onUserOnlineStatusChanged(z: unknown): void;
|
||||
|
||||
onUserTabStatusChanged(arrayList: unknown): void;
|
||||
|
||||
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
|
||||
|
||||
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
|
||||
|
||||
// 第一次发现于Linux
|
||||
onUserSecQualityChanged(...args: unknown[]): void;
|
||||
|
||||
onMsgWithRichLinkInfoUpdate(...args: unknown[]): void;
|
||||
|
||||
onRedTouchChanged(...args: unknown[]): void;
|
||||
|
||||
// 第一次发现于Win 9.9.9 23159
|
||||
onBroadcastHelperProgerssUpdate(...args: unknown[]): void;
|
||||
|
||||
}
|
||||
|
||||
export interface NodeIKernelMsgListener extends IKernelMsgListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IKernelMsgListener): NodeIKernelMsgListener;
|
||||
}
|
||||
|
||||
|
||||
export class MsgListener implements IKernelMsgListener {
|
||||
onAddSendMsg(msgRecord: RawMessage) {
|
||||
|
||||
}
|
||||
|
||||
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onContactUnreadCntUpdate(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onEmojiDownloadComplete(emojiNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onEmojiResourceUpdate(emojiResourceInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFileMsgCome(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFirstViewGroupGuildMapping(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGroupFileInfoAdd(groupItem: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType) {
|
||||
|
||||
}
|
||||
|
||||
onGroupGuildUpdate(groupGuildNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
onGroupTransferInfoAdd(groupItem: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGroupTransferInfoUpdate(groupFileListResult: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onInputStatusPush(inputStatusInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onKickedOffLine(kickedInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onLineDev(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onLogLevelChanged(j2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgAbstractUpdate(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgBoxChanged(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgDelete(contact: unknown, arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgEventListUpdate(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgInfoListAdd(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgInfoListUpdate(msgList: RawMessage[]) {
|
||||
|
||||
}
|
||||
|
||||
onMsgQRCodeStatusChanged(i2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgRecall(i2: unknown, str: unknown, j2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgSecurityNotify(msgRecord: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgSettingUpdate(msgSetting: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onNtFirstViewMsgSyncEnd() {
|
||||
|
||||
}
|
||||
|
||||
onNtMsgSyncEnd() {
|
||||
|
||||
}
|
||||
|
||||
onNtMsgSyncStart() {
|
||||
|
||||
}
|
||||
|
||||
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvGroupGuildFlag(i2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvMsg(arrayList: RawMessage[]) {
|
||||
|
||||
}
|
||||
|
||||
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvOnlineFileMsg(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvS2CMsg(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvSysMsg(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvUDCFlag(i2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) {
|
||||
}
|
||||
|
||||
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRichMediaUploadComplete(fileTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams) {
|
||||
|
||||
}
|
||||
|
||||
onUnreadCntAfterFirstView(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUnreadCntUpdate(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserChannelTabStatusChanged(z: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserOnlineStatusChanged(z: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserTabStatusChanged(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
||||
|
||||
}
|
||||
|
||||
// 第一次发现于Linux
|
||||
onUserSecQualityChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onMsgWithRichLinkInfoUpdate(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onRedTouchChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
// 第一次发现于Win 9.9.9-23159
|
||||
onBroadcastHelperProgerssUpdate(...args: unknown[]) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { User, UserDetailInfoListenerArg } from '@/core/entities';
|
||||
|
||||
interface IProfileListener {
|
||||
onProfileSimpleChanged(...args: unknown[]): void;
|
||||
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void;
|
||||
onProfileDetailInfoChanged(profile: User): void;
|
||||
|
||||
onStatusUpdate(...args: unknown[]): void;
|
||||
|
||||
onSelfStatusChanged(...args: unknown[]): void;
|
||||
|
||||
onStrangerRemarkChanged(...args: unknown[]): void;
|
||||
}
|
||||
|
||||
export interface NodeIKernelProfileListener extends IProfileListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IProfileListener): NodeIKernelProfileListener;
|
||||
}
|
||||
|
||||
export class ProfileListener implements IProfileListener {
|
||||
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void {
|
||||
|
||||
}
|
||||
onProfileSimpleChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onProfileDetailInfoChanged(profile: User) {
|
||||
|
||||
}
|
||||
|
||||
onStatusUpdate(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onSelfStatusChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onStrangerRemarkChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
interface IKernelRecentContactListener {
|
||||
onDeletedContactsNotify(...args: unknown[]): unknown;
|
||||
|
||||
onRecentContactNotification(...args: unknown[]): unknown;
|
||||
|
||||
onMsgUnreadCountUpdate(...args: unknown[]): unknown;
|
||||
|
||||
onGuildDisplayRecentContactListChanged(...args: unknown[]): unknown;
|
||||
|
||||
onRecentContactListChanged(...args: unknown[]): unknown;
|
||||
|
||||
onRecentContactListChangedVer2(...args: unknown[]): unknown;
|
||||
}
|
||||
|
||||
export interface NodeIKernelRecentContactListener extends IKernelRecentContactListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IKernelRecentContactListener): NodeIKernelRecentContactListener;
|
||||
}
|
||||
|
||||
export class KernelRecentContactListener implements IKernelRecentContactListener {
|
||||
onDeletedContactsNotify(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onRecentContactNotification(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onMsgUnreadCountUpdate(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onGuildDisplayRecentContactListChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onRecentContactListChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onRecentContactListChangedVer2(...args: unknown[]) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
|
||||
export interface IKernelRobotListener {
|
||||
onRobotFriendListChanged(...args: unknown[]): void;
|
||||
|
||||
onRobotListChanged(...args: unknown[]): void;
|
||||
|
||||
onRobotProfileChanged(...args: unknown[]): void;
|
||||
}
|
||||
|
||||
export interface NodeIKernelRobotListener extends IKernelRobotListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IKernelRobotListener): NodeIKernelRobotListener;
|
||||
}
|
||||
|
||||
export class KernelRobotListener implements IKernelRobotListener {
|
||||
onRobotFriendListChanged(...args: unknown[]){
|
||||
|
||||
}
|
||||
|
||||
onRobotListChanged(...args: unknown[]){
|
||||
|
||||
}
|
||||
|
||||
onRobotProfileChanged(...args: unknown[]){
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
export interface ISessionListener {
|
||||
onNTSessionCreate(args: unknown): void;
|
||||
|
||||
onGProSessionCreate(args: unknown): void;
|
||||
|
||||
onSessionInitComplete(args: unknown): void;
|
||||
|
||||
onOpentelemetryInit(args: unknown): void;
|
||||
|
||||
onUserOnlineResult(args: unknown): void;
|
||||
|
||||
onGetSelfTinyId(args: unknown): void;
|
||||
}
|
||||
|
||||
export interface NodeIKernelSessionListener extends ISessionListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: ISessionListener): NodeIKernelSessionListener;
|
||||
}
|
||||
|
||||
export class SessionListener implements ISessionListener {
|
||||
onNTSessionCreate(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGProSessionCreate(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSessionInitComplete(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onOpentelemetryInit(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserOnlineResult(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGetSelfTinyId(args: unknown) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
export interface IStorageCleanListener {
|
||||
onCleanCacheProgressChanged(args: unknown): void;
|
||||
|
||||
onScanCacheProgressChanged(args: unknown): void;
|
||||
|
||||
onCleanCacheStorageChanged(args: unknown): void;
|
||||
|
||||
onFinishScan(args: unknown): void;
|
||||
|
||||
onChatCleanDone(args: unknown): void;
|
||||
|
||||
}
|
||||
export interface NodeIKernelStorageCleanListener extends IStorageCleanListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IStorageCleanListener): NodeIKernelStorageCleanListener;
|
||||
}
|
||||
|
||||
export class StorageCleanListener implements IStorageCleanListener {
|
||||
onCleanCacheProgressChanged(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onScanCacheProgressChanged(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onCleanCacheStorageChanged(args: unknown) {
|
||||
|
||||
}
|
||||
onFinishScan(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onChatCleanDone(args: unknown) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
export interface IKernelTicketListener {
|
||||
}
|
||||
export interface NodeIKernelTicketListener extends IKernelTicketListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(adapter: IKernelTicketListener): NodeIKernelTicketListener;
|
||||
}
|
||||
|
||||
export class KernelTicketListener implements IKernelTicketListener {
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
export * from './NodeIKernelSessionListener';
|
||||
export * from './NodeIKernelLoginListener';
|
||||
export * from './NodeIKernelMsgListener';
|
||||
export * from './NodeIKernelGroupListener';
|
||||
export * from './NodeIKernelBuddyListener';
|
||||
export * from './NodeIKernelProfileListener';
|
||||
export * from './NodeIKernelRobotListener';
|
||||
export * from './NodeIKernelTicketListener';
|
||||
export * from './NodeIKernelStorageCleanListener';
|
||||
export * from './NodeIKernelFileAssistantListener';
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
export interface NodeIKernelAlbumService {
|
||||
setAlbumServiceInfo(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
getMainPage(...args: any[]): unknown;// needs 2 arguments
|
||||
|
||||
getAlbumList(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
getAlbumInfo(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
deleteAlbum(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
addAlbum(...args: any[]): unknown;// needs 2 arguments
|
||||
|
||||
deleteMedias(...args: any[]): unknown;// needs 4 arguments
|
||||
|
||||
modifyAlbum(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
getMediaList(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
quoteToQzone(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
quoteToQunAlbum(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
queryQuoteToQunAlbumStatus(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
getQunFeeds(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
getQunFeedDetail(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
getQunNoticeList(...args: any[]): unknown;// needs 4 arguments
|
||||
|
||||
getQunComment(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
getQunLikes(...args: any[]): unknown;// needs 4 arguments
|
||||
|
||||
deleteQunFeed(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
doQunComment(...args: any[]): unknown;// needs 6 arguments
|
||||
|
||||
doQunReply(...args: any[]): unknown;// needs 7 arguments
|
||||
|
||||
doQunLike(...args: any[]): unknown;// needs 5 arguments
|
||||
|
||||
getRedPoints(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
export interface NodeIKernelAvatarService {
|
||||
addAvatarListener(arg: unknown): unknown;
|
||||
|
||||
removeAvatarListener(arg: unknown): unknown;
|
||||
|
||||
getAvatarPath(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
forceDownloadAvatar(uid: string, useCache: number): Promise<unknown>;
|
||||
|
||||
getGroupAvatarPath(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
getConfGroupAvatarPath(arg: unknown): unknown;
|
||||
|
||||
forceDownloadGroupAvatar(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
getGroupPortraitPath(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
forceDownloadGroupPortrait(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
getAvatarPaths(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
getGroupAvatarPaths(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
getConfGroupAvatarPaths(arg: unknown): unknown;
|
||||
|
||||
getAvatarPathByUin(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
forceDownloadAvatarByUin(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
import { Friend } from '@/core/entities';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
import { NodeIKernelBuddyListener } from '@/core/listeners';
|
||||
export enum BuddyListReqType {
|
||||
KNOMAL,
|
||||
KLETTER
|
||||
}
|
||||
export interface NodeIKernelBuddyService {
|
||||
// 26702 以上
|
||||
getBuddyListV2(callFrom: string, reqType: BuddyListReqType): Promise<GeneralCallResult & {
|
||||
data: Array<{
|
||||
categoryId: number,
|
||||
categorySortId: number,
|
||||
categroyName: string,
|
||||
categroyMbCount: number,
|
||||
onlineCount: number,
|
||||
buddyUids: Array<string>
|
||||
}>
|
||||
}>;
|
||||
//26702 以上
|
||||
getBuddyListFromCache(callFrom: string): Promise<Array<
|
||||
{
|
||||
categoryId: number,//9999应该跳过 那是兜底数据吧
|
||||
categorySortId: number,//排序方式
|
||||
categroyName: string,//分类名
|
||||
categroyMbCount: number,//不懂
|
||||
onlineCount: number,//在线数目
|
||||
buddyUids: Array<string>//Uids
|
||||
}>>;
|
||||
// 以下为原生方法
|
||||
addKernelBuddyListener(listener: NodeIKernelBuddyListener): number;
|
||||
|
||||
getAllBuddyCount(): number;
|
||||
|
||||
removeKernelBuddyListener(listener: unknown): void;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param nocache 使用缓存
|
||||
*/
|
||||
getBuddyList(nocache: boolean): Promise<GeneralCallResult>;
|
||||
|
||||
getBuddyNick(uid: number): string;
|
||||
|
||||
getBuddyRemark(uid: number): string;
|
||||
|
||||
setBuddyRemark(uid: number, remark: string): void;
|
||||
|
||||
getAvatarUrl(uid: number): string;
|
||||
|
||||
isBuddy(uid: string): boolean;
|
||||
|
||||
getCategoryNameWithUid(uid: number): string;
|
||||
|
||||
getTargetBuddySetting(uid: number): unknown;
|
||||
|
||||
getTargetBuddySettingByType(uid: number, type: number): unknown;
|
||||
|
||||
getBuddyReqUnreadCnt(): number;
|
||||
|
||||
getBuddyReq(): unknown;
|
||||
|
||||
delBuddyReq(uid: number): void;
|
||||
|
||||
clearBuddyReqUnreadCnt(): void;
|
||||
|
||||
reqToAddFriends(uid: number, msg: string): void;
|
||||
|
||||
setSpacePermission(uid: number, permission: number): void;
|
||||
|
||||
approvalFriendRequest(arg: {
|
||||
friendUid: string;
|
||||
reqTime: string;
|
||||
accept: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
delBuddy(uid: number): void;
|
||||
|
||||
delBatchBuddy(uids: number[]): void;
|
||||
|
||||
getSmartInfos(uid: number): unknown;
|
||||
|
||||
setBuddyCategory(uid: number, category: number): void;
|
||||
|
||||
setBatchBuddyCategory(uids: number[], category: number): void;
|
||||
|
||||
addCategory(category: string): void;
|
||||
|
||||
delCategory(category: string): void;
|
||||
|
||||
renameCategory(oldCategory: string, newCategory: string): void;
|
||||
|
||||
resortCategory(categorys: string[]): void;
|
||||
|
||||
pullCategory(uid: number, category: string): void;
|
||||
|
||||
setTop(uid: number, isTop: boolean): void;
|
||||
|
||||
SetSpecialCare(uid: number, isSpecialCare: boolean): void;
|
||||
|
||||
setMsgNotify(uid: number, isNotify: boolean): void;
|
||||
|
||||
hasBuddyList(): boolean;
|
||||
|
||||
setBlock(uid: number, isBlock: boolean): void;
|
||||
|
||||
isBlocked(uid: number): boolean;
|
||||
|
||||
modifyAddMeSetting(setting: unknown): void;
|
||||
|
||||
getAddMeSetting(): unknown;
|
||||
|
||||
getDoubtBuddyReq(): unknown;
|
||||
|
||||
getDoubtBuddyUnreadNum(): number;
|
||||
|
||||
approvalDoubtBuddyReq(uid: number, isAgree: boolean): void;
|
||||
|
||||
delDoubtBuddyReq(uid: number): void;
|
||||
|
||||
delAllDoubtBuddyReq(): void;
|
||||
|
||||
reportDoubtBuddyReqUnread(): void;
|
||||
|
||||
getBuddyRecommendContactArkJson(uid: string, phoneNumber: string): Promise<unknown>;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
import { GeneralCallResult } from "./common";
|
||||
|
||||
export interface NodeIKernelCollectionService {
|
||||
addKernelCollectionListener(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
removeKernelCollectionListener(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
getCollectionItemList(param: {
|
||||
category: number,
|
||||
groupId: number,
|
||||
forceSync: boolean,
|
||||
forceFromDb: boolean,
|
||||
timeStamp: string,
|
||||
count: number,
|
||||
searchDown: boolean
|
||||
}): Promise<GeneralCallResult &
|
||||
{
|
||||
collectionSearchList: {
|
||||
collectionItemList: Array<
|
||||
{
|
||||
cid: string,
|
||||
type: number,
|
||||
status: number,
|
||||
author: {
|
||||
type: number,
|
||||
numId: string,
|
||||
strId: string,
|
||||
groupId: string,
|
||||
groupName: string,
|
||||
uid: string
|
||||
},
|
||||
bid: number,
|
||||
category: number,
|
||||
createTime: string,
|
||||
collectTime: string,
|
||||
modifyTime: string,
|
||||
sequence: string,
|
||||
shareUrl: string,
|
||||
customGroupId: number,
|
||||
securityBeat: boolean,
|
||||
summary: {
|
||||
textSummary: unknown,
|
||||
linkSummary: unknown,
|
||||
gallerySummary: unknown,
|
||||
audioSummary: unknown,
|
||||
videoSummary: unknown,
|
||||
fileSummary: unknown,
|
||||
locationSummary: unknown,
|
||||
richMediaSummary: unknown,
|
||||
}
|
||||
}>,
|
||||
hasMore: boolean,
|
||||
bottomTimeStamp: string
|
||||
}
|
||||
}
|
||||
>;//needs 1 arguments
|
||||
|
||||
getCollectionContent(...args: any[]): unknown;//needs 5 arguments
|
||||
|
||||
getCollectionCustomGroupList(...args: any[]): unknown;//needs 0 arguments
|
||||
|
||||
getCollectionUserInfo(...args: any[]): unknown;//needs 0 arguments
|
||||
|
||||
searchCollectionItemList(...args: any[]): unknown;//needs 2 arguments
|
||||
|
||||
addMsgToCollection(...args: any[]): unknown;//needs 2 arguments
|
||||
|
||||
collectionArkShare(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
collectionFileForward(...args: any[]): unknown;//needs 3 arguments
|
||||
|
||||
downloadCollectionFile(...args: any[]): unknown;//needs 4 arguments
|
||||
|
||||
downloadCollectionFileThumbPic(...args: any[]): unknown;//needs 4 arguments
|
||||
|
||||
downloadCollectionPic(...args: any[]): unknown;//needs 3 arguments
|
||||
|
||||
cancelDownloadCollectionFile(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
deleteCollectionItemList(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
editCollectionItem(...args: any[]): unknown;//needs 2 arguments
|
||||
|
||||
getEditPicInfoByPath(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
collectionFastUpload(...args: any[]): unknown;//needs 1 arguments
|
||||
|
||||
editCollectionItemAfterFastUpload(...args: any[]): unknown;//needs 2 arguments
|
||||
|
||||
createNewCollectionItem(...args: any[]): unknown;//needs 1 arguments
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export interface NodeIKernelDbToolsService {
|
||||
depositDatabase(...args: unknown[]): unknown;
|
||||
backupDatabase(...args: unknown[]): unknown;
|
||||
retrieveDatabase(...args: unknown[]): unknown;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export interface NodeIKernelECDHService{
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
export interface NodeIKernelFileAssistantService {
|
||||
addKernelFileAssistantListener(arg1: unknown[]): unknown;
|
||||
|
||||
removeKernelFileAssistantListener(arg1: unknown[]): unknown;
|
||||
|
||||
getFileAssistantList(arg1: unknown[]): unknown;
|
||||
|
||||
getMoreFileAssistantList(arg1: unknown[]): unknown;
|
||||
|
||||
getFileSessionList(): unknown;
|
||||
|
||||
searchFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
resetSearchFileSortType(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
searchMoreFile(arg1: unknown[]): unknown;
|
||||
|
||||
cancelSearchFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
downloadFile(arg1: unknown[]): unknown;
|
||||
|
||||
forwardFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
cancelFileAction(arg1: unknown[]): unknown;
|
||||
|
||||
retryFileAction(arg1: unknown[]): unknown;
|
||||
|
||||
deleteFile(arg1: unknown[]): unknown;
|
||||
|
||||
saveAs(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
saveAsWithRename(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
import { NodeIKernelGroupListener } from '@/core/listeners/NodeIKernelGroupListener';
|
||||
import {
|
||||
GroupExtParam,
|
||||
GroupMember,
|
||||
GroupMemberRole,
|
||||
GroupNotifyTypes,
|
||||
GroupRequestOperateTypes,
|
||||
} from '@/core/entities';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
|
||||
//高版本的接口不应该随意使用 使用应该严格进行pr审核 同时部分ipc中未出现的接口不要过于依赖 应该做好数据兜底
|
||||
|
||||
export interface NodeIKernelGroupService {
|
||||
getMemberCommonInfo(Req: {
|
||||
groupCode: string,
|
||||
startUin: string,
|
||||
identifyFlag: string,
|
||||
uinList: string[],
|
||||
memberCommonFilter: {
|
||||
memberUin: number,
|
||||
uinFlag: number,
|
||||
uinFlagExt: number,
|
||||
uinMobileFlag: number,
|
||||
shutUpTime: number,
|
||||
privilege: number,
|
||||
},
|
||||
memberNum: number,
|
||||
filterMethod: string,
|
||||
onlineFlag: string,
|
||||
realSpecialTitleFlag: number
|
||||
}): Promise<unknown>;
|
||||
//26702
|
||||
getGroupMemberLevelInfo(groupCode: string): Promise<unknown>;
|
||||
//26702
|
||||
getGroupHonorList(groupCodes: Array<string>): unknown;
|
||||
|
||||
getUinByUids(uins: string[]): Promise<{
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
uins: Map<string, string>
|
||||
}>;
|
||||
|
||||
getUidByUins(uins: string[]): Promise<{
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
uids: Map<string, string>
|
||||
}>;
|
||||
//26702(其实更早 但是我不知道)
|
||||
checkGroupMemberCache(arrayList: Array<string>): Promise<unknown>;
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
getGroupLatestEssenceList(groupCode: string): Promise<unknown>;
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
shareDigest(Req: {
|
||||
appId: string,
|
||||
appType: number,
|
||||
msgStyle: number,
|
||||
recvUin: string,
|
||||
sendType: number,
|
||||
clientInfo: {
|
||||
platform: number
|
||||
},
|
||||
richMsg: {
|
||||
usingArk: boolean,
|
||||
title: string,
|
||||
summary: string,
|
||||
url: string,
|
||||
pictureUrl: string,
|
||||
brief: string
|
||||
}
|
||||
}): Promise<unknown>;
|
||||
//26702(其实更早 但是我不知道)
|
||||
isEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
|
||||
//26702(其实更早 但是我不知道)
|
||||
queryCachedEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
|
||||
//26702(其实更早 但是我不知道)
|
||||
fetchGroupEssenceList(Req: { groupCode: string, pageStart: number, pageLimit: number }, Arg: unknown): Promise<unknown>;
|
||||
//26702
|
||||
getAllMemberList(groupCode: string, forceFetch: boolean): Promise<{
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
result: {
|
||||
ids: Array<{
|
||||
uid: string,
|
||||
index: number//0
|
||||
}>,
|
||||
infos: {},
|
||||
finish: true,
|
||||
hasRobot: false
|
||||
}
|
||||
}>;
|
||||
|
||||
setHeader(uid: string, path: string): unknown;
|
||||
|
||||
addKernelGroupListener(listener: NodeIKernelGroupListener): number;
|
||||
|
||||
removeKernelGroupListener(listenerId: unknown): void;
|
||||
|
||||
createMemberListScene(groupCode: string, scene: string): string;
|
||||
|
||||
destroyMemberListScene(SceneId:string): void;
|
||||
//About Arg (a) name: lastId 根据手Q来看为object {index:?(number),uid:string}
|
||||
getNextMemberList(sceneId: string, a: undefined, num: number): Promise<{
|
||||
errCode: number, errMsg: string,
|
||||
result: { ids: string[], infos: Map<string, GroupMember>, finish: boolean, hasRobot: boolean }
|
||||
}>;
|
||||
|
||||
getPrevMemberList(): unknown;
|
||||
|
||||
monitorMemberList(): unknown;
|
||||
|
||||
searchMember(sceneId: string, keywords: string[]): unknown;
|
||||
|
||||
getMemberInfo(group_id: string, uids: string[], forceFetch: boolean): Promise<GeneralCallResult>;
|
||||
//getMemberInfo [ '56729xxxx', [ 'u_4Nj08cwW5Hxxxxx' ], true ]
|
||||
|
||||
kickMember(groupCode: string, memberUids: string[], refuseForever: boolean, kickReason: string): Promise<void>;
|
||||
|
||||
modifyMemberRole(groupCode: string, uid: string, role: GroupMemberRole): void;
|
||||
|
||||
modifyMemberCardName(groupCode: string, uid: string, cardName: string): void;
|
||||
|
||||
getTransferableMemberInfo(groupCode: string): unknown;//获取整个群的
|
||||
|
||||
transferGroup(uid: string): void;
|
||||
|
||||
getGroupList(force: boolean): Promise<GeneralCallResult>;
|
||||
|
||||
getGroupExtList(force: boolean): Promise<GeneralCallResult>;
|
||||
|
||||
getGroupDetailInfo(groupCode: string): unknown;
|
||||
|
||||
getMemberExtInfo(param: GroupExtParam): Promise<unknown>;//req
|
||||
|
||||
getGroupAllInfo(): unknown;
|
||||
|
||||
getDiscussExistInfo(): unknown;
|
||||
|
||||
getGroupConfMember(): unknown;
|
||||
|
||||
getGroupMsgMask(): unknown;
|
||||
|
||||
getGroupPortrait(): void;
|
||||
|
||||
modifyGroupName(groupCode: string, groupName: string, arg: false): void;
|
||||
|
||||
modifyGroupRemark(groupCode: string, remark: string): void;
|
||||
|
||||
modifyGroupDetailInfo(groupCode: string, arg: unknown): void;
|
||||
|
||||
setGroupMsgMask(groupCode: string, arg: unknown): void;
|
||||
|
||||
changeGroupShieldSettingTemp(groupCode: string, arg: unknown): void;
|
||||
|
||||
inviteToGroup(arg: unknown): void;
|
||||
|
||||
inviteMembersToGroup(args: unknown[]): void;
|
||||
|
||||
inviteMembersToGroupWithMsg(args: unknown): void;
|
||||
|
||||
createGroup(arg: unknown): void;
|
||||
|
||||
createGroupWithMembers(arg: unknown): void;
|
||||
|
||||
quitGroup(groupCode: string): void;
|
||||
|
||||
destroyGroup(groupCode: string): void;
|
||||
//获取单屏群通知列表
|
||||
getSingleScreenNotifies(force: boolean, start_seq: string, num: number): Promise<GeneralCallResult>;
|
||||
|
||||
clearGroupNotifies(groupCode: string): void;
|
||||
|
||||
getGroupNotifiesUnreadCount(unknown: Boolean): Promise<GeneralCallResult>;
|
||||
|
||||
clearGroupNotifiesUnreadCount(groupCode: string): void;
|
||||
|
||||
operateSysNotify(
|
||||
doubt: boolean,
|
||||
operateMsg: {
|
||||
operateType: GroupRequestOperateTypes, // 2 拒绝
|
||||
targetMsg: {
|
||||
seq: string, // 通知序列号
|
||||
type: GroupNotifyTypes,
|
||||
groupCode: string,
|
||||
postscript: string
|
||||
}
|
||||
}): Promise<void>;
|
||||
|
||||
setTop(groupCode: string, isTop: boolean): void;
|
||||
|
||||
getGroupBulletin(groupCode: string): unknown;
|
||||
|
||||
deleteGroupBulletin(groupCode: string, seq: string): void;
|
||||
|
||||
publishGroupBulletin(groupCode: string, pskey: string, data: any): Promise<GeneralCallResult>;
|
||||
|
||||
publishInstructionForNewcomers(groupCode: string, arg: unknown): void;
|
||||
|
||||
uploadGroupBulletinPic(groupCode: string, pskey: string, imagePath: string): Promise<GeneralCallResult & {
|
||||
errCode: number;
|
||||
picInfo?: {
|
||||
id: string,
|
||||
width: number,
|
||||
height: number
|
||||
}
|
||||
}>;
|
||||
|
||||
downloadGroupBulletinRichMedia(groupCode: string): unknown;
|
||||
|
||||
getGroupBulletinList(groupCode: string): unknown;
|
||||
|
||||
getGroupStatisticInfo(groupCode: string): unknown;
|
||||
|
||||
getGroupRemainAtTimes(groupCode: string): number;
|
||||
|
||||
getJoinGroupNoVerifyFlag(groupCode: string): unknown;
|
||||
|
||||
getGroupArkInviteState(groupCode: string): unknown;
|
||||
|
||||
reqToJoinGroup(groupCode: string, arg: unknown): void;
|
||||
|
||||
setGroupShutUp(groupCode: string, shutUp: boolean): void;
|
||||
|
||||
getGroupShutUpMemberList(groupCode: string): unknown[];
|
||||
|
||||
setMemberShutUp(groupCode: string, memberTimes: { uid: string, timeStamp: number }[]): Promise<void>;
|
||||
|
||||
getGroupRecommendContactArkJson(groupCode: string): unknown;
|
||||
|
||||
getJoinGroupLink(groupCode: string): unknown;
|
||||
|
||||
modifyGroupExtInfo(groupCode: string, arg: unknown): void;
|
||||
|
||||
//需要提前判断是否存在 高版本新增
|
||||
addGroupEssence(param: {
|
||||
groupCode: string
|
||||
msgRandom: number,
|
||||
msgSeq: number
|
||||
}): Promise<unknown>;
|
||||
//需要提前判断是否存在 高版本新增
|
||||
removeGroupEssence(param: {
|
||||
groupCode: string
|
||||
msgRandom: number,
|
||||
msgSeq: number
|
||||
}): Promise<unknown>;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import { NodeIKernelLoginListener } from '@/core/listeners/NodeIKernelLoginListener';
|
||||
|
||||
export interface LoginInitConfig {
|
||||
machineId: '';
|
||||
appid: string;
|
||||
platVer: string;
|
||||
commonPath: string;
|
||||
clientVer: string;
|
||||
hostName: string;
|
||||
}
|
||||
|
||||
export interface passwordLoginRetType {
|
||||
result: string,
|
||||
loginErrorInfo: {
|
||||
step: number;
|
||||
errMsg: string;
|
||||
proofWaterUrl: string;
|
||||
newDevicePullQrCodeSig: string;
|
||||
jumpUrl: string,
|
||||
jumpWord: string;
|
||||
tipsTitle: string;
|
||||
tipsContent: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface passwordLoginArgType {
|
||||
uin: string;
|
||||
passwordMd5: string;//passwMD5
|
||||
step: number;//猜测是需要二次认证 参数 一次为0
|
||||
newDeviceLoginSig: string;
|
||||
proofWaterSig: string;
|
||||
proofWaterRand: string;
|
||||
proofWaterSid: string;
|
||||
}
|
||||
|
||||
export interface LoginListItem {
|
||||
uin: string;
|
||||
uid: string;
|
||||
nickName: string;
|
||||
faceUrl: string;
|
||||
facePath: string;
|
||||
loginType: 1; // 1是二维码登录?
|
||||
isQuickLogin: boolean; // 是否可以快速登录
|
||||
isAutoLogin: boolean; // 是否可以自动登录
|
||||
}
|
||||
|
||||
export interface QuickLoginResult{
|
||||
result: string
|
||||
loginErrorInfo: {
|
||||
step: number,
|
||||
errMsg: string,
|
||||
proofWaterUrl: string,
|
||||
newDevicePullQrCodeSig: string,
|
||||
jumpUrl: string,
|
||||
jumpWord: string,
|
||||
tipsTitle: string,
|
||||
tipsContent: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface NodeIKernelLoginService {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeIKernelLoginService;
|
||||
|
||||
addKernelLoginListener(listener: NodeIKernelLoginListener): number;
|
||||
removeKernelLoginListener(listener: number): void;
|
||||
|
||||
initConfig(config: LoginInitConfig): void;
|
||||
|
||||
getLoginMiscData(cb: (r: unknown) => void): void;
|
||||
|
||||
getLoginList(): Promise<{
|
||||
result: number, // 0是ok
|
||||
LocalLoginInfoList: LoginListItem[]
|
||||
}>;
|
||||
|
||||
quickLoginWithUin(uin: string): Promise<QuickLoginResult>;
|
||||
|
||||
passwordLogin(param: passwordLoginArgType): Promise<any>;
|
||||
|
||||
getQRCodePicture(): boolean;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export interface NodeIKernelMSFService {
|
||||
getServerTime(): string;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
export interface NodeIKernelMsgBackupService {
|
||||
addKernelMsgBackupListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
removeKernelMsgBackupListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
getMsgBackupLocation(...args: any[]): unknown;// needs 0 arguments
|
||||
|
||||
setMsgBackupLocation(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
requestMsgBackup(...args: any[]): unknown;// needs 0 arguments
|
||||
|
||||
requestMsgRestore(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
requestMsgMigrate(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
getLocalStorageBackup(...args: any[]): unknown;// needs 0 arguments
|
||||
|
||||
deleteLocalBackup(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
clearCache(...args: any[]): unknown;// needs 0 arguments
|
||||
|
||||
start(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
stop(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
pause(...args: any[]): unknown;// needs 2 arguments
|
||||
}
|
||||
@@ -1,727 +0,0 @@
|
||||
import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/core/entities';
|
||||
import { NodeIKernelMsgListener } from '@/core/listeners/NodeIKernelMsgListener';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
|
||||
export interface QueryMsgsParams {
|
||||
chatInfo: Peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: string[],
|
||||
filterMsgFromTime: string,
|
||||
filterMsgToTime: string,
|
||||
pageLimit: number,
|
||||
isReverseOrder: boolean,
|
||||
isIncludeCurrent: boolean
|
||||
}
|
||||
export interface NodeIKernelMsgService {
|
||||
|
||||
generateMsgUniqueId(chatType: number, time: string): string;
|
||||
|
||||
addKernelMsgListener(nodeIKernelMsgListener: NodeIKernelMsgListener): number;
|
||||
|
||||
sendMsg(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>): Promise<GeneralCallResult>;
|
||||
|
||||
recallMsg(peer: Peer, msgIds: string[]): Promise<GeneralCallResult>;
|
||||
|
||||
addKernelMsgImportToolListener(arg: Object): unknown;
|
||||
|
||||
removeKernelMsgListener(args: unknown): unknown;
|
||||
|
||||
addKernelTempChatSigListener(...args: unknown[]): unknown;
|
||||
|
||||
removeKernelTempChatSigListener(...args: unknown[]): unknown;
|
||||
|
||||
setAutoReplyTextList(AutoReplyText: Array<unknown>, i2: number): unknown;
|
||||
|
||||
getAutoReplyTextList(...args: unknown[]): unknown;
|
||||
|
||||
getOnLineDev(): void;
|
||||
|
||||
kickOffLine(DevInfo: Object): unknown;
|
||||
|
||||
setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult>;
|
||||
|
||||
fetchStatusMgrInfo(): unknown;
|
||||
|
||||
fetchStatusUnitedConfigInfo(): unknown;
|
||||
|
||||
getOnlineStatusSmallIconBasePath(): unknown;
|
||||
|
||||
getOnlineStatusSmallIconFileNameByUrl(Url: string): unknown;
|
||||
|
||||
downloadOnlineStatusSmallIconByUrl(arg0: number, arg1: string): unknown;
|
||||
|
||||
getOnlineStatusBigIconBasePath(): unknown;
|
||||
|
||||
downloadOnlineStatusBigIconByUrl(arg0: number, arg1: string): unknown;
|
||||
|
||||
getOnlineStatusCommonPath(arg: string): unknown;
|
||||
|
||||
getOnlineStatusCommonFileNameByUrl(Url: string): unknown;
|
||||
|
||||
downloadOnlineStatusCommonByUrl(arg0: string, arg1: string): unknown;
|
||||
|
||||
// this.tokenType = i2;
|
||||
// this.apnsToken = bArr;
|
||||
// this.voipToken = bArr2;
|
||||
// this.profileId = str;
|
||||
|
||||
setToken(arg: Object): unknown;
|
||||
|
||||
switchForeGround(): unknown;
|
||||
|
||||
switchBackGround(arg: Object): unknown;
|
||||
|
||||
//hex
|
||||
setTokenForMqq(token: string): unknown;
|
||||
|
||||
switchForeGroundForMqq(...args: unknown[]): unknown;
|
||||
|
||||
switchBackGroundForMqq(...args: unknown[]): unknown;
|
||||
|
||||
getMsgSetting(...args: unknown[]): unknown;
|
||||
|
||||
setMsgSetting(...args: unknown[]): unknown;
|
||||
|
||||
addSendMsg(...args: unknown[]): unknown;
|
||||
|
||||
cancelSendMsg(...args: unknown[]): unknown;
|
||||
|
||||
switchToOfflineSendMsg(peer: Peer, MsgId: string): unknown;
|
||||
|
||||
reqToOfflineSendMsg(...args: unknown[]): unknown;
|
||||
|
||||
refuseReceiveOnlineFileMsg(peer: Peer, MsgId: string): unknown;
|
||||
|
||||
resendMsg(...args: unknown[]): unknown;
|
||||
|
||||
recallMsg(...args: unknown[]): unknown;
|
||||
|
||||
reeditRecallMsg(...args: unknown[]): unknown;
|
||||
|
||||
forwardMsg(...args: unknown[]): Promise<GeneralCallResult>;
|
||||
|
||||
forwardMsgWithComment(...args: unknown[]): unknown;
|
||||
|
||||
forwardSubMsgWithComment(...args: unknown[]): unknown;
|
||||
|
||||
forwardRichMsgInVist(...args: unknown[]): unknown;
|
||||
|
||||
forwardFile(...args: unknown[]): unknown;
|
||||
//Array<Msg>, Peer from, Peer to
|
||||
multiForwardMsg(...args: unknown[]): unknown;
|
||||
|
||||
multiForwardMsgWithComment(...args: unknown[]): unknown;
|
||||
|
||||
deleteRecallMsg(...args: unknown[]): unknown;
|
||||
|
||||
deleteRecallMsgForLocal(...args: unknown[]): unknown;
|
||||
|
||||
addLocalGrayTipMsg(...args: unknown[]): unknown;
|
||||
|
||||
addLocalJsonGrayTipMsg(...args: unknown[]): unknown;
|
||||
|
||||
addLocalJsonGrayTipMsgExt(...args: unknown[]): unknown;
|
||||
|
||||
IsLocalJsonTipValid(...args: unknown[]): unknown;
|
||||
|
||||
addLocalAVRecordMsg(...args: unknown[]): unknown;
|
||||
|
||||
addLocalTofuRecordMsg(...args: unknown[]): unknown;
|
||||
|
||||
addLocalRecordMsg(Peer: Peer, msgId: string, ele: MessageElement, attr: Array<any> | number, front: boolean): Promise<unknown>;
|
||||
|
||||
deleteMsg(Peer: Peer, msgIds: Array<string>): Promise<any>;
|
||||
|
||||
updateElementExtBufForUI(...args: unknown[]): unknown;
|
||||
|
||||
updateMsgRecordExtPbBufForUI(...args: unknown[]): unknown;
|
||||
|
||||
startMsgSync(...args: unknown[]): unknown;
|
||||
|
||||
startGuildMsgSync(...args: unknown[]): unknown;
|
||||
|
||||
isGuildChannelSync(...args: unknown[]): unknown;
|
||||
|
||||
getMsgUniqueId(UniqueId: string): string;
|
||||
|
||||
isMsgMatched(...args: unknown[]): unknown;
|
||||
|
||||
getOnlineFileMsgs(...args: unknown[]): unknown;
|
||||
|
||||
getAllOnlineFileMsgs(...args: unknown[]): unknown;
|
||||
|
||||
getLatestDbMsgs(peer: Peer, cnt: number): Promise<unknown>;
|
||||
|
||||
getLastMessageList(peer: Peer[]): Promise<unknown>;
|
||||
|
||||
getAioFirstViewLatestMsgs(peer: Peer, num: number): unknown;
|
||||
|
||||
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>;
|
||||
|
||||
getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
}>;
|
||||
|
||||
// this.$peer = contact;
|
||||
// this.$msgTime = j2;
|
||||
// this.$clientSeq = j3;
|
||||
// this.$cnt = i2;
|
||||
|
||||
getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getMsgsWithStatus(params: {
|
||||
peer: Peer
|
||||
msgId: string
|
||||
msgTime: unknown
|
||||
cnt: unknown
|
||||
queryOrder: boolean
|
||||
isIncludeSelf: boolean
|
||||
appid: unknown
|
||||
}): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getMsgsByMsgId(peer: Peer, ids: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getRecallMsgsByMsgId(peer: Peer, MsgId: string[]): Promise<unknown>;
|
||||
|
||||
getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||
|
||||
getSourceOfReplyMsg(peer: Peer, MsgId: string, SourceSeq: string): unknown;
|
||||
|
||||
getSourceOfReplyMsgV2(peer: Peer, RootMsgId: string, ReplyMsgId: string): unknown;
|
||||
|
||||
getMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown;
|
||||
|
||||
getSourceOfReplyMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown;
|
||||
//cnt clientSeq?并不是吧
|
||||
getMsgsByTypeFilter(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilter: { type: number, subtype: Array<number> }): unknown;
|
||||
|
||||
getMsgsByTypeFilters(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilters: Array<{ type: number, subtype: Array<number> }>): unknown;
|
||||
|
||||
getMsgWithAbstractByFilterParam(...args: unknown[]): unknown;
|
||||
|
||||
queryMsgsWithFilter(...args: unknown[]): unknown;
|
||||
|
||||
/**
|
||||
* @deprecated 该函数已被标记为废弃,请使用新的替代方法。
|
||||
* 使用过滤条件查询消息列表的版本2接口。
|
||||
*
|
||||
* 该函数通过一系列过滤条件来查询特定聊天中的消息列表。这些条件包括消息类型、发送者、时间范围等。
|
||||
* 函数返回一个Promise,解析为查询结果的未知类型对象。
|
||||
*
|
||||
* @param MsgId 消息ID,用于特定消息的查询。
|
||||
* @param MsgTime 消息时间,用于指定消息的时间范围。
|
||||
* @param param 查询参数对象,包含详细的过滤条件和分页信息。
|
||||
* @param param.chatInfo 聊天信息,包括聊天类型和对方用户ID。
|
||||
* @param param.filterMsgType 需要过滤的消息类型数组,留空表示不过滤。
|
||||
* @param param.filterSendersUid 需要过滤的发送者用户ID数组。
|
||||
* @param param.filterMsgFromTime 查询消息的起始时间。
|
||||
* @param param.filterMsgToTime 查询消息的结束时间。
|
||||
* @param param.pageLimit 每页的消息数量限制。
|
||||
* @param param.isReverseOrder 是否按时间顺序倒序返回消息。
|
||||
* @param param.isIncludeCurrent 是否包含当前页码。
|
||||
* @returns 返回一个Promise,解析为查询结果的未知类型对象。
|
||||
*/
|
||||
queryMsgsWithFilterVer2(MsgId: string, MsgTime: string, param: QueryMsgsParams): Promise<unknown>;
|
||||
|
||||
// this.chatType = i2;
|
||||
// this.peerUid = str;
|
||||
|
||||
// this.chatInfo = new ChatInfo();
|
||||
// this.filterMsgType = new ArrayList<>();
|
||||
// this.filterSendersUid = new ArrayList<>();
|
||||
// this.chatInfo = chatInfo;
|
||||
// this.filterMsgType = arrayList;
|
||||
// this.filterSendersUid = arrayList2;
|
||||
// this.filterMsgFromTime = j2;
|
||||
// this.filterMsgToTime = j3;
|
||||
// this.pageLimit = i2;
|
||||
// this.isReverseOrder = z;
|
||||
// this.isIncludeCurrent = z2;
|
||||
//queryMsgsWithFilterEx(0L, 0L, 0L, new QueryMsgsParams(new ChatInfo(2, str), new ArrayList(), new ArrayList(), 0L, 0L, 250, false, true))
|
||||
queryMsgsWithFilterEx(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
}>;
|
||||
//queryMsgsWithFilterEx(this.$msgId, this.$msgTime, this.$msgSeq, this.$param)
|
||||
queryFileMsgsDesktop(...args: unknown[]): unknown;
|
||||
|
||||
setMsgRichInfoFlag(...args: unknown[]): unknown;
|
||||
|
||||
queryPicOrVideoMsgs(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): Promise<unknown>;
|
||||
|
||||
queryPicOrVideoMsgsDesktop(...args: unknown[]): unknown;
|
||||
|
||||
queryEmoticonMsgs(msgId: string, msgTime: string, msgSeq: string, Params: QueryMsgsParams): Promise<unknown>;
|
||||
|
||||
queryTroopEmoticonMsgs(msgId: string, msgTime: string, msgSeq: string, Params: QueryMsgsParams): Promise<unknown>;
|
||||
|
||||
queryMsgsAndAbstractsWithFilter(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): unknown;
|
||||
|
||||
setFocusOnGuild(...args: unknown[]): unknown;
|
||||
|
||||
setFocusSession(...args: unknown[]): unknown;
|
||||
|
||||
enableFilterUnreadInfoNotify(...args: unknown[]): unknown;
|
||||
|
||||
enableFilterMsgAbstractNotify(...args: unknown[]): unknown;
|
||||
|
||||
onScenesChangeForSilenceMode(...args: unknown[]): unknown;
|
||||
|
||||
getContactUnreadCnt(...args: unknown[]): unknown;
|
||||
|
||||
getUnreadCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
getGuildUnreadCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
getGuildUnreadCntTabInfo(...args: unknown[]): unknown;
|
||||
|
||||
getAllGuildUnreadCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
getAllJoinGuildCnt(...args: unknown[]): unknown;
|
||||
|
||||
getAllDirectSessionUnreadCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
getCategoryUnreadCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
getGuildFeedsUnreadCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
setUnVisibleChannelCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
setUnVisibleChannelTypeCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
setVisibleGuildCntInfo(...args: unknown[]): unknown;
|
||||
|
||||
setMsgRead(peer: Peer): Promise<GeneralCallResult>;
|
||||
|
||||
setAllC2CAndGroupMsgRead(): Promise<unknown>;
|
||||
|
||||
setGuildMsgRead(...args: unknown[]): unknown;
|
||||
|
||||
setAllGuildMsgRead(...args: unknown[]): unknown;
|
||||
|
||||
setMsgReadAndReport(...args: unknown[]): unknown;
|
||||
|
||||
setSpecificMsgReadAndReport(...args: unknown[]): unknown;
|
||||
|
||||
setLocalMsgRead(...args: unknown[]): unknown;
|
||||
|
||||
setGroupGuildMsgRead(...args: unknown[]): unknown;
|
||||
|
||||
getGuildGroupTransData(...args: unknown[]): unknown;
|
||||
|
||||
setGroupGuildBubbleRead(...args: unknown[]): unknown;
|
||||
|
||||
getGuildGroupBubble(...args: unknown[]): unknown;
|
||||
|
||||
fetchGroupGuildUnread(...args: unknown[]): unknown;
|
||||
|
||||
setGroupGuildFlag(...args: unknown[]): unknown;
|
||||
|
||||
setGuildUDCFlag(...args: unknown[]): unknown;
|
||||
|
||||
setGuildTabUserFlag(...args: unknown[]): unknown;
|
||||
|
||||
setBuildMode(flag: number/*0 1 3*/): unknown;
|
||||
|
||||
setConfigurationServiceData(...args: unknown[]): unknown;
|
||||
|
||||
setMarkUnreadFlag(...args: unknown[]): unknown;
|
||||
|
||||
getChannelEventFlow(...args: unknown[]): unknown;
|
||||
|
||||
getMsgEventFlow(...args: unknown[]): unknown;
|
||||
|
||||
getRichMediaFilePathForMobileQQSend(...args: unknown[]): unknown;
|
||||
|
||||
getRichMediaFilePathForGuild(arg: {
|
||||
md5HexStr: string,
|
||||
fileName: string,
|
||||
elementType: ElementType,
|
||||
elementSubType: number,
|
||||
thumbSize: 0,
|
||||
needCreate: true,
|
||||
downloadType: 1,
|
||||
file_uuid: ''
|
||||
}): string;
|
||||
|
||||
assembleMobileQQRichMediaFilePath(...args: unknown[]): unknown;
|
||||
|
||||
getFileThumbSavePathForSend(...args: unknown[]): unknown;
|
||||
|
||||
getFileThumbSavePath(...args: unknown[]): unknown;
|
||||
//猜测居多
|
||||
translatePtt2Text(MsgId: string, Peer: {}, MsgElement: {}): unknown;
|
||||
|
||||
setPttPlayedState(...args: unknown[]): unknown;
|
||||
// NodeIQQNTWrapperSession fetchFavEmojiList [
|
||||
// "",
|
||||
// 48,
|
||||
// true,
|
||||
// true
|
||||
// ]
|
||||
fetchFavEmojiList(str: string, num: number, uk1: boolean, uk2: boolean): Promise<GeneralCallResult & {
|
||||
emojiInfoList: Array<{
|
||||
uin: string,
|
||||
emoId: number,
|
||||
emoPath: string,
|
||||
isExist: boolean,
|
||||
resId: string,
|
||||
url: string,
|
||||
md5: string,
|
||||
emoOriginalPath: string,
|
||||
thumbPath: string,
|
||||
RomaingType: string,
|
||||
isAPNG: false,
|
||||
isMarkFace: false,
|
||||
eId: string,
|
||||
epId: string,
|
||||
ocrWord: string,
|
||||
modifyWord: string,
|
||||
exposeNum: number,
|
||||
clickNum: number,
|
||||
desc: string
|
||||
}>
|
||||
}>;
|
||||
|
||||
addFavEmoji(...args: unknown[]): unknown;
|
||||
|
||||
fetchMarketEmoticonList(...args: unknown[]): unknown;
|
||||
|
||||
fetchMarketEmoticonShowImage(...args: unknown[]): unknown;
|
||||
|
||||
fetchMarketEmoticonAioImage(...args: unknown[]): unknown;
|
||||
|
||||
fetchMarketEmotionJsonFile(...args: unknown[]): unknown;
|
||||
|
||||
getMarketEmoticonPath(...args: unknown[]): unknown;
|
||||
|
||||
getMarketEmoticonPathBySync(...args: unknown[]): unknown;
|
||||
|
||||
fetchMarketEmoticonFaceImages(...args: unknown[]): unknown;
|
||||
|
||||
fetchMarketEmoticonAuthDetail(...args: unknown[]): unknown;
|
||||
|
||||
getFavMarketEmoticonInfo(...args: unknown[]): unknown;
|
||||
|
||||
addRecentUsedFace(...args: unknown[]): unknown;
|
||||
|
||||
getRecentUsedFaceList(...args: unknown[]): unknown;
|
||||
|
||||
getMarketEmoticonEncryptKeys(...args: unknown[]): unknown;
|
||||
|
||||
downloadEmojiPic(...args: unknown[]): unknown;
|
||||
|
||||
deleteFavEmoji(...args: unknown[]): unknown;
|
||||
|
||||
modifyFavEmojiDesc(...args: unknown[]): unknown;
|
||||
|
||||
queryFavEmojiByDesc(...args: unknown[]): unknown;
|
||||
|
||||
getHotPicInfoListSearchString(...args: unknown[]): unknown;
|
||||
|
||||
getHotPicSearchResult(...args: unknown[]): unknown;
|
||||
|
||||
getHotPicHotWords(...args: unknown[]): unknown;
|
||||
|
||||
getHotPicJumpInfo(...args: unknown[]): unknown;
|
||||
|
||||
getEmojiResourcePath(...args: unknown[]): unknown;
|
||||
|
||||
JoinDragonGroupEmoji(JoinDragonGroupEmojiReq: any/*joinDragonGroupEmojiReq*/): unknown;
|
||||
|
||||
getMsgAbstracts(...args: unknown[]): unknown;
|
||||
|
||||
getMsgAbstract(...args: unknown[]): unknown;
|
||||
|
||||
getMsgAbstractList(...args: unknown[]): unknown;
|
||||
|
||||
getMsgAbstractListBySeqRange(...args: unknown[]): unknown;
|
||||
|
||||
refreshMsgAbstracts(...args: unknown[]): unknown;
|
||||
|
||||
refreshMsgAbstractsByGuildIds(...args: unknown[]): unknown;
|
||||
|
||||
getRichMediaElement(...args: unknown[]): unknown;
|
||||
|
||||
cancelGetRichMediaElement(...args: unknown[]): unknown;
|
||||
|
||||
refuseGetRichMediaElement(...args: unknown[]): unknown;
|
||||
|
||||
switchToOfflineGetRichMediaElement(...args: unknown[]): unknown;
|
||||
|
||||
downloadRichMedia(...args: unknown[]): unknown;
|
||||
|
||||
getFirstUnreadMsgSeq(args: {
|
||||
peerUid: string
|
||||
guildId: string
|
||||
}): unknown;
|
||||
|
||||
getFirstUnreadCommonMsg(...args: unknown[]): unknown;
|
||||
|
||||
getFirstUnreadAtmeMsg(...args: unknown[]): unknown;
|
||||
|
||||
getFirstUnreadAtallMsg(...args: unknown[]): unknown;
|
||||
|
||||
getNavigateInfo(...args: unknown[]): unknown;
|
||||
|
||||
getChannelFreqLimitInfo(...args: unknown[]): unknown;
|
||||
|
||||
getRecentUseEmojiList(...args: unknown[]): unknown;
|
||||
|
||||
getRecentEmojiList(...args: unknown[]): unknown;
|
||||
|
||||
setMsgEmojiLikes(...args: unknown[]): unknown;
|
||||
|
||||
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<{
|
||||
result: number,
|
||||
errMsg: string,
|
||||
emojiLikesList:
|
||||
Array<{
|
||||
tinyId: string,
|
||||
nickName: string,
|
||||
headUrl: string
|
||||
}>,
|
||||
cookie: string,
|
||||
isLastPage: boolean,
|
||||
isFirstPage: boolean
|
||||
}>;
|
||||
|
||||
setMsgEmojiLikesForRole(...args: unknown[]): unknown;
|
||||
|
||||
clickInlineKeyboardButton(...args: unknown[]): unknown;
|
||||
|
||||
setCurOnScreenMsg(...args: unknown[]): unknown;
|
||||
|
||||
setCurOnScreenMsgForMsgEvent(...args: unknown[]): unknown;
|
||||
|
||||
getMiscData(key: string): unknown;
|
||||
|
||||
setMiscData(key: string, value: string): unknown;
|
||||
|
||||
getBookmarkData(...args: unknown[]): unknown;
|
||||
|
||||
setBookmarkData(...args: unknown[]): unknown;
|
||||
|
||||
sendShowInputStatusReq(ChatType: number, EventType: number, toUid: string): Promise<unknown>;
|
||||
|
||||
queryCalendar(...args: unknown[]): unknown;
|
||||
|
||||
queryFirstMsgSeq(peer: Peer, ...args: unknown[]): unknown;
|
||||
|
||||
queryRoamCalendar(...args: unknown[]): unknown;
|
||||
|
||||
queryFirstRoamMsg(...args: unknown[]): unknown;
|
||||
|
||||
fetchLongMsg(peer: Peer, msgId: string): unknown;
|
||||
|
||||
fetchLongMsgWithCb(...args: unknown[]): unknown;
|
||||
|
||||
setIsStopKernelFetchLongMsg(...args: unknown[]): unknown;
|
||||
|
||||
insertGameResultAsMsgToDb(...args: unknown[]): unknown;
|
||||
|
||||
getMultiMsg(...args: unknown[]): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
}>;
|
||||
|
||||
setDraft(...args: unknown[]): unknown;
|
||||
|
||||
getDraft(...args: unknown[]): unknown;
|
||||
|
||||
deleteDraft(...args: unknown[]): unknown;
|
||||
|
||||
getRecentHiddenSesionList(...args: unknown[]): unknown;
|
||||
|
||||
setRecentHiddenSession(...args: unknown[]): unknown;
|
||||
|
||||
delRecentHiddenSession(...args: unknown[]): unknown;
|
||||
|
||||
getCurHiddenSession(...args: unknown[]): unknown;
|
||||
|
||||
setCurHiddenSession(...args: unknown[]): unknown;
|
||||
|
||||
setReplyDraft(...args: unknown[]): unknown;
|
||||
|
||||
getReplyDraft(...args: unknown[]): unknown;
|
||||
|
||||
deleteReplyDraft(...args: unknown[]): unknown;
|
||||
|
||||
getFirstUnreadAtMsg(peer: Peer): unknown;
|
||||
|
||||
clearMsgRecords(...args: unknown[]): unknown;//设置已读后调用我觉得比较好 清理记录 现在别了
|
||||
|
||||
IsExistOldDb(...args: unknown[]): unknown;
|
||||
|
||||
canImportOldDbMsg(...args: unknown[]): unknown;
|
||||
|
||||
setPowerStatus(z: boolean): unknown;
|
||||
|
||||
canProcessDataMigration(...args: unknown[]): unknown;
|
||||
|
||||
importOldDbMsg(...args: unknown[]): unknown;
|
||||
|
||||
stopImportOldDbMsgAndroid(...args: unknown[]): unknown;
|
||||
|
||||
isMqqDataImportFinished(...args: unknown[]): unknown;
|
||||
|
||||
getMqqDataImportTableNames(...args: unknown[]): unknown;
|
||||
|
||||
getCurChatImportStatusByUin(...args: unknown[]): unknown;
|
||||
|
||||
getDataImportUserLevel(): unknown;
|
||||
|
||||
getMsgQRCode(...args: unknown[]): unknown;
|
||||
|
||||
getGuestMsgAbstracts(...args: unknown[]): unknown;
|
||||
|
||||
getGuestMsgByRange(...args: unknown[]): unknown;
|
||||
|
||||
getGuestMsgAbstractByRange(...args: unknown[]): unknown;
|
||||
|
||||
registerSysMsgNotification(...args: unknown[]): unknown;
|
||||
|
||||
unregisterSysMsgNotification(...args: unknown[]): unknown;
|
||||
|
||||
enterOrExitAio(...args: unknown[]): unknown;
|
||||
|
||||
// this.peerUid = "";
|
||||
// this.peerNickname = "";
|
||||
// this.fromGroupCode = "";
|
||||
// this.sig = new byte[0];
|
||||
// this.selfUid = "";
|
||||
// this.selfPhone = "";
|
||||
// this.chatType = i2;
|
||||
// this.peerUid = str;
|
||||
// this.peerNickname = str2;
|
||||
// this.fromGroupCode = str3;
|
||||
// this.sig = bArr;
|
||||
// this.selfUid = str4;
|
||||
// this.selfPhone = str5;
|
||||
// this.gameSession = tempChatGameSession;
|
||||
prepareTempChat(args: unknown): unknown;//主动临时消息 不做
|
||||
|
||||
sendSsoCmdReqByContend(cmd: string, param: string): Promise<unknown>;
|
||||
|
||||
//chattype,uid->Promise<any>
|
||||
getTempChatInfo(ChatType: number, Uid: string): unknown;
|
||||
|
||||
setContactLocalTop(...args: unknown[]): unknown;
|
||||
|
||||
switchAnonymousChat(...args: unknown[]): unknown;
|
||||
|
||||
renameAnonyChatNick(...args: unknown[]): unknown;
|
||||
|
||||
getAnonymousInfo(...args: unknown[]): unknown;
|
||||
|
||||
updateAnonymousInfo(...args: unknown[]): unknown;
|
||||
|
||||
sendSummonMsg(peer: Peer, MsgElement: unknown, MsgAttributeInfo: unknown): Promise<unknown>;//频道的东西
|
||||
|
||||
outputGuildUnreadInfo(...args: unknown[]): unknown;
|
||||
|
||||
checkMsgWithUrl(...args: unknown[]): unknown;
|
||||
|
||||
checkTabListStatus(...args: unknown[]): unknown;
|
||||
|
||||
getABatchOfContactMsgBoxInfo(...args: unknown[]): unknown;
|
||||
|
||||
insertMsgToMsgBox(peer: Peer, msgId: string, arg: 2006): unknown;
|
||||
|
||||
isHitEmojiKeyword(...args: unknown[]): unknown;
|
||||
|
||||
getKeyWordRelatedEmoji(...args: unknown[]): unknown;
|
||||
|
||||
recordEmoji(...args: unknown[]): unknown;
|
||||
|
||||
fetchGetHitEmotionsByWord(args: Object): Promise<unknown>;//表情推荐?
|
||||
|
||||
deleteAllRoamMsgs(...args: unknown[]): unknown;//漫游消息?
|
||||
|
||||
packRedBag(...args: unknown[]): unknown;
|
||||
|
||||
grabRedBag(...args: unknown[]): unknown;
|
||||
|
||||
pullDetail(...args: unknown[]): unknown;
|
||||
|
||||
selectPasswordRedBag(...args: unknown[]): unknown;
|
||||
|
||||
pullRedBagPasswordList(...args: unknown[]): unknown;
|
||||
|
||||
requestTianshuAdv(...args: unknown[]): unknown;
|
||||
|
||||
tianshuReport(...args: unknown[]): unknown;
|
||||
|
||||
tianshuMultiReport(...args: unknown[]): unknown;
|
||||
|
||||
GetMsgSubType(a0: number, a1: number): unknown;
|
||||
|
||||
setIKernelPublicAccountAdapter(...args: unknown[]): unknown;
|
||||
//tempChatGameSession有关
|
||||
createUidFromTinyId(fromTinyId: string, toTinyId: string): unknown;
|
||||
|
||||
dataMigrationGetDataAvaiableContactList(...args: unknown[]): unknown;
|
||||
|
||||
dataMigrationGetMsgList(...args: unknown[]): unknown;
|
||||
|
||||
dataMigrationStopOperation(...args: unknown[]): unknown;
|
||||
|
||||
//新的希望
|
||||
dataMigrationImportMsgPbRecord(DataMigrationMsgInfo: Array<{
|
||||
extensionData: string//"Hex"
|
||||
extraData: string //""
|
||||
chatType: number
|
||||
chatUin: string
|
||||
msgType: number
|
||||
msgTime: string
|
||||
msgSeq: string
|
||||
msgRandom: string
|
||||
}>, DataMigrationResourceInfo: {
|
||||
extraData: string
|
||||
filePath: string
|
||||
fileSize: string
|
||||
msgRandom: string
|
||||
msgSeq: string
|
||||
msgSubType: number
|
||||
msgType: number
|
||||
}): unknown;
|
||||
|
||||
dataMigrationGetResourceLocalDestinyPath(...args: unknown[]): unknown;
|
||||
|
||||
dataMigrationSetIOSPathPrefix(...args: unknown[]): unknown;
|
||||
|
||||
getServiceAssistantSwitch(...args: unknown[]): unknown;
|
||||
|
||||
setServiceAssistantSwitch(...args: unknown[]): unknown;
|
||||
|
||||
setSubscribeFolderUsingSmallRedPoint(...args: unknown[]): unknown;
|
||||
|
||||
clearGuildNoticeRedPoint(...args: unknown[]): unknown;
|
||||
|
||||
clearFeedNoticeRedPoint(...args: unknown[]): unknown;
|
||||
|
||||
clearFeedSquareRead(...args: unknown[]): unknown;
|
||||
|
||||
IsC2CStyleChatType(...args: unknown[]): unknown;
|
||||
|
||||
IsTempChatType(uin: number): unknown;//猜的
|
||||
|
||||
getGuildInteractiveNotification(...args: unknown[]): unknown;
|
||||
|
||||
getGuildNotificationAbstract(...args: unknown[]): unknown;
|
||||
|
||||
setFocusOnBase(...args: unknown[]): unknown;
|
||||
|
||||
queryArkInfo(...args: unknown[]): unknown;
|
||||
|
||||
queryUserSecQuality(...args: unknown[]): unknown;
|
||||
|
||||
getGuildMsgAbFlag(...args: unknown[]): unknown;
|
||||
|
||||
getGroupMsgStorageTime(): unknown;//这是嘛啊
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { GeneralCallResult } from "./common";
|
||||
|
||||
//没扒干净 因为用不着
|
||||
export interface NodeIKernelNodeMiscService {
|
||||
getMiniAppPath(): unknown;
|
||||
setMiniAppVersion(version:string): unknown;
|
||||
wantWinScreenOCR(imagepath: string): Promise<GeneralCallResult>;
|
||||
SendMiniAppMsg(arg1: string, arg2: string, arg3: string): unknown;
|
||||
startNewMiniApp(appfile: string, params: string): unknown;
|
||||
// 我的计划是转发给一个新程序避免吃掉Electron_AS_Node的环境 然后重写启动MiniApp 挂载相应JS脚本 这样有个问题
|
||||
// 需要自己转发ipc参数 然后必须处在gui环境 且完成校验破解 才能实现发包 有点抽象了
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
export interface NodeIKernelOnlineStatusService {
|
||||
|
||||
addKernelOnlineStatusListener(listener: unknown): void;
|
||||
|
||||
removeKernelOnlineStatusListener(listenerId: unknown): void;
|
||||
|
||||
getShouldShowAIOStatusAnimation(arg: unknown): unknown;
|
||||
|
||||
setReadLikeList(arg: unknown): unknown;
|
||||
|
||||
getLikeList(arg: unknown): unknown;
|
||||
|
||||
setLikeStatus(arg: unknown): unknown;
|
||||
|
||||
getAggregationPageEntrance(): unknown;
|
||||
|
||||
didClickAggregationPageEntrance(): unknown;
|
||||
|
||||
getAggregationGroupModels(): unknown;
|
||||
|
||||
// {
|
||||
// "businessType": 1,
|
||||
// "uins": [
|
||||
// "1627126029",
|
||||
// "66600000",
|
||||
// "71702575"
|
||||
// ]
|
||||
// }
|
||||
|
||||
checkLikeStatus(param: {
|
||||
businessType: number,
|
||||
uins: string[]
|
||||
}): Promise<any>;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { BuddyProfileLikeReq } from "../entities/user";
|
||||
import { GeneralCallResult } from "./common";
|
||||
|
||||
export interface NodeIKernelProfileLikeService {
|
||||
addKernelProfileLikeListener(listener: NodeIKernelProfileLikeService): void;
|
||||
|
||||
removeKernelProfileLikeListener(listener: unknown): void;
|
||||
|
||||
setBuddyProfileLike(...args: unknown[]): { result: number, errMsg: string, succCounts: number };
|
||||
|
||||
getBuddyProfileLike(req: BuddyProfileLikeReq): Promise<GeneralCallResult & {
|
||||
"info": {
|
||||
"userLikeInfos": Array<any>,
|
||||
"friendMaxVotes": number,
|
||||
"start": number
|
||||
}
|
||||
}>;
|
||||
|
||||
getProfileLikeScidResourceInfo(...args: unknown[]): void;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
import { AnyCnameRecord } from 'node:dns';
|
||||
import { BaseInfo, BizKey, CoreInfo, ModifyProfileParams, SimpleInfo, UserDetailInfoByUin } from '../entities';
|
||||
import { NodeIKernelProfileListener } from '../listeners';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
export enum UserDetailSource {
|
||||
KDB,
|
||||
KSERVER
|
||||
}
|
||||
export enum ProfileBizType {
|
||||
KALL,
|
||||
KBASEEXTEND,
|
||||
KVAS,
|
||||
KQZONE,
|
||||
KOTHER
|
||||
}
|
||||
export interface NodeIKernelProfileService {
|
||||
|
||||
getUidByUin(callfrom: string, uin: Array<string>): Promise<Map<string,string>>;//uin->uid
|
||||
|
||||
getUinByUid(callfrom: string, uid: Array<string>): Promise<Map<string,string>>;
|
||||
// {
|
||||
// coreInfo: CoreInfo,
|
||||
// baseInfo: BaseInfo,
|
||||
// status: null,
|
||||
// vasInfo: null,
|
||||
// relationFlags: null,
|
||||
// otherFlags: null,
|
||||
// intimate: null
|
||||
// }
|
||||
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>;
|
||||
|
||||
fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>;
|
||||
|
||||
addKernelProfileListener(listener: NodeIKernelProfileListener): number;
|
||||
|
||||
removeKernelProfileListener(listenerId: number): void;
|
||||
|
||||
prepareRegionConfig(...args: unknown[]): unknown;
|
||||
|
||||
getLocalStrangerRemark(): Promise<AnyCnameRecord>;
|
||||
|
||||
enumCountryOptions(): Array<string>;
|
||||
|
||||
enumProvinceOptions(Country: string): Array<string>;
|
||||
|
||||
enumCityOptions(Country: string, Province: string): unknown;
|
||||
|
||||
enumAreaOptions(...args: unknown[]): unknown;
|
||||
|
||||
//SimpleInfo
|
||||
// this.uid = "";
|
||||
// this.uid = str;
|
||||
// this.uin = j2;
|
||||
// this.isBuddy = z;
|
||||
// this.coreInfo = coreInfo;
|
||||
// this.baseInfo = baseInfo;
|
||||
// this.status = statusInfo;
|
||||
// this.vasInfo = vasInfo;
|
||||
// this.relationFlags = relationFlag;
|
||||
// this.otherFlags = otherFlag;
|
||||
// this.intimate = intimate;
|
||||
|
||||
modifySelfProfile(...args: unknown[]): Promise<unknown>;
|
||||
|
||||
modifyDesktopMiniProfile(param: ModifyProfileParams): Promise<GeneralCallResult>;
|
||||
|
||||
setNickName(NickName: string): Promise<unknown>;
|
||||
|
||||
setLongNick(longNick: string): Promise<unknown>;
|
||||
|
||||
setBirthday(...args: unknown[]): Promise<unknown>;
|
||||
|
||||
setGander(...args: unknown[]): Promise<unknown>;
|
||||
|
||||
setHeader(arg: string): Promise<unknown>;
|
||||
|
||||
setRecommendImgFlag(...args: unknown[]): Promise<unknown>;
|
||||
|
||||
getUserSimpleInfo(force: boolean, uids: string[],): Promise<unknown>;
|
||||
|
||||
getUserDetailInfo(uid: string): Promise<unknown>;
|
||||
|
||||
getUserDetailInfoWithBizInfo(uid: string, Biz: BizKey[]): Promise<GeneralCallResult>;
|
||||
|
||||
getUserDetailInfoByUin(uin: string): Promise<UserDetailInfoByUin>;
|
||||
|
||||
getZplanAvatarInfos(args: string[]): Promise<unknown>;
|
||||
|
||||
getStatus(uid: string): Promise<unknown>;
|
||||
|
||||
startStatusPolling(isForceReset: boolean): Promise<unknown>;
|
||||
|
||||
getSelfStatus(): Promise<unknown>;
|
||||
//
|
||||
setdisableEmojiShortCuts(...args: unknown[]): unknown;
|
||||
|
||||
getProfileQzonePicInfo(uid: string, type: number, force: boolean): Promise<unknown>;
|
||||
|
||||
//profileService.getCoreInfo("UserRemarkServiceImpl::getStrangerRemarkByUid", arrayList);
|
||||
getCoreInfo(name: string, arg: any[]): unknown;
|
||||
//m429253e12.getOtherFlag("FriendListInfoCache_getKernelDataAndPutCache", new ArrayList<>());
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import { ChatType, Peer } from "../entities";
|
||||
import { NodeIKernelRecentContactListener } from "../listeners/NodeIKernelRecentContactListener";
|
||||
import { GeneralCallResult } from "./common";
|
||||
export interface FSABRecentContactParams {
|
||||
anchorPointContact: {
|
||||
contactId: string;
|
||||
sortField: string;
|
||||
pos: number;
|
||||
},
|
||||
relativeMoveCount: number;
|
||||
listType: number;
|
||||
count: number;
|
||||
fetchOld: boolean;
|
||||
}
|
||||
// {
|
||||
// "anchorPointContact": {
|
||||
// "contactId": "",
|
||||
// "sortField": "",
|
||||
// "pos": 0
|
||||
// },
|
||||
// "relativeMoveCount": 0,
|
||||
// "listType": 1,
|
||||
// "count": 200,
|
||||
// "fetchOld": true
|
||||
// }
|
||||
export interface NodeIKernelRecentContactService {
|
||||
setGuildDisplayStatus(...args: unknown[]): unknown; // 2 arguments
|
||||
|
||||
setContactListTop(...args: unknown[]): unknown; // 2 arguments
|
||||
|
||||
updateRecentContactExtBufForUI(...args: unknown[]): unknown; // 2 arguments
|
||||
|
||||
upsertRecentContactManually(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
enterOrExitMsgList(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
/*!---!*/getRecentContactListSnapShot(count: number): Promise<GeneralCallResult & {
|
||||
info: {
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
sortedContactList: Array<number>,
|
||||
changedList: Array<{
|
||||
remark: any;
|
||||
peerName: any;
|
||||
sendMemberName: any;
|
||||
sendNickName: any;
|
||||
peerUid: string; peerUin: string, msgTime: string, chatType: ChatType, msgId: string
|
||||
}>
|
||||
}
|
||||
}>; // 1 arguments
|
||||
|
||||
clearMsgUnreadCount(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
getRecentContactListSyncLimit(count: number): unknown;
|
||||
|
||||
jumpToSpecifyRecentContact(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
/*!---!*/fetchAndSubscribeABatchOfRecentContact(params: FSABRecentContactParams): unknown; // 1 arguments
|
||||
|
||||
addRecentContact(peer: Peer): unknown;
|
||||
|
||||
deleteRecentContacts(peer: Peer): unknown; // 猜测
|
||||
|
||||
getContacts(peers: Peer[]): Promise<unknown>;
|
||||
|
||||
setThirdPartyBusinessInfos(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
updateGameMsgConfigs(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
removeKernelRecentContactListener(listenerid: number): unknown; // 1 arguments
|
||||
|
||||
addKernelRecentContactListener(listener: NodeIKernelRecentContactListener): void;
|
||||
|
||||
clearRecentContactsByChatType(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
upInsertModule(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
jumpToSpecifyRecentContactVer2(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
deleteRecentContactsVer2(...args: unknown[]): unknown; // 1 arguments
|
||||
|
||||
getRecentContactList(): Promise<any>;
|
||||
|
||||
getMsgUnreadCount(): unknown;
|
||||
|
||||
clearRecentContacts(): unknown;
|
||||
|
||||
getServiceAssistantRecentContactInfos(): unknown;
|
||||
|
||||
getRecentContactInfos(): unknown;
|
||||
|
||||
getUnreadDetailsInfos(): unknown;
|
||||
|
||||
cleanAllModule(): unknown;
|
||||
|
||||
setAllGameMsgRead(): unknown;
|
||||
|
||||
getRecentContactListSync(): unknown;
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
import { GetFileListParam, MessageElement, Peer, SendMessageElement } from "../entities";
|
||||
import { GeneralCallResult } from "./common";
|
||||
export enum UrlFileDownloadType {
|
||||
KUNKNOWN,
|
||||
KURLFILEDOWNLOADPRIVILEGEICON,
|
||||
KURLFILEDOWNLOADPHOTOWALL,
|
||||
KURLFILEDOWNLOADQZONE,
|
||||
KURLFILEDOWNLOADCOMMON,
|
||||
KURLFILEDOWNLOADINSTALLAPP
|
||||
}
|
||||
export enum RMBizTypeEnum {
|
||||
KUNKNOWN,
|
||||
KC2CFILE,
|
||||
KGROUPFILE,
|
||||
KC2CPIC,
|
||||
KGROUPPIC,
|
||||
KDISCPIC,
|
||||
KC2CVIDEO,
|
||||
KGROUPVIDEO,
|
||||
KC2CPTT,
|
||||
KGROUPPTT,
|
||||
KFEEDCOMMENTPIC,
|
||||
KGUILDFILE,
|
||||
KGUILDPIC,
|
||||
KGUILDPTT,
|
||||
KGUILDVIDEO
|
||||
}
|
||||
export interface CommonFileInfo {
|
||||
bizType: number;
|
||||
chatType: number;
|
||||
elemId: string;
|
||||
favId: string;
|
||||
fileModelId: string;
|
||||
fileName: string;
|
||||
fileSize: string;
|
||||
md5: string;
|
||||
md510m: string;
|
||||
msgId: string;
|
||||
msgTime: string;
|
||||
parent: string;
|
||||
peerUid: string;
|
||||
picThumbPath: Array<string>
|
||||
sha: string;
|
||||
sha3: string;
|
||||
subId: string;
|
||||
uuid: string;
|
||||
}
|
||||
export interface NodeIKernelRichMediaService {
|
||||
//getVideoPlayUrl(peer, msgId, elemId, videoCodecFormat, VideoRequestWay.KHAND, cb);
|
||||
// public enum VideoCodecFormatType {
|
||||
// KCODECFORMATH264,
|
||||
// KCODECFORMATH265,
|
||||
// KCODECFORMATH266,
|
||||
// KCODECFORMATAV1
|
||||
// }
|
||||
// public enum VideoRequestWay {
|
||||
// KUNKNOW,
|
||||
// KHAND,
|
||||
// KAUTO
|
||||
// }
|
||||
getVideoPlayUrl(peer: Peer, msgId: string, elemId: string, videoCodecFormat: number, VideoRequestWay: number): Promise<unknown>;
|
||||
|
||||
//exParams (RMReqExParams)
|
||||
// this.downSourceType = i2;
|
||||
// this.triggerType = i3;
|
||||
//peer, msgId, elemId, videoCodecFormat, exParams
|
||||
// 1 0 频道在用
|
||||
// 1 1
|
||||
// 0 2
|
||||
|
||||
// public static final int KCOMMONREDENVELOPEMSGTYPEINMSGBOX = 1007;
|
||||
// public static final int KDOWNSOURCETYPEAIOINNER = 1;
|
||||
// public static final int KDOWNSOURCETYPEBIGSCREEN = 2;
|
||||
// public static final int KDOWNSOURCETYPEHISTORY = 3;
|
||||
// public static final int KDOWNSOURCETYPEUNKNOWN = 0;
|
||||
|
||||
// public static final int KTRIGGERTYPEAUTO = 1;
|
||||
// public static final int KTRIGGERTYPEMANUAL = 0;
|
||||
|
||||
getVideoPlayUrlV2(peer: Peer, msgId: string, elemId: string, videoCodecFormat: number, exParams: { downSourceType: number, triggerType: number }): Promise<GeneralCallResult & {
|
||||
urlResult: {
|
||||
v4IpUrl: [],
|
||||
v6IpUrl: [],
|
||||
domainUrl: Array<{
|
||||
url: string,
|
||||
isHttps: boolean,
|
||||
httpsDomain: string
|
||||
}>,
|
||||
videoCodecFormat: number
|
||||
}
|
||||
}>;
|
||||
|
||||
getRichMediaFileDir(elementType: number, downType: number, isTemp: boolean): unknown;
|
||||
|
||||
// this.senderUid = "";
|
||||
// this.peerUid = "";
|
||||
// this.guildId = "";
|
||||
// this.elem = new MsgElement();
|
||||
// this.downloadType = i2;
|
||||
// this.thumbSize = i3;
|
||||
// this.msgId = j2;
|
||||
// this.msgRandom = j3;
|
||||
// this.msgSeq = j4;
|
||||
// this.msgTime = j5;
|
||||
// this.chatType = i4;
|
||||
// this.senderUid = str;
|
||||
// this.peerUid = str2;
|
||||
// this.guildId = str3;
|
||||
// this.elem = msgElement;
|
||||
// this.useHttps = num;
|
||||
|
||||
getVideoPlayUrlInVisit(arg: {
|
||||
downloadType: number,
|
||||
thumbSize: number,
|
||||
msgId: string,
|
||||
msgRandom: string,
|
||||
msgSeq: string,
|
||||
msgTime: string,
|
||||
chatType: number,
|
||||
senderUid: string,
|
||||
peerUid: string,
|
||||
guildId: string,
|
||||
ele: MessageElement,
|
||||
useHttps: boolean
|
||||
}): Promise<unknown>;
|
||||
|
||||
//arg双端number
|
||||
isFileExpired(arg: number): unknown;
|
||||
|
||||
deleteGroupFolder(GroupCode: string, FolderId: string): Promise<GeneralCallResult & { groupFileCommonResult: { retCode: number, retMsg: string, clientWording: string } }>;
|
||||
|
||||
//参数与getVideoPlayUrlInVisit一样
|
||||
downloadRichMediaInVisit(arg: {
|
||||
downloadType: number,
|
||||
thumbSize: number,
|
||||
msgId: string,
|
||||
msgRandom: string,
|
||||
msgSeq: string,
|
||||
msgTime: string,
|
||||
chatType: number,
|
||||
senderUid: string,
|
||||
peerUid: string,
|
||||
guildId: string,
|
||||
ele: MessageElement,
|
||||
useHttps: boolean
|
||||
}): unknown;
|
||||
//arg3为“”
|
||||
downloadFileForModelId(peer: Peer, ModelId: string[], arg3: string): unknown;
|
||||
//第三个参数 Array<Type>
|
||||
// this.fileId = "";
|
||||
// this.fileName = "";
|
||||
// this.fileId = str;
|
||||
// this.fileName = str2;
|
||||
// this.fileSize = j2;
|
||||
// this.fileModelId = j3;
|
||||
|
||||
downloadFileForFileUuid(peer: Peer, uuid: string, arg3: {
|
||||
fileId: string,
|
||||
fileName: string,
|
||||
fileSize: string,
|
||||
fileModelId: string
|
||||
}[]): Promise<unknown>;
|
||||
|
||||
downloadFileByUrlList(fileDownloadTyp: UrlFileDownloadType, urlList: Array<string>): unknown;
|
||||
|
||||
downloadFileForFileInfo(fileInfo: CommonFileInfo[], savePath: string): unknown;
|
||||
|
||||
createGroupFolder(GroupCode: string, FolderName: string): Promise<GeneralCallResult & { resultWithGroupItem: { result: any, groupItem: Array<any> } }>
|
||||
|
||||
downloadFile(commonFile: CommonFileInfo, arg2: unknown, arg3: unknown, savePath: string): unknown;
|
||||
|
||||
createGroupFolder(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
downloadGroupFolder(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
renameGroupFolder(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
deleteGroupFolder(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
deleteTransferInfo(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
cancelTransferTask(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
cancelUrlDownload(arg: unknown): unknown;
|
||||
|
||||
updateOnlineVideoElemStatus(arg: unknown): unknown;
|
||||
|
||||
getGroupSpace(arg: unknown): unknown;
|
||||
|
||||
getGroupFileList(groupCode: string, params: GetFileListParam): Promise<GeneralCallResult & {
|
||||
groupSpaceResult: {
|
||||
retCode: number
|
||||
retMsg: string
|
||||
clientWording: string
|
||||
totalSpace: number
|
||||
usedSpace: number
|
||||
allUpload: boolean
|
||||
}
|
||||
}>;
|
||||
|
||||
getGroupFileInfo(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
getGroupTransferList(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
renameGroupFile(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown, arg5: unknown): unknown;
|
||||
|
||||
moveGroupFile(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown, arg5: unknown): unknown;
|
||||
|
||||
transGroupFile(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
searchGroupFile(
|
||||
keywords: Array<string>,
|
||||
param: {
|
||||
groupIds: Array<string>,
|
||||
fileType: number,
|
||||
context: string,
|
||||
count: number,
|
||||
sortType: number,
|
||||
groupNames: Array<string>
|
||||
}): Promise<unknown>;
|
||||
searchGroupFileByWord(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown, arg5: unknown): unknown;
|
||||
|
||||
deleteGroupFile(GroupCode: string, params: Array<number>, Files: Array<string>): Promise<GeneralCallResult & {
|
||||
transGroupFileResult: {
|
||||
result: any
|
||||
successFileIdList: Array<any>
|
||||
failFileIdList: Array<any>
|
||||
}
|
||||
}>;
|
||||
|
||||
translateEnWordToZn(words: string[]): Promise<GeneralCallResult & { words: string[] }>;
|
||||
|
||||
getScreenOCR(path: string): Promise<unknown>;
|
||||
|
||||
batchGetGroupFileCount(Gids: Array<string>): Promise<GeneralCallResult & { groupCodes: Array<string>, groupFileCounts: Array<number> }>;
|
||||
|
||||
queryPicDownloadSize(arg: unknown): unknown;
|
||||
|
||||
searchGroupFile(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
searchMoreGroupFile(arg: unknown): unknown;
|
||||
|
||||
cancelSearcheGroupFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
onlyDownloadFile(peer: Peer, arg2: unknown, arg3: Array<{
|
||||
fileId: string,
|
||||
fileName: string,
|
||||
fileSize: string,
|
||||
fileModelId: string
|
||||
}
|
||||
>): unknown;
|
||||
|
||||
onlyUploadFile(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
isExtraLargePic(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
uploadRMFileWithoutMsg(arg: {
|
||||
bizType: RMBizTypeEnum,
|
||||
filePath: string,
|
||||
peerUid: string,
|
||||
transferId: string
|
||||
useNTV2: string
|
||||
}): Promise<unknown>;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { NodeIKernelRobotListener } from "@/core/listeners";
|
||||
|
||||
export interface NodeIKernelRobotService {
|
||||
fetchGroupRobotStoreDiscovery(arg: unknown): unknown;
|
||||
|
||||
sendGroupRobotStoreSearch(arg: unknown): unknown;
|
||||
|
||||
fetchGroupRobotStoreCategoryList(arg: unknown): unknown;
|
||||
|
||||
FetchSubscribeMsgTemplate(arg: unknown): unknown;
|
||||
|
||||
FetchSubcribeMsgTemplateStatus(arg: unknown): unknown;
|
||||
|
||||
SubscribeMsgTemplateSet(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
fetchRecentUsedRobots(arg: unknown): unknown;
|
||||
|
||||
fetchShareArkInfo(arg: unknown): unknown;
|
||||
|
||||
addKernelRobotListener(Listener: NodeIKernelRobotListener): number;
|
||||
|
||||
removeKernelRobotListener(ListenerId: number): unknown;
|
||||
|
||||
getAllRobotFriendsFromCache(): Promise<unknown>;
|
||||
|
||||
fetchAllRobots(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
removeAllRecommendCache(): unknown;
|
||||
|
||||
setRobotPickTts(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
getRobotUinRange(data: any): Promise<{ response: { robotUinRanges: any } }>
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
import { ChatType } from "../entities";
|
||||
|
||||
export interface NodeIKernelSearchService {
|
||||
addKernelSearchListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
removeKernelSearchListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
searchStranger(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchGroup(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
searchLocalInfo(keywords: string, unknown: number/*4*/): unknown;
|
||||
|
||||
cancelSearchLocalInfo(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchBuddyChatInfo(...args: any[]): unknown;// needs 2 arguments
|
||||
|
||||
searchMoreBuddyChatInfo(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchBuddyChatInfo(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchContact(...args: any[]): unknown;// needs 2 arguments
|
||||
|
||||
searchMoreContact(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchContact(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchGroupChatInfo(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
resetSearchGroupChatInfoSortType(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
resetSearchGroupChatInfoFilterMembers(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchMoreGroupChatInfo(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchGroupChatInfo(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchChatsWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchMoreChatsWithKeywords(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchChatsWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchChatMsgs(...args: any[]): unknown;// needs 2 arguments
|
||||
|
||||
searchMoreChatMsgs(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchChatMsgs(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchMsgWithKeywords(...args: any[]): unknown;// needs 2 arguments
|
||||
|
||||
searchMoreMsgWithKeywords(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchMsgWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchFileWithKeywords(keywords: string[], source: number): Promise<string>;// needs 2 arguments
|
||||
|
||||
searchMoreFileWithKeywords(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchFileWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchAtMeChats(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchMoreAtMeChats(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchAtMeChats(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
searchChatAtMeMsgs(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
searchMoreChatAtMeMsgs(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
cancelSearchChatAtMeMsgs(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
addSearchHistory(param: {
|
||||
type: number,//4
|
||||
contactList: [],
|
||||
id: number,//-1
|
||||
groupInfos: [],
|
||||
msgs: [],
|
||||
fileInfos: [
|
||||
{
|
||||
chatType: ChatType,
|
||||
buddyChatInfo: Array<{ category_name: string, peerUid: string, peerUin: string, remark: string }>,
|
||||
discussChatInfo: [],
|
||||
groupChatInfo: Array<
|
||||
{
|
||||
groupCode: string,
|
||||
isConf: boolean,
|
||||
hasModifyConfGroupFace: boolean,
|
||||
hasModifyConfGroupName: boolean,
|
||||
groupName: string,
|
||||
remark: string
|
||||
}>
|
||||
,
|
||||
dataLineChatInfo: [],
|
||||
tmpChatInfo: [],
|
||||
msgId: string,
|
||||
msgSeq: string,
|
||||
msgTime: string,
|
||||
senderUid: string,
|
||||
senderNick: string,
|
||||
senderRemark: string,
|
||||
senderCard: string,
|
||||
elemId: string,
|
||||
elemType: string,//3
|
||||
fileSize: string,
|
||||
filePath: string,
|
||||
fileName: string,
|
||||
hits: Array<
|
||||
{
|
||||
start: 12,
|
||||
end: 14
|
||||
}
|
||||
>
|
||||
}
|
||||
]
|
||||
|
||||
}): Promise<{
|
||||
result: number,
|
||||
errMsg: string,
|
||||
id?: number
|
||||
}>;
|
||||
|
||||
removeSearchHistory(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
searchCache(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
clearSearchCache(...args: any[]): unknown;// needs 1 arguments
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { NodeIKernelStorageCleanListener } from "@/core/listeners";
|
||||
import { GeneralCallResult } from "./common";
|
||||
|
||||
export interface NodeIKernelStorageCleanService {
|
||||
|
||||
addKernelStorageCleanListener(Listener: NodeIKernelStorageCleanListener): number;
|
||||
|
||||
removeKernelStorageCleanListener(ListenerId: number): void;
|
||||
|
||||
addCacheScanedPaths(arg: unknown): unknown;
|
||||
|
||||
addFilesScanedPaths(arg: unknown): unknown;
|
||||
|
||||
scanCache(): Promise<GeneralCallResult & {
|
||||
size: string[]
|
||||
}>;
|
||||
|
||||
addReportData(arg: unknown): unknown;
|
||||
|
||||
reportData(): unknown;
|
||||
|
||||
getChatCacheInfo(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown): unknown;
|
||||
|
||||
getFileCacheInfo(arg1: unknown, arg2: unknown, arg3: unknown, arg44: unknown, args5: unknown): unknown;
|
||||
|
||||
clearChatCacheInfo(arg1: unknown, arg2: unknown): unknown;
|
||||
|
||||
clearCacheDataByKeys(arg: unknown): unknown;
|
||||
|
||||
setSilentScan(arg: unknown): unknown;
|
||||
|
||||
closeCleanWindow(): unknown;
|
||||
|
||||
clearAllChatCacheInfo(): unknown;
|
||||
|
||||
endScan(arg: unknown): unknown;
|
||||
|
||||
addNewDownloadOrUploadFile(arg: unknown): unknown;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export interface NodeIKernelTianShuService {
|
||||
addKernelTianShuListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
removeKernelTianShuListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
requesTianShuNumeralRe(...args: any[]): unknown;//d needs 1 arguments
|
||||
|
||||
reportTianShuNumeralRed(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { forceFetchClientKeyRetType } from "./common";
|
||||
|
||||
export interface NodeIKernelTicketService {
|
||||
|
||||
addKernelTicketListener(listener: unknown): void;
|
||||
|
||||
removeKernelTicketListener(listenerId: unknown): void;
|
||||
|
||||
forceFetchClientKey(arg: string): Promise<forceFetchClientKeyRetType>;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { GeneralCallResult } from "./common";
|
||||
|
||||
export interface NodeIKernelTipOffService {
|
||||
|
||||
addKernelTipOffListener(listener: unknown): void;
|
||||
|
||||
removeKernelTipOffListener(listenerId: unknown): void;
|
||||
|
||||
tipOffSendJsData(args: unknown[]): Promise<unknown>;//2
|
||||
|
||||
getPskey(domainList: string[], nocache: boolean): Promise<GeneralCallResult & { domainPskeyMap: Map<string, string> }>;//2
|
||||
|
||||
tipOffSendJsData(args: unknown[]): Promise<unknown>;//2
|
||||
|
||||
tipOffMsgs(args: unknown[]): Promise<unknown>;//1
|
||||
|
||||
encodeUinAesInfo(args: unknown[]): Promise<unknown>;//2
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export interface NodeIKernelUixConvertService {
|
||||
getUin(uid: string[]): Promise<{ uinInfo: Map<string, string> }>;
|
||||
|
||||
getUid(uin: string[]): Promise<{ uidInfo: Map<string, string> }>;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
export interface NodeIKernelUnitedConfigService{
|
||||
addKernelUnitedConfigListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
removeKernelUnitedConfigListener(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
fetchUnitedCommendConfig(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
fetchUnitedSwitchConfig(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
loadUnitedConfig(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
isUnitedConfigSwitchOn(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
registerUnitedConfigPushGroupList(...args: any[]): unknown;// needs 1 arguments
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// public interface IYellowFaceForManagerService extends QRouteApi {
|
||||
// void download(@NotNull String resourceConfigJson, @NotNull String resourceDir, @NotNull String cacheDir, boolean force, @NotNull IKernelYellowFaceDownloadCallback callback);
|
||||
|
||||
// void setHistory(@NotNull String fullMd5, @NotNull IOperateCallback callback);
|
||||
// }
|
||||
@@ -1,14 +0,0 @@
|
||||
import { MessageElement, Peer } from "../entities";
|
||||
|
||||
export interface NodeIkernelTestPerformanceService {
|
||||
insertMsg(MsgParam: {
|
||||
peer: Peer
|
||||
msgTime: string
|
||||
msgId: string
|
||||
msgSeq: string
|
||||
batchNums: number
|
||||
timesPerBatch: number
|
||||
numPerTime: number
|
||||
}, msg: Array<MessageElement>): Promise<unknown>;
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
export enum GeneralCallResultStatus {
|
||||
OK = 0,
|
||||
// ERROR = 1,
|
||||
}
|
||||
export interface GeneralCallResult{
|
||||
result: GeneralCallResultStatus,
|
||||
errMsg: string
|
||||
}
|
||||
export interface forceFetchClientKeyRetType extends GeneralCallResult {
|
||||
url: string;
|
||||
keyIndex: string;
|
||||
clientKey: string;
|
||||
expireTime: string;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
export * from './common';
|
||||
export * from './NodeIKernelAvatarService';
|
||||
export * from './NodeIKernelBuddyService';
|
||||
export * from './NodeIKernelFileAssistantService';
|
||||
export * from './NodeIKernelGroupService';
|
||||
export * from './NodeIKernelLoginService';
|
||||
export * from './NodeIKernelMsgService';
|
||||
export * from './NodeIKernelOnlineStatusService';
|
||||
export * from './NodeIKernelProfileLikeService';
|
||||
export * from './NodeIKernelProfileService';
|
||||
export * from './NodeIKernelTicketService';
|
||||
export * from './NodeIKernelStorageCleanService';
|
||||
export * from './NodeIKernelRobotService';
|
||||
export * from './NodeIKernelRichMediaService';
|
||||
export * from './NodeIKernelDbToolsService';
|
||||
export * from './NodeIKernelTipOffService'
|
||||
@@ -1,130 +0,0 @@
|
||||
import { getFullQQVesion, QQVersionAppid } from '@/common/utils/QQBasicInfo';
|
||||
import { hostname, systemName, systemVersion } from '@/common/utils/system';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { getMachineId } from '@/common/utils/system';
|
||||
// 补充
|
||||
export enum PlatformType {
|
||||
KUNKNOWN,
|
||||
KANDROID,
|
||||
KIOS,
|
||||
KWINDOWS,
|
||||
KMAC
|
||||
}
|
||||
export enum DeviceType {
|
||||
KUNKNOWN,
|
||||
KPHONE,
|
||||
KPAD,
|
||||
KCOMPUTER
|
||||
}
|
||||
//推送类型
|
||||
export enum VendorType {
|
||||
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":{}}'
|
||||
}
|
||||
|
||||
export const sessionConfig: WrapperSessionInitConfig | any = {};
|
||||
|
||||
export async function genSessionConfig(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
|
||||
//console.log(guid);
|
||||
// guid = '52afb776-82f6-4e59-9d38-44705b112d0a';
|
||||
//let guid: string = await getMachineId();
|
||||
const config: WrapperSessionInitConfig = {
|
||||
selfUin,
|
||||
selfUid,
|
||||
desktopPathConfig: {
|
||||
account_path // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
|
||||
},
|
||||
clientVer: getFullQQVesion(), // 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: getFullQQVesion(),
|
||||
localId: 2052,
|
||||
devName: hostname,
|
||||
devType: systemName,
|
||||
vendorName: '',
|
||||
osVer: systemVersion,
|
||||
vendorOsName: systemName,
|
||||
setMute: false,
|
||||
vendorType: VendorType.KNOSETONIOS
|
||||
},
|
||||
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}'
|
||||
};
|
||||
Object.assign(sessionConfig, config);
|
||||
return config;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { enableConsoleLog, enableFileLog, logDebug, logError, LogLevel, setLogLevel } from '@/common/utils/log';
|
||||
import { ConfigBase } from '@/common/utils/ConfigBase';
|
||||
import { selfInfo } from '@/core/data';
|
||||
|
||||
|
||||
export interface NapCatConfig {
|
||||
fileLog: boolean,
|
||||
consoleLog: boolean,
|
||||
fileLogLevel: LogLevel,
|
||||
consoleLogLevel: LogLevel,
|
||||
}
|
||||
|
||||
class Config extends ConfigBase<NapCatConfig> implements NapCatConfig {
|
||||
name: string = 'napcat'
|
||||
fileLog = true;
|
||||
consoleLog = true;
|
||||
fileLogLevel = LogLevel.DEBUG;
|
||||
consoleLogLevel = LogLevel.INFO;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export const napCatConfig = new Config();
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
//远端rkey获取
|
||||
import { logError } from '@/common/utils/log';
|
||||
import { RequestUtil } from '@/common/utils/request';
|
||||
|
||||
interface ServerRkeyData {
|
||||
group_rkey: string;
|
||||
private_rkey: string;
|
||||
expired_time: number;
|
||||
}
|
||||
|
||||
class RkeyManager {
|
||||
serverUrl: string = '';
|
||||
private rkeyData: ServerRkeyData = {
|
||||
group_rkey: '',
|
||||
private_rkey: '',
|
||||
expired_time: 0
|
||||
};
|
||||
constructor(serverUrl: string) {
|
||||
this.serverUrl = serverUrl;
|
||||
}
|
||||
async getRkey() {
|
||||
if (this.isExpired()) {
|
||||
try {
|
||||
await this.refreshRkey();
|
||||
} catch (e) {
|
||||
logError('获取rkey失败', e);
|
||||
}
|
||||
}
|
||||
return this.rkeyData;
|
||||
}
|
||||
|
||||
isExpired(): boolean {
|
||||
const now = new Date().getTime() / 1000;
|
||||
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`);
|
||||
return now > this.rkeyData.expired_time;
|
||||
}
|
||||
async refreshRkey(): Promise<any> {
|
||||
//刷新rkey
|
||||
this.rkeyData = await RequestUtil.HttpGetJson<ServerRkeyData>(this.serverUrl, 'GET');
|
||||
}
|
||||
}
|
||||
export const rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey');
|
||||
@@ -1,300 +0,0 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { WrapperSessionInitConfig } from './sessionConfig';
|
||||
import {
|
||||
NodeIDependsAdapter,
|
||||
NodeIDispatcherAdapter,
|
||||
NodeIGlobalAdapter,
|
||||
} from './adapters';
|
||||
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 { dirname } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
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';
|
||||
import { getFullQQVesion } from '@/common/utils/QQBasicInfo';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export interface NodeQQNTWrapperUtil {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeQQNTWrapperUtil
|
||||
|
||||
getNTUserDataInfoConfig(): string
|
||||
|
||||
emptyWorkingSet(n: number): void
|
||||
|
||||
getSsoCmdOfOidbReq(arg1: number, arg2: number): unknown,
|
||||
|
||||
getSsoBufferOfOidbReq(...args: unknown[]): unknown,//有点看不懂参数定义 待补充 好像是三个参数
|
||||
|
||||
getOidbRspInfo(arg: string): unknown,//可能是错的
|
||||
|
||||
getFileSize(path: string): Promise<number>,//直接的猜测
|
||||
|
||||
genFileMd5Buf(arg: string): unknown,//可能是错的
|
||||
|
||||
genFileMd5Hex(path: string): unknown,//直接的猜测
|
||||
|
||||
genFileShaBuf(path: string): unknown,//直接的猜测
|
||||
|
||||
genFileCumulateSha1(path: string): unknown,//直接的猜测
|
||||
|
||||
genFileShaHex(path: string): unknown,//直接的猜测
|
||||
|
||||
fileIsExist(path: string): unknown,
|
||||
|
||||
startTrace(path: string): unknown,//可能是错的
|
||||
|
||||
copyFile(src: string, dst: string): unknown,
|
||||
|
||||
genFileShaAndMd5Hex(path: string, unknown: number): unknown,//可能是错的
|
||||
|
||||
setTraceInfo(unknown: Object): unknown,
|
||||
|
||||
encodeOffLine(unknown: Object): unknown,
|
||||
|
||||
decodeOffLine(arg: string): unknown,//可能是错的 传递hex
|
||||
|
||||
DecoderRecentInfo(arg: string): unknown,//可能是错的 传递hex
|
||||
|
||||
getPinyin(arg0: string, arg1: boolean): unknown,
|
||||
|
||||
matchInPinyin(arg0: any[], arg1: string): unknown,//参数特复杂 arg0是个复杂数据类型
|
||||
|
||||
makeDirByPath(arg0: string): unknown,
|
||||
|
||||
emptyWorkingSet(arg0: number): unknown,//参数是UINT32
|
||||
|
||||
runProcess(arg0: string, arg1: boolean): unknown,
|
||||
|
||||
runProcessArgs(arg0: string, arg1: { [key: string]: string; }, arg2: boolean): unknown,
|
||||
|
||||
calcThumbSize(arg0: number, arg1: number, arg2: Object): unknown,
|
||||
|
||||
fullWordToHalfWord(arg0: string): unknown,
|
||||
|
||||
getNTUserDataInfoConfig(): unknown,
|
||||
|
||||
pathIsReadableAndWriteable(path: string): unknown,//直接的猜测
|
||||
|
||||
resetUserDataSavePathToDocument(): unknown,
|
||||
|
||||
getSoBuildInfo(): any,//例如 0[0]_d491dc01e0a_0
|
||||
|
||||
registerCountInstruments(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,
|
||||
|
||||
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,
|
||||
|
||||
checkNewUserDataSaveDirAvailable(arg0: string): unknown,
|
||||
|
||||
copyUserData(arg0: string, arg1: string): Promise<any>,
|
||||
|
||||
setUserDataSaveDirectory(arg0: string): Promise<any>,
|
||||
|
||||
hasOtherRunningQQProcess(): boolean,
|
||||
|
||||
quitAllRunningQQProcess(arg: boolean): unknown,
|
||||
|
||||
checkNvidiaConfig(): unknown,
|
||||
|
||||
repairNvidiaConfig(): unknown,
|
||||
|
||||
getNvidiaDriverVersion(): unknown,
|
||||
|
||||
isNull(): unknown
|
||||
}
|
||||
|
||||
export interface NodeIQQNTWrapperSession {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeIQQNTWrapperSession;
|
||||
|
||||
init(
|
||||
wrapperSessionInitConfig: WrapperSessionInitConfig,
|
||||
nodeIDependsAdapter: NodeIDependsAdapter,
|
||||
nodeIDispatcherAdapter: NodeIDispatcherAdapter,
|
||||
nodeIKernelSessionListener: NodeIKernelSessionListener
|
||||
): void;
|
||||
|
||||
startNT(n: 0): void;
|
||||
|
||||
startNT(): void;
|
||||
|
||||
getBdhUploadService(): unknown;
|
||||
|
||||
getECDHService(): NodeIKernelECDHService;
|
||||
|
||||
getMsgService(): NodeIKernelMsgService;
|
||||
|
||||
getProfileService(): NodeIKernelProfileService;
|
||||
|
||||
getProfileLikeService(): NodeIKernelProfileLikeService;
|
||||
|
||||
getGroupService(): NodeIKernelGroupService;
|
||||
|
||||
getStorageCleanService(): NodeIKernelStorageCleanService;
|
||||
|
||||
getBuddyService(): NodeIKernelBuddyService;
|
||||
|
||||
getRobotService(): NodeIKernelRobotService;
|
||||
|
||||
getTicketService(): NodeIKernelTicketService;
|
||||
|
||||
getTipOffService(): NodeIKernelTipOffService;
|
||||
|
||||
getNodeMiscService(): NodeIKernelNodeMiscService;
|
||||
|
||||
getRichMediaService(): NodeIKernelRichMediaService;
|
||||
|
||||
getMsgBackupService(): NodeIKernelMsgBackupService;
|
||||
|
||||
getAlbumService(): NodeIKernelAlbumService;
|
||||
|
||||
getTianShuService(): NodeIKernelTianShuService;
|
||||
|
||||
getUnitedConfigService(): NodeIKernelUnitedConfigService;
|
||||
|
||||
getSearchService(): NodeIKernelSearchService;
|
||||
|
||||
getDirectSessionService(): unknown;
|
||||
|
||||
getRDeliveryService(): unknown;
|
||||
|
||||
getAvatarService(): NodeIKernelAvatarService;
|
||||
|
||||
getFeedChannelService(): unknown;
|
||||
|
||||
getYellowFaceService(): unknown;
|
||||
|
||||
getCollectionService(): NodeIKernelCollectionService;
|
||||
|
||||
getSettingService(): unknown;
|
||||
|
||||
getQiDianService(): unknown;
|
||||
|
||||
getFileAssistantService(): unknown;
|
||||
|
||||
getGuildService(): unknown;
|
||||
|
||||
getSkinService(): unknown;
|
||||
|
||||
getTestPerformanceService(): NodeIkernelTestPerformanceService;
|
||||
|
||||
getQQPlayService(): unknown;
|
||||
|
||||
getDbToolsService(): unknown;
|
||||
|
||||
getUixConvertService(): NodeIKernelUixConvertService;
|
||||
|
||||
getOnlineStatusService(): unknown;
|
||||
|
||||
getRemotingService(): unknown;
|
||||
|
||||
getGroupTabService(): unknown;
|
||||
|
||||
getGroupSchoolService(): unknown;
|
||||
|
||||
getLiteBusinessService(): unknown;
|
||||
|
||||
getGuildMsgService(): unknown;
|
||||
|
||||
getLockService(): unknown;
|
||||
|
||||
getMSFService(): NodeIKernelMSFService;
|
||||
|
||||
getGuildHotUpdateService(): unknown;
|
||||
|
||||
getAVSDKService(): 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 }
|
||||
}
|
||||
|
||||
export interface NodeIQQNTWrapperEngine {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeIQQNTWrapperEngine;
|
||||
|
||||
initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void;
|
||||
}
|
||||
|
||||
export interface WrapperNodeApi {
|
||||
[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;
|
||||
}
|
||||
|
||||
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/${getFullQQVesion()}/wrapper.node`);
|
||||
}
|
||||
const nativemodule: any = { exports: {} };
|
||||
process.dlopen(nativemodule, wrapperNodePath);
|
||||
const QQWrapper: WrapperNodeApi = nativemodule.exports;
|
||||
export default QQWrapper;
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "./dist",
|
||||
"declaration": true,
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "Node",
|
||||
"experimentalDecorators": true,
|
||||
"allowImportingTsExtensions": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": false,
|
||||
"jsx": "preserve",
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@/common/*": [
|
||||
"../common/*"
|
||||
],
|
||||
"@/core": [
|
||||
"./src/index"
|
||||
],
|
||||
"@/core/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
import { UserConfig, defineConfig } from 'vite';
|
||||
import { builtinModules } from 'module';
|
||||
import obfuscator from 'rollup-plugin-obfuscator';
|
||||
import { Plugin } from 'vite';
|
||||
import path from 'node:path';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import cp from 'vite-plugin-cp';
|
||||
import babel from 'vite-plugin-babel';
|
||||
|
||||
const external: string[] = [ /* Empty */];
|
||||
const nodeModules = [...builtinModules, builtinModules.map(m => `node:${m}`)].flat();
|
||||
|
||||
const baseConfig: UserConfig = {
|
||||
build: {
|
||||
target: 'modules',
|
||||
outDir: './',
|
||||
lib: {
|
||||
name: '@napneko/core',
|
||||
entry: 'src/index.ts',
|
||||
formats: ['es'],
|
||||
fileName: () => 'index.js',
|
||||
},
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: path.resolve(__dirname, 'src/index.ts'),
|
||||
qqnt: path.resolve(__dirname, 'src/qqnt/index.ts'),
|
||||
'qqnt/apis': path.resolve(__dirname, 'src/qqnt/apis/index.ts'),
|
||||
'qqnt/listeners': path.resolve(__dirname, 'src/qqnt/listeners/index.ts'),
|
||||
'qqnt/entities': path.resolve(__dirname, 'src/qqnt/entities/index.ts'),
|
||||
'qqnt/adapters': path.resolve(__dirname, 'src/qqnt/adapters/index.ts'),
|
||||
'qqnt/services': path.resolve(__dirname, 'src/qqnt/services/index.ts'),
|
||||
service: path.resolve(__dirname, 'src/service/index.ts')
|
||||
},
|
||||
output: {
|
||||
// 输出设置为系统模块格式,确保目录结构被保持
|
||||
format: 'esm',
|
||||
dir: path.resolve(__dirname, './dist/core/src'),
|
||||
entryFileNames: '[name]/index.js',
|
||||
chunkFileNames: '[name]/[hash]/index.js',
|
||||
// preserveModules: true, // 保持模块结构
|
||||
// preserveModulesRoot: 'src'
|
||||
},
|
||||
external: [...nodeModules, ...external],
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@/common': path.resolve(__dirname, '../common'),
|
||||
'@/core': path.resolve(__dirname, './src'),
|
||||
'./lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg',
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const commonPlugins: Plugin[] = [
|
||||
babel({
|
||||
filter: /.*\.(ts)$/,
|
||||
babelConfig: {
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
presets: ["@babel/preset-typescript"],
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-decorators', { legacy: true }],
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
],
|
||||
},
|
||||
}),
|
||||
dts({
|
||||
outDir: './dist',
|
||||
staticImport: true,
|
||||
rollupTypes: false,
|
||||
include: 'src/**/*.ts',
|
||||
}),
|
||||
cp({
|
||||
targets: [
|
||||
// ...external.map(genCpModule),
|
||||
{ src: './pub-package.json', dest: '../core.lib', rename: 'package.json' },
|
||||
]
|
||||
})
|
||||
];
|
||||
export default defineConfig(({ mode }) => {
|
||||
const result: UserConfig = { ...baseConfig };
|
||||
if (mode === 'production') {
|
||||
result.build!.minify = 'esbuild';
|
||||
result.plugins = [
|
||||
obfuscator({
|
||||
options: {
|
||||
compact: true,
|
||||
controlFlowFlattening: true,
|
||||
controlFlowFlatteningThreshold: 0.75,
|
||||
deadCodeInjection: true,
|
||||
deadCodeInjectionThreshold: 0.4,
|
||||
debugProtection: false,
|
||||
disableConsoleOutput: false,
|
||||
identifierNamesGenerator: 'hexadecimal',
|
||||
log: false,
|
||||
renameGlobals: false,
|
||||
rotateStringArray: true,
|
||||
selfDefending: true,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: ['base64'],
|
||||
stringArrayThreshold: 0.75,
|
||||
transformObjectKeys: true,
|
||||
unicodeEscapeSequence: false
|
||||
},
|
||||
include: ['src/**/*.js', 'src/**/*.ts'],
|
||||
}),
|
||||
...commonPlugins
|
||||
];
|
||||
} else {
|
||||
result.build!.minify = false;
|
||||
result.plugins = [...commonPlugins];
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user