chore: run a full eslint

This commit is contained in:
Wesley F. Young 2024-08-10 19:58:31 +08:00
parent 5a5257294b
commit 87c3b24488
198 changed files with 8187 additions and 7744 deletions

View File

@ -1,5 +1,5 @@
import { NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper";
import { randomUUID } from "crypto";
import { NodeIQQNTWrapperSession } from '@/core/wrapper/wrapper';
import { randomUUID } from 'crypto';
interface Internal_MapKey {
timeout: number;
@ -23,7 +23,7 @@ export class LegacyNTEventWrapper {
constructor(
listenerMapping: Record<string, ListenerIBase>,
wrapperSession: NodeIQQNTWrapperSession
wrapperSession: NodeIQQNTWrapperSession,
) {
this.listenerMapping = listenerMapping;
this.WrapperSession = wrapperSession;
@ -37,7 +37,7 @@ export class LegacyNTEventWrapper {
{
get(target: any, prop: any, receiver: any) {
// console.log('get', prop, typeof target[prop]);
if (typeof target[prop] === "undefined") {
if (typeof target[prop] === 'undefined') {
// 如果方法不存在返回一个函数这个函数调用existentMethod
return (...args: any[]) => {
current.dispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then();
@ -46,17 +46,17 @@ export class LegacyNTEventWrapper {
// 如果方法存在,正常返回
return Reflect.get(target, prop, receiver);
},
}
},
);
}
createEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
const eventNameArr = eventName.split("/");
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 serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '');
const eventName = eventNameArr[1];
//getNodeIKernelGroupListener,GroupService
//console.log('2', eventName);
@ -71,13 +71,13 @@ export class LegacyNTEventWrapper {
}
}
createListenerFunction<T>(listenerMainName: string, uniqueCode: string = ""): T {
createListenerFunction<T>(listenerMainName: string, uniqueCode: string = ''): T {
const ListenerType = this.listenerMapping![listenerMainName];
let Listener = this.listenerManager.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 Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener';
const addfunc = this.createEventFunction<(listener: T) => number>(Service);
addfunc!(Listener as T);
//console.log(addfunc!(Listener as T));
@ -104,7 +104,7 @@ export class LegacyNTEventWrapper {
}
async callNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(
EventName = "",
EventName = '',
timeout: number = 3000,
...args: Parameters<EventType>
) {
@ -113,7 +113,7 @@ export class LegacyNTEventWrapper {
let complete = false;
setTimeout(() => {
if (!complete) {
reject(new Error("NTEvent EventName:" + EventName + " timeout"));
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
}
}, timeout);
const retData = await EventFunc!(...args);
@ -123,13 +123,13 @@ export class LegacyNTEventWrapper {
}
async RegisterListen<ListenerType extends (...args: any[]) => void>(
ListenerName = "",
ListenerName = '',
waitTimes = 1,
timeout = 5000,
checker: (...args: Parameters<ListenerType>) => boolean
checker: (...args: Parameters<ListenerType>) => boolean,
) {
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
const ListenerNameList = ListenerName.split("/");
const ListenerNameList = ListenerName.split('/');
const ListenerMainName = ListenerNameList[0];
const ListenerSubName = ListenerNameList[1];
const id = randomUUID();
@ -137,7 +137,7 @@ export class LegacyNTEventWrapper {
let retData: Parameters<ListenerType> | undefined = undefined;
const databack = () => {
if (complete == 0) {
reject(new Error(" ListenerName:" + ListenerName + " timeout"));
reject(new Error(' ListenerName:' + ListenerName + ' timeout'));
} else {
resolve(retData!);
}
@ -166,12 +166,13 @@ export class LegacyNTEventWrapper {
this.createListenerFunction(ListenerMainName);
});
}
async CallNormalEvent<
EventType extends (...args: any[]) => Promise<any>,
ListenerType extends (...args: any[]) => void
>(
EventName = "",
ListenerName = "",
EventName = '',
ListenerName = '',
waitTimes = 1,
timeout: number = 3000,
checker: (...args: Parameters<ListenerType>) => boolean,
@ -187,21 +188,21 @@ export class LegacyNTEventWrapper {
if (complete == 0) {
reject(
new Error(
"Timeout: NTEvent EventName:" +
EventName +
" ListenerName:" +
ListenerName +
" EventRet:\n" +
JSON.stringify(retEvent, null, 4) +
"\n"
)
'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 ListenerNameList = ListenerName.split('/');
const ListenerMainName = ListenerNameList[0];
const ListenerSubName = ListenerNameList[1];
@ -231,7 +232,7 @@ export class LegacyNTEventWrapper {
this.createListenerFunction(ListenerMainName);
const EventFunc = this.createEventFunction<EventType>(EventName);
retEvent = await EventFunc!(...(args as any[]));
}
},
);
}
}

View File

@ -1,5 +1,5 @@
import type { NodeIQQNTWrapperSession, WrapperNodeApi } from "@/core/wrapper/wrapper";
import EventEmitter from "node:events";
import type { NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core/wrapper/wrapper';
import EventEmitter from 'node:events';
export type ListenerClassBase = Record<string, string>;
@ -12,9 +12,11 @@ export class NTEventChannel extends EventEmitter {
private wrapperApi: WrapperNodeApi;
private wrapperSession: NodeIQQNTWrapperSession;
private listenerRefStorage = new Map<string, ListenerIBase>();
constructor(WrapperApi: WrapperNodeApi, WrapperSession: NodeIQQNTWrapperSession) {
super();
this.on('error', () => { });
this.on('error', () => {
});
this.wrapperApi = WrapperApi;
this.wrapperSession = WrapperSession;
}
@ -31,7 +33,7 @@ export class NTEventChannel extends EventEmitter {
return (...args: any[]) => {
current.dispatcherListener.apply(current, [ListenerMainName + '/' + prop, ...args]);
};
}
},
});
}
@ -109,7 +111,7 @@ export class NTEventChannel extends EventEmitter {
//console.log('2', eventName);
const services = (this.wrapperSession as unknown as eventType)[serviceName]();
const event = services[eventName]
//重新绑定this
//重新绑定this
.bind(services);
if (event) {
return event as T;
@ -134,4 +136,5 @@ export class NTEventChannel extends EventEmitter {
});
}
}
//NTEvent2.0
//NTEvent2.0

View File

@ -1,6 +1,8 @@
import path, { dirname } from "path";
import { fileURLToPath } from "url";
export const napcat_version = "2.0.0";
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
export const napcat_version = '2.0.0';
export class NapCatPathWrapper {
binaryPath: string;
logsPath: string;
@ -8,7 +10,7 @@ export class NapCatPathWrapper {
constructor(mainPath: string = dirname(fileURLToPath(import.meta.url))) {
this.binaryPath = mainPath;
this.logsPath = path.join(this.binaryPath, "logs");
this.configPath = path.join(this.binaryPath, "config");
this.logsPath = path.join(this.binaryPath, 'logs');
this.configPath = path.join(this.binaryPath, 'config');
}
}

View File

@ -1,86 +1,91 @@
import path from 'node:path';
import fs from 'node:fs';
import type { NapCatCore } from '@/core';
export class ConfigBase<T> {
public name: string = 'default_config';
private pathName: string | null = null; // 本次读取的文件路径
coreContext: NapCatCore;
configPath: string;
config: { [key: string]: any } = {};
constructor(coreContext: NapCatCore, configPath: string) {
this.coreContext = coreContext;
this.configPath = configPath;
this.read();
}
public name: string = 'default_config';
private pathName: string | null = null; // 本次读取的文件路径
coreContext: NapCatCore;
configPath: string;
config: { [key: string]: any } = {};
protected getKeys(): string[] | null {
// 决定 key 在json配置文件中的顺序
return null;
}
getConfigDir() {
const configDir = path.resolve(this.configPath, '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(this.coreContext.selfInfo.uin, false)) return this;
// 尝试加载默认配置
return this.read_from_file('', true);
}
getConfig(): T {
return this.config as T;
}
read_from_file(pathName: string, createIfNotExist: boolean) {
const logger = this.coreContext.context.logger;
const configPath = this.getConfigPath(pathName);
if (!fs.existsSync(configPath)) {
if (!createIfNotExist) return null;
this.pathName = pathName; // 记录有效的设置文件
try {
fs.writeFileSync(configPath, JSON.stringify(this.config, this.getKeys(), 2));
logger.log(`配置文件${configPath}已创建\n如果修改此文件后需要重启 NapCat 生效`);
}
catch (e: any) {
logger.logError(`创建配置文件 ${configPath} 时发生错误:`, e.message);
}
return this.config;
constructor(coreContext: NapCatCore, configPath: string) {
this.coreContext = coreContext;
this.configPath = configPath;
this.read();
}
try {
this.config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
logger.logDebug(`配置文件${configPath}已加载`, this.config);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
this.save(); // 保存一次,让新版本的字段写入
return this.config;
} catch (e: any) {
if (e instanceof SyntaxError) {
logger.logError(`配置文件 ${configPath} 格式错误,请检查配置文件:`, e.message);
} else {
logger.logError(`读取配置文件 ${configPath} 时发生错误:`, e.message);
}
return {};
protected getKeys(): string[] | null {
// 决定 key 在json配置文件中的顺序
return null;
}
}
save(configData: T = this.config as T, overwrite: boolean = false) {
const logger = this.coreContext.context.logger;
const selfInfo = this.coreContext.selfInfo;
if (overwrite) {
// 用户要求强制写入,则变更当前文件为目标文件
this.pathName = `${selfInfo.uin}`;
getConfigDir() {
const configDir = path.resolve(this.configPath, 'config');
fs.mkdirSync(configDir, { recursive: true });
return configDir;
}
const configPath = this.getConfigPath(this.pathName);
try {
fs.writeFileSync(configPath, JSON.stringify(configData, this.getKeys(), 2));
} catch (e: any) {
logger.logError(`保存配置文件 ${configPath} 时发生错误:`, e.message);
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(this.coreContext.selfInfo.uin, false)) return this;
// 尝试加载默认配置
return this.read_from_file('', true);
}
getConfig(): T {
return this.config as T;
}
read_from_file(pathName: string, createIfNotExist: boolean) {
const logger = this.coreContext.context.logger;
const configPath = this.getConfigPath(pathName);
if (!fs.existsSync(configPath)) {
if (!createIfNotExist) return null;
this.pathName = pathName; // 记录有效的设置文件
try {
fs.writeFileSync(configPath, JSON.stringify(this.config, this.getKeys(), 2));
logger.log(`配置文件${configPath}已创建\n如果修改此文件后需要重启 NapCat 生效`);
} catch (e: any) {
logger.logError(`创建配置文件 ${configPath} 时发生错误:`, e.message);
}
return this.config;
}
try {
this.config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
logger.logDebug(`配置文件${configPath}已加载`, this.config);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
this.save(); // 保存一次,让新版本的字段写入
return this.config;
} catch (e: any) {
if (e instanceof SyntaxError) {
logger.logError(`配置文件 ${configPath} 格式错误,请检查配置文件:`, e.message);
} else {
logger.logError(`读取配置文件 ${configPath} 时发生错误:`, e.message);
}
return {};
}
}
save(configData: T = this.config as T, overwrite: boolean = false) {
const logger = this.coreContext.context.logger;
const selfInfo = this.coreContext.selfInfo;
if (overwrite) {
// 用户要求强制写入,则变更当前文件为目标文件
this.pathName = `${selfInfo.uin}`;
}
const configPath = this.getConfigPath(this.pathName);
try {
fs.writeFileSync(configPath, JSON.stringify(configData, this.getKeys(), 2));
} catch (e: any) {
logger.logError(`保存配置文件 ${configPath} 时发生错误:`, e.message);
}
}
}
}

View File

@ -1,5 +1,6 @@
import { Peer } from '@/core';
import crypto from 'crypto';
export class LimitedHashTable<K, V> {
private keyToValue: Map<K, V> = new Map();
private valueToKey: Map<V, K> = new Map();
@ -8,15 +9,16 @@ export class LimitedHashTable<K, V> {
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;
// }
// 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) {
@ -63,6 +65,7 @@ export class LimitedHashTable<K, V> {
getKeyList(): K[] {
return Array.from(this.keyToValue.keys());
}
//获取最近刚写入的几个值
getHeads(size: number): { key: K; value: V }[] | undefined {
const keyList = this.getKeyList();
@ -82,10 +85,12 @@ export class LimitedHashTable<K, V> {
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) {
@ -95,6 +100,7 @@ class MessageUniqueWrapper {
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();
@ -128,11 +134,13 @@ class MessageUniqueWrapper {
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);

View File

@ -1,9 +1,9 @@
import path from "node:path";
import fs from "node:fs";
import { systemPlatform } from "@/common/utils/system";
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from "./helper";
import AppidTable from "@/core/external/appid.json";
import { LogWrapper } from "./log";
import path from 'node:path';
import fs from 'node:fs';
import { systemPlatform } from '@/common/utils/system';
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
import AppidTable from '@/core/external/appid.json';
import { LogWrapper } from './log';
export class QQBasicInfoWrapper {
QQMainPath: string | undefined;
@ -20,7 +20,7 @@ export class QQBasicInfoWrapper {
//基础目录获取
this.context = context;
this.QQMainPath = process.execPath;
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), "resources", "app", "package.json");
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json');
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
//基础信息获取 无快更则启用默认模板填充
@ -40,27 +40,29 @@ export class QQBasicInfoWrapper {
}
getFullQQVesion() {
const version = this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version;
if(!version) throw new Error("QQ版本获取失败");
const version = this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version;
if (!version) throw new Error('QQ版本获取失败');
return version;
}
requireMinNTQQBuild(buildStr: string) {
const currentBuild = parseInt(this.getQQBuildStr() || "0");
if (currentBuild == 0) throw new Error("QQBuildStr获取失败");
const currentBuild = parseInt(this.getQQBuildStr() || '0');
if (currentBuild == 0) throw new Error('QQBuildStr获取失败');
return currentBuild >= parseInt(buildStr);
}
//此方法不要直接使用
getQUAInternal() {
return systemPlatform === "linux"
return systemPlatform === 'linux'
? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`
: `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
}
getAppidV2(): { appid: string; qua: string } {
const appidTbale = AppidTable as unknown as QQAppidTableType;
try {
const fullVersion = this.getFullQQVesion();
if (!fullVersion) throw new Error("QQ版本获取失败");
if (!fullVersion) throw new Error('QQ版本获取失败');
const data = appidTbale[fullVersion];
if (data) {
return data;
@ -70,9 +72,10 @@ export class QQBasicInfoWrapper {
}
// 以下是兜底措施
this.context.logger.log(
`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`
`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`,
);
return { appid: systemPlatform === "linux" ? "537237950" : "537237765", qua: this.getQUAInternal() };
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: this.getQUAInternal() };
}
}
export let QQBasicInfo: QQBasicInfoWrapper | undefined;

View File

@ -1,88 +1,90 @@
import fs from 'fs';
import { encode, getDuration, getWavFileInfo, isWav, isSilk } from 'silk-wasm';
import { encode, getDuration, getWavFileInfo, isSilk, isWav } from 'silk-wasm';
import fsPromise from 'fs/promises';
import path from 'node:path';
import { randomUUID } from 'crypto';
import { spawn } from 'node:child_process';
import { LogWrapper } from './log';
export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: LogWrapper) {
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);
logger.log('通过文件大小估算语音的时长:', duration);
return duration;
}
try {
const file = await fsPromise.readFile(filePath);
const pttPath = path.join(TEMP_DIR, randomUUID());
if (!isSilk(file)) {
logger.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 => {
logger.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);
}
logger.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);
logger.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) {
logger.log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack);
duration = await guessDuration(filePath);
}
return {
converted: false,
path: filePath,
duration,
};
export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: LogWrapper) {
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);
logger.log('通过文件大小估算语音的时长:', duration);
return duration;
}
try {
const file = await fsPromise.readFile(filePath);
const pttPath = path.join(TEMP_DIR, randomUUID());
if (!isSilk(file)) {
logger.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 => {
logger.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);
}
logger.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);
logger.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) {
logger.log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack);
duration = await guessDuration(filePath);
}
return {
converted: false,
path: filePath,
duration,
};
}
} catch (error: any) {
logger.logError('convert silk failed', error.stack);
return {};
}
} catch (error: any) {
logger.logError('convert silk failed', error.stack);
return {};
}
}

View File

@ -1,299 +1,301 @@
import fs from 'fs';
import fsPromise, { stat } from 'fs/promises';
import crypto from 'crypto';
import crypto, { randomUUID } from 'crypto';
import util from 'util';
import path from 'node:path';
import * as fileType from 'file-type';
import { randomUUID } from 'crypto';
import { LogWrapper } from './log';
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';
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();
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);
}
}
function check() {
if (fs.existsSync(path)) {
resolve();
} else if (Date.now() - startTime > timeout) {
reject(new Error(`文件不存在: ${path}`));
} else {
setTimeout(check, 100);
}
}
check();
});
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.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);
});
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;
await stat(path);
} catch (error: any) {
if (error.code === 'ENOENT') {
// 如果文件不存在,则抛出一个错误
throw new Error(`文件不存在: ${path}`);
} else {
// 对于 stat 调用的其他错误,重新抛出
throw error;
}
}
const data = await readFile(path);
// 转换为Base64编码
result.data = data.toString('base64');
} catch (err: any) {
result.err = err.toString();
}
return result;
// 如果文件存在则无需做任何事情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');
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('data', (data: Buffer) => {
// 当读取到数据时,更新哈希对象的状态
hash.update(data);
});
stream.on('end', () => {
// 文件读取完成,计算哈希
const md5 = hash.digest('hex');
resolve(md5);
});
stream.on('end', () => {
// 文件读取完成,计算哈希
const md5 = hash.digest('hex');
resolve(md5);
});
stream.on('error', (err: Error) => {
// 处理可能的读取错误
reject(err);
stream.on('error', (err: Error) => {
// 处理可能的读取错误
reject(err);
});
});
});
}
export interface HttpDownloadOptions {
url: string;
headers?: Record<string, string> | string;
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 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 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);
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
success: boolean,
errMsg: string,
fileName: string,
ext: string,
path: string,
isLocal: boolean
}
export async function uri2local(TempDir: string, 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(TempDir, 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];
const res = {
success: false,
errMsg: '',
fileName: '',
ext: '',
path: '',
isLocal: false,
};
if (!fileName) fileName = randomUUID();
let filePath = path.join(TempDir, fileName);//临时目录
let url = null;
//区分path和uri
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;
if (fs.existsSync(UriOrPath)) url = new URL('file://' + UriOrPath);
} catch (error: any) {
}
try {
const pathInfo = path.parse(decodeURIComponent(url.pathname));
if (pathInfo.name) {
fileName = pathInfo.name;
if (pathInfo.ext) {
fileName += pathInfo.ext;
// res.ext = pathInfo.ext
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;
}
}
fileName = fileName.replace(/[/\\:*?"<>|]/g, '_');
res.fileName = fileName;
filePath = path.join(TempDir, randomUUID() + fileName);
fs.writeFileSync(filePath, buffer);
} catch (e: any) {
res.errMsg = `${url}下载失败,` + 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(TempDir, 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 {
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{
// 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) {
fs.renameSync(filePath, filePath + `.${ext}`);
filePath += `.${ext}`;
res.fileName += `.${ext}`;
res.ext = ext;
}
} catch (e) {
// log("获取文件类型失败", filePath,e.stack)
}
}
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) {
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;
res.success = true;
res.path = filePath;
return res;
}
export async function copyFolder(sourcePath: string, destPath: string, logger: LogWrapper) {
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, logger);
} else {
try {
await fsPromise.copyFile(srcPath, dstPath);
} catch (error) {
logger.logError(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
// 这里可以决定是否要继续复制其他文件
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, logger);
} else {
try {
await fsPromise.copyFile(srcPath, dstPath);
} catch (error) {
logger.logError(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
// 这里可以决定是否要继续复制其他文件
}
}
}
}
} catch (error) {
logger.logError('复制文件夹时出错:', error);
}
} catch (error) {
logger.logError('复制文件夹时出错:', error);
}
}

View File

@ -1,9 +1,9 @@
import crypto from "node:crypto";
import path from "node:path";
import fs from "fs";
import * as fsPromise from "node:fs/promises";
import os from "node:os";
import { QQLevel } from "@/core";
import crypto from 'node:crypto';
import path from 'node:path';
import fs from 'fs';
import * as fsPromise from 'node:fs/promises';
import os from 'node:os';
import { QQLevel } from '@/core';
//下面这个类是用于将uid+msgid合并的类
@ -11,19 +11,20 @@ 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 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
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));
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() };
}
}
@ -34,27 +35,28 @@ export function sleep(ms: number): Promise<void> {
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)
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 })
)
(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);
.filter((result) => result.status === 'fulfilled')
.map((result) => (result as { status: 'fulfilled'; value: T }).value);
}
export function getMd5(s: string) {
const h = crypto.createHash("md5");
const h = crypto.createHash('md5');
h.update(s);
return h.digest("hex");
return h.digest('hex');
}
export function isNull(value: any) {
@ -64,15 +66,16 @@ export function isNull(value: any) {
export function isNumeric(str: string) {
return /^\d+$/.test(str);
}
export function truncateString(obj: any, maxLength = 500) {
if (obj !== null && typeof obj === "object") {
if (obj !== null && typeof obj === 'object') {
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === "string") {
if (typeof obj[key] === 'string') {
// 如果是字符串且超过指定长度,则截断
if (obj[key].length > maxLength) {
obj[key] = obj[key].substring(0, maxLength) + "...";
obj[key] = obj[key].substring(0, maxLength) + '...';
}
} else if (typeof obj[key] === "object") {
} else if (typeof obj[key] === 'object') {
// 如果是对象或数组,则递归调用
truncateString(obj[key], maxLength);
}
@ -80,10 +83,11 @@ export function truncateString(obj: any, maxLength = 500) {
}
return obj;
}
export function isEqual(obj1: any, obj2: any) {
if (obj1 === obj2) return true;
if (obj1 == null || obj2 == null) return false;
if (typeof obj1 !== "object" || typeof obj2 !== "object") return obj1 === obj2;
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
@ -95,35 +99,36 @@ export function isEqual(obj1: any, obj2: any) {
}
return true;
}
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
if (os.platform() === "linux") {
if (os.platform() === 'linux') {
return {
baseVersion: "3.2.12-26702",
curVersion: "3.2.12-26702",
prevVersion: "",
baseVersion: '3.2.12-26702',
curVersion: '3.2.12-26702',
prevVersion: '',
onErrorVersions: [],
buildId: "26702",
buildId: '26702',
};
}
return {
baseVersion: "9.9.15-26702",
curVersion: "9.9.15-26702",
prevVersion: "",
baseVersion: '9.9.15-26702',
curVersion: '9.9.15-26702',
prevVersion: '',
onErrorVersions: [],
buildId: "26702",
buildId: '26702',
};
}
export function getQQVersionConfigPath(exePath: string = ""): string | undefined {
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
let configVersionInfoPath;
if (os.platform() !== "linux") {
configVersionInfoPath = path.join(path.dirname(exePath), "resources", "app", "versions", "config.json");
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");
const appDataPath = path.resolve(userPath, './.config/QQ');
configVersionInfoPath = path.resolve(appDataPath, './versions/config.json');
}
if (typeof configVersionInfoPath !== "string") {
if (typeof configVersionInfoPath !== 'string') {
return undefined;
}
if (!fs.existsSync(configVersionInfoPath)) {
@ -153,7 +158,8 @@ export async function deleteOldFiles(directoryPath: string, daysThreshold: numbe
//console.error('Error deleting files:', error);
}
}
export function calcQQLevel(level: QQLevel) {
const { crownNum, sunNum, moonNum, starNum } = level;
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
const { crownNum, sunNum, moonNum, starNum } = level;
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
}

View File

@ -2,13 +2,15 @@ import log4js, { Configuration } from 'log4js';
import { truncateString } from '@/common/utils/helper';
import path from 'node:path';
import chalk from 'chalk';
export enum LogLevel {
DEBUG = 'debug',
INFO = 'info',
WARN = 'warn',
ERROR = 'error',
FATAL = 'fatal',
DEBUG = 'debug',
INFO = 'info',
WARN = 'warn',
ERROR = 'error',
FATAL = 'fatal',
}
function getFormattedTimestamp() {
const now = new Date();
const year = now.getFullYear();
@ -20,6 +22,7 @@ function getFormattedTimestamp() {
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
}
export class LogWrapper {
fileLogEnabled = true;
consoleLogEnabled = true;
@ -29,8 +32,9 @@ export class LogWrapper {
loggerDefault: log4js.Logger;
// eslint-disable-next-line no-control-regex
colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
constructor(logDir: string) {
// logDir = path.join(path.resolve(__dirname), 'logs');
// logDir = path.join(path.resolve(__dirname), 'logs');
const filename = `${getFormattedTimestamp()}.log`;
const logPath = path.join(logDir, filename);
this.logConfig = {
@ -41,22 +45,22 @@ export class LogWrapper {
maxLogSize: 10485760, // 日志文件的最大大小单位字节这里设置为10MB
layout: {
type: 'pattern',
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] %X{userInfo} | %m'
}
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`
}
}
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' }
}
console: { appenders: ['ConsoleAppender'], level: 'debug' },
},
};
log4js.configure(this.logConfig);
this.loggerConsole = log4js.getLogger('console');
@ -64,6 +68,7 @@ export class LogWrapper {
this.loggerDefault = log4js.getLogger('default');
this.setLogSelfInfo({ nick: '', uin: '', uid: '' });
}
setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
this.logConfig.categories.file.level = fileLogLevel;
this.logConfig.categories.console.level = consoleLogLevel;
@ -81,6 +86,7 @@ export class LogWrapper {
enableFileLog(enable: boolean) {
this.fileLogEnabled = enable;
}
enableConsoleLog(enable: boolean) {
this.consoleLogEnabled = enable;
}
@ -102,7 +108,6 @@ export class LogWrapper {
}
_log(level: LogLevel, ...args: any[]) {
if (this.consoleLogEnabled) {
this.loggerConsole[level](this.formatMsg(args));
@ -113,7 +118,7 @@ export class LogWrapper {
}
log(...args: any[]) {
// info 等级
// info 等级
this._log(LogLevel.INFO, ...args);
}

View File

@ -1,4 +1,4 @@
import { LogWrapper } from "./log";
import { LogWrapper } from './log';
export function proxyHandlerOf(logger: LogWrapper) {
return {
@ -12,10 +12,10 @@ export function proxyHandlerOf(logger: LogWrapper) {
}
// 如果方法存在,正常返回
return Reflect.get(target, prop, receiver);
}
},
};
}
export function proxiedListenerOf<T extends object>(listener: T, logger: LogWrapper) {
return new Proxy<T>(listener, proxyHandlerOf(logger));
}
}

View File

@ -1,6 +1,7 @@
import https from 'node:https';
import http from 'node:http';
import { readFileSync } from 'node:fs';
export class RequestUtil {
// 适用于获取服务器下发cookies时获取仅GET
static async HttpsGetCookies(url: string): Promise<{ [key: string]: string }> {
@ -27,7 +28,8 @@ export class RequestUtil {
resolve(cookies);
}
};
res.on('data', () => { }); // Necessary to consume the stream
res.on('data', () => {
}); // Necessary to consume the stream
res.on('end', () => {
handleRedirect(res);
});
@ -45,14 +47,15 @@ export class RequestUtil {
});
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> {
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 = {
@ -60,7 +63,7 @@ export class RequestUtil {
port: option.port,
path: option.href,
method: method,
headers: headers
headers: headers,
};
// headers: {
// 'Content-Type': 'application/json',
@ -119,7 +122,7 @@ export class RequestUtil {
const formDataParts = [
`------${boundary}\r\n`,
`Content-Disposition: form-data; name="share_image"; filename="${filePath}"\r\n`,
'Content-Type: ' + type + '\r\n\r\n'
'Content-Type: ' + type + '\r\n\r\n',
];
const fileContent = readFileSync(filePath);
@ -127,65 +130,65 @@ export class RequestUtil {
return Buffer.concat([
Buffer.from(formDataParts.join(''), 'utf8'),
fileContent,
Buffer.from(footer, 'utf8')
Buffer.from(footer, 'utf8'),
]);
}
static async uploadImageForOpenPlatform(filePath: string,cookies:string): Promise<string> {
static async uploadImageForOpenPlatform(filePath: string, cookies: string): Promise<string> {
return new Promise(async (resolve, reject) => {
type retType = { retcode: number, result?: { url: string } };
try {
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 = '';
type retType = { retcode: number, result?: { url: string } };
try {
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('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);
}
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);
});
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;
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;
});
}
}

View File

@ -17,7 +17,7 @@ try {
const invalidMacAddresses = new Set([
'00:00:00:00:00:00',
'ff:ff:ff:ff:ff:ff',
'ac:de:48:00:11:22'
'ac:de:48:00:11:22',
]);
function validateMacAddress(candidate: string): boolean {
@ -70,4 +70,4 @@ 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();
export const systemName = os.type();

View File

@ -1,17 +1,17 @@
//QQVersionType
type QQPackageInfoType = {
version: string;
buildVersion: string;
platform: string;
eleArch: string;
version: string;
buildVersion: string;
platform: string;
eleArch: string;
}
type QQVersionConfigType = {
baseVersion: string;
curVersion: string;
prevVersion: string;
onErrorVersions: Array<any>;
buildId: string;
baseVersion: string;
curVersion: string;
prevVersion: string;
onErrorVersions: Array<any>;
buildId: string;
}
type QQAppidTableType = {
[key: string]: { appid: string, qua: string };
}
[key: string]: { appid: string, qua: string };
}

View File

@ -2,57 +2,58 @@ import ffmpeg, { FfprobeStream } from 'fluent-ffmpeg';
import fs from 'fs';
import type { LogWrapper } from './log';
export async function getVideoInfo(filePath: string,logger:LogWrapper) {
const size = fs.statSync(filePath).size;
return new Promise<{
width: number,
height: number,
time: number,
format: string,
size: number,
filePath: string
}>((resolve, reject) => {
const ffmpegPath = process.env.FFMPEG_PATH;
ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
if (err) {
reject(err);
} else {
const videoStream = metadata.streams.find((s: FfprobeStream) => s.codec_type === 'video');
if (videoStream) {
logger.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
} else {
return reject('未找到视频流信息。');
}
resolve({
width: videoStream.width!, height: videoStream.height!,
time: parseInt(videoStream.duration!),
format: metadata.format.format_name!,
size,
filePath
export async function getVideoInfo(filePath: string, logger: LogWrapper) {
const size = fs.statSync(filePath).size;
return new Promise<{
width: number,
height: number,
time: number,
format: string,
size: number,
filePath: string
}>((resolve, reject) => {
const ffmpegPath = process.env.FFMPEG_PATH;
ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
if (err) {
reject(err);
} else {
const videoStream = metadata.streams.find((s: FfprobeStream) => s.codec_type === 'video');
if (videoStream) {
logger.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
} else {
return reject('未找到视频流信息。');
}
resolve({
width: videoStream.width!, height: videoStream.height!,
time: parseInt(videoStream.duration!),
format: metadata.format.format_name!,
size,
filePath,
});
}
});
}
});
});
}
export function checkFfmpeg(newPath: string | null = null,logger:LogWrapper): Promise<boolean> {
return new Promise((resolve, reject) => {
logger.log('开始检查ffmpeg', newPath);
if (newPath) {
ffmpeg.setFfmpegPath(newPath);
}
try {
ffmpeg.getAvailableFormats((err: any, formats: any) => {
if (err) {
logger.log('ffmpeg is not installed or not found in PATH:', err);
resolve(false);
} else {
logger.log('ffmpeg is installed.');
resolve(true);
export function checkFfmpeg(newPath: string | null = null, logger: LogWrapper): Promise<boolean> {
return new Promise((resolve, reject) => {
logger.log('开始检查ffmpeg', newPath);
if (newPath) {
ffmpeg.setFfmpegPath(newPath);
}
});
} catch (e) {
resolve(false);
}
});
try {
ffmpeg.getAvailableFormats((err: any, formats: any) => {
if (err) {
logger.log('ffmpeg is not installed or not found in PATH:', err);
resolve(false);
} else {
logger.log('ffmpeg is installed.');
resolve(true);
}
});
} catch (e) {
resolve(false);
}
});
}

View File

@ -1,24 +1,22 @@
import { log } from "@/common/utils/log";
interface IDependsAdapter {
onMSFStatusChange(arg1: number, arg2: number): void;
onMSFStatusChange(arg1: number, arg2: number): void;
onMSFSsoError(args: unknown): void;
onMSFSsoError(args: unknown): void;
getGroupCode(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;
// 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丢失网络连接,请检查网络")
// }
// console.log(arg1, arg2);
// if (arg1 == 2 && arg2 == 2) {
// log("NapCat丢失网络连接,请检查网络")
// }
}
onMSFSsoError(args: unknown) {

View File

@ -1,14 +1,14 @@
interface IDispatcherAdapter {
dispatchRequest(arg: unknown): void;
dispatchRequest(arg: unknown): void;
dispatchCall(arg: unknown): void;
dispatchCall(arg: unknown): void;
dispatchCallWithJson(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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IDispatcherAdapter): NodeIDispatcherAdapter;
}
export class DispatcherAdapter implements IDispatcherAdapter {

View File

@ -1,24 +1,24 @@
interface IGlobalAdapter {
onLog(...args: unknown[]): void;
onLog(...args: unknown[]): void;
onGetSrvCalTime(...args: unknown[]): void;
onGetSrvCalTime(...args: unknown[]): void;
onShowErrUITips(...args: unknown[]): void;
onShowErrUITips(...args: unknown[]): void;
fixPicImgType(...args: unknown[]): void;
fixPicImgType(...args: unknown[]): void;
getAppSetting(...args: unknown[]): void;
getAppSetting(...args: unknown[]): void;
onInstallFinished(...args: unknown[]): void;
onInstallFinished(...args: unknown[]): void;
onUpdateGeneralFlag(...args: unknown[]): void;
onUpdateGeneralFlag(...args: unknown[]): void;
onGetOfflineMsg(...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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IGlobalAdapter): NodeIGlobalAdapter;
}
export class GlobalAdapter implements IGlobalAdapter {

View File

@ -1,12 +1,14 @@
import { InstanceContext, NapCatCore } from "..";
import { InstanceContext, NapCatCore } from '..';
export class NTQQCollectionApi {
context: InstanceContext;
core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) {
this.context = context;
this.core = core;
}
async createCollection(authorUin: string, authorUid: string, authorName: string, brief: string, rawData: string) {
const param = {
commInfo: {
@ -18,11 +20,11 @@ export class NTQQCollectionApi {
strId: authorName,
groupId: '0',
groupName: '',
uid: authorUid
uid: authorUid,
},
customGroupId: '0',
createTime: Date.now().toString(),
sequence: Date.now().toString()
sequence: Date.now().toString(),
},
richMediaSummary: {
originalUri: '',
@ -32,27 +34,28 @@ export class NTQQCollectionApi {
title: '',
brief: brief,
picList: [],
contentType: 1
contentType: 1,
},
richMediaContent: {
rawData: rawData,
bizDataList: [],
picList: [],
fileList: []
fileList: [],
},
need_share_url: false
need_share_url: false,
};
return this.context.session.getCollectionService().createNewCollectionItem(param);
}
async getAllCollection(category: number = 0, count: number = 50) {
const param = {
category: category,
groupId: -1,
forceSync: true,
forceFromDb: false,
timeStamp: "0",
timeStamp: '0',
count: count,
searchDown: true
searchDown: true,
};
return this.context.session.getCollectionService().getCollectionItemList(param);
}

View File

@ -3,7 +3,11 @@ import {
CacheFileType,
ChatCacheListItemBasic,
ChatType,
ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, Peer, PicElement
ElementType,
IMAGE_HTTP_HOST,
IMAGE_HTTP_HOST_NT,
Peer,
PicElement,
} from '@/core/entities';
import path from 'path';
import fs from 'fs';
@ -21,11 +25,13 @@ export class NTQQFileApi {
context: InstanceContext;
core: NapCatCore;
rkeyManager: RkeyManager;
constructor(context: InstanceContext, core: NapCatCore) {
this.context = context;
this.core = core;
this.rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey', this.context.logger);
}
async getFileType(filePath: string) {
return fileType.fileTypeFromFile(filePath);
}
@ -37,12 +43,17 @@ export class NTQQFileApi {
async getFileSize(filePath: string): Promise<number> {
return await this.context.wrapper.util.getFileSize(filePath);
}
async getVideoUrl(peer: Peer, msgId: string, elementId: string) {
return (await this.context.session.getRichMediaService().getVideoPlayUrlV2(peer, msgId, elementId, 0, { downSourceType: 1, triggerType: 1 })).urlResult.domainUrl;
return (await this.context.session.getRichMediaService().getVideoPlayUrlV2(peer, msgId, elementId, 0, {
downSourceType: 1,
triggerType: 1,
})).urlResult.domainUrl;
}
// 上传文件到QQ的文件夹
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
// napCatCore.wrapper.util.
// napCatCore.wrapper.util.
const fileMd5 = await calculateFileMD5(filePath);
let ext: string = (await this.getFileType(filePath))?.ext as string || '';
if (ext) {
@ -60,7 +71,7 @@ export class NTQQFileApi {
thumbSize: 0,
needCreate: true,
downloadType: 1,
file_uuid: ''
file_uuid: '',
});
await this.copyFile(filePath, mediaPath!);
const fileSize = await this.getFileSize(filePath);
@ -69,76 +80,78 @@ export class NTQQFileApi {
fileName,
path: mediaPath,
fileSize,
ext
ext,
};
}
async downloadMediaByUuid() {
//napCatCore.session.getRichMediaService().downloadFileForFileUuid();
//napCatCore.session.getRichMediaService().downloadFileForFileUuid();
}
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;
//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;
}
}
}
const data = await this.core.eventWrapper.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
const data = await this.core.eventWrapper.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 \\');
// Mlikiowa V2.0.0 Refactor Todo
//const downloadPath = sessionConfig.defaultFileDownloadPath;
//logDebug('downloadPath', downloadPath);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
filePath = path.join('', filePath);
// 下载路径是下载文件夹的相对路径
}
);
let filePath = data[1].filePath;
if (filePath.startsWith('\\')) {
// log('filePath start with \\');
// Mlikiowa V2.0.0 Refactor Todo
//const downloadPath = sessionConfig.defaultFileDownloadPath;
//logDebug('downloadPath', downloadPath);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
filePath = path.join("", filePath);
// 下载路径是下载文件夹的相对路径
}
return filePath;
return filePath;
}
async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
@ -152,25 +165,26 @@ export class NTQQFileApi {
});
});
}
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"
}];
[{
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'
remark: 'NapCat.Cached',
}];
} else {
return undefined;
@ -204,65 +218,68 @@ export class NTQQFileApi {
fileName: fileName,
hits: [{
start: 12,
end: 14
}]
}
]
end: 14,
}],
},
],
});
}
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 = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords');
let id = '';
const Listener = this.core.eventWrapper.RegisterListen<(params: OnListener) => void>
(
'NodeIKernelSearchListener/onSearchFileKeywordsResult',
1,
20000,
(params) => id !== '' && params.searchId == id
);
id = await Event!(keys, 12);
const [ret] = (await Listener);
return ret;
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 = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords');
let id = '';
const Listener = this.core.eventWrapper.RegisterListen<(params: OnListener) => void>
(
'NodeIKernelSearchListener/onSearchFileKeywordsResult',
1,
20000,
(params) => id !== '' && params.searchId == id,
);
id = await Event!(keys, 12);
const [ret] = (await Listener);
return ret;
}
async getImageUrl(element: PicElement) {
if (!element) {
return '';
@ -300,10 +317,12 @@ export class NTQQFileApi {
export class NTQQFileCacheApi {
context: InstanceContext;
core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) {
this.context = context;
this.core = core;
}
async setCacheSilentScan(isSilent: boolean = true) {
return '';
}
@ -313,7 +332,7 @@ export class NTQQFileCacheApi {
}
clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
// 参数未验证
// 参数未验证
return this.context.session.getStorageCleanService().clearCacheDataByKeys(cacheKeys);
}
@ -322,16 +341,16 @@ export class NTQQFileCacheApi {
}
scanCache() {
//return (await this.context.session.getStorageCleanService().scanCache()).size;
//return (await this.context.session.getStorageCleanService().scanCache()).size;
}
getHotUpdateCachePath() {
// 未实现
// 未实现
return '';
}
getDesktopTmpPath() {
// 未实现
// 未实现
return '';
}
@ -341,8 +360,8 @@ export class NTQQFileCacheApi {
getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
//需要五个参数
//return napCatCore.session.getStorageCleanService().getFileCacheInfo();
//需要五个参数
//return napCatCore.session.getStorageCleanService().getFileCacheInfo();
}
async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {

View File

@ -1,23 +1,27 @@
import { GetFileListParam, Peer, RawMessage, SendMessageElement } from '@/core/entities';
import { InstanceContext, NapCatCore, NTApiContext } from '@/core';
import { InstanceContext, NapCatCore } from '@/core';
import { onGroupFileInfoUpdateParamType } from '@/core/listeners';
import { GeneralCallResult } from '@/core/services/common';
export class NTQQMsgApi {
context: InstanceContext;
core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) {
this.context = context;
this.core = core;
}
async FetchLongMsg(peer: Peer, msgId: string) {
return this.context.session.getMsgService().fetchLongMsg(peer, msgId);
}
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 this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, "", false, 20);
//console.log(peer, msgSeq, emojiId, emojiType, count);
//注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged M likiowa
return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, 20);
}
// napCatCore: NapCatCore | null = null;
// enum BaseEmojiType {
// NORMAL_EMOJI,
@ -27,20 +31,23 @@ export class NTQQMsgApi {
// EMOJI_EMOJI
// }
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
// 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 this.context.session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiId.length > 3 ? '2' : '1', set);
}
async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise<GeneralCallResult & {
msgList: RawMessage[]
} | undefined> {
msgList: RawMessage[]
} | undefined> {
return this.context.session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId);
}
async ForwardMsg(peer: Peer, msgIds: string[]) {
return this.context.session.getMsgService().forwardMsg(msgIds, peer, [peer], new Map());
}
async getLastestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) {
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: peer,
@ -54,18 +61,22 @@ export class NTQQMsgApi {
});
return ret;
}
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 this.context.session.getMsgService().getMsgsByMsgId(peer, msgIds);
}
async getSingleMsg(peer: Peer, seq: string) {
return await this.context.session.getMsgService().getSingleMsg(peer, seq);
}
async fetchFavEmojiList(num: number) {
return this.context.session.getMsgService().fetchFavEmojiList("", num, true, true);
return this.context.session.getMsgService().fetchFavEmojiList('', num, true, true);
}
async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) {
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa
@ -79,40 +90,46 @@ export class NTQQMsgApi {
});
return ret;
}
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
}
async setMsgRead(peer: Peer) {
return this.context.session.getMsgService().setMsgRead(peer);
}
async getGroupFileList(GroupCode: string, params: GetFileListParam) {
const data = await this.core.eventWrapper.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
);
(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;
}
async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) {
// 消息时间从旧到新
// 消息时间从旧到新
return this.context.session.getMsgService().getMsgsIncludeSelf(peer, msgId, count, isReverseOrder);
}
async recallMsg(peer: Peer, msgIds: string[]) {
await this.context.session.getMsgService().recallMsg({
chatType: peer.chatType,
peerUid: peer.peerUid
peerUid: peer.peerUid,
}, msgIds);
}
async sendMsgV2(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
function generateMsgId() {
const timestamp = Math.floor(Date.now() / 1000);
@ -120,9 +137,10 @@ export class NTQQMsgApi {
const buffer = Buffer.alloc(8);
buffer.writeUInt32BE(timestamp, 0);
buffer.writeUInt32BE(random, 4);
const msgId = BigInt("0x" + buffer.toString('hex')).toString();
const msgId = BigInt('0x' + buffer.toString('hex')).toString();
return msgId;
}
// 此处有采用Hack方法 利用数据返回正确得到对应消息
// 与之前 Peer队列 MsgSeq队列 真正的MsgId并发不同
// 谨慎采用 目前测试暂无问题 Developer.Mlikiowa
@ -135,26 +153,26 @@ export class NTQQMsgApi {
msgId = generateMsgId().toString();
}
const data = await this.core.eventWrapper.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 (const msgRecord of msgRecords) {
if (msgRecord.msgId === msgId && msgRecord.sendStatus === 2) {
return true;
}
}
return false;
},
msgId,
peer,
msgElements,
new Map()
);
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
(msgList: RawMessage[]) => void
>(
'NodeIKernelMsgService/sendMsg',
'NodeIKernelMsgListener/onMsgInfoListUpdate',
1,
timeout,
(msgRecords: RawMessage[]) => {
for (const msgRecord of msgRecords) {
if (msgRecord.msgId === msgId && msgRecord.sendStatus === 2) {
return true;
}
}
return false;
},
msgId,
peer,
msgElements,
new Map(),
);
const retMsg = data[1].find(msgRecord => {
if (msgRecord.msgId === msgId) {
return true;
@ -162,34 +180,36 @@ export class NTQQMsgApi {
});
return retMsg;
}
sendMsgEx(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
//return NTQQMsgApi.sendMsgV1(peer, msgElements, waitComplete, timeout);
//return NTQQMsgApi.sendMsgV1(peer, msgElements, waitComplete, timeout);
}
async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
//唉? !我有个想法
//唉? !我有个想法
const msgId = await this.getMsgUnique(peer.chatType, await this.getServerTime());
peer.guildId = msgId;
const data = await this.core.eventWrapper.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 (const msgRecord of msgRecords) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === 2) {
return true;
}
}
return false;
},
"0",
peer,
msgElements,
new Map()
);
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
(msgList: RawMessage[]) => void
>(
'NodeIKernelMsgService/sendMsg',
'NodeIKernelMsgListener/onMsgInfoListUpdate',
1,
timeout,
(msgRecords: RawMessage[]) => {
for (const msgRecord of msgRecords) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === 2) {
return true;
}
}
return false;
},
'0',
peer,
msgElements,
new Map(),
);
const retMsg = data[1].find(msgRecord => {
if (msgRecord.guildId === msgId) {
return true;
@ -197,47 +217,52 @@ export class NTQQMsgApi {
});
return retMsg;
}
async getMsgUnique(chatType: number, time: string) {
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return this.context.session.getMsgService().generateMsgUniqueId(chatType, time);
}
return this.context.session.getMsgService().getMsgUniqueId(time);
}
async getServerTime() {
return this.context.session.getMSFService().getServerTime();
}
async getServerTimeV2() {
return this.core.eventWrapper.callNoListenerEvent<() => string>('NodeIKernelMsgService/getServerTime', 5000);
}
async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
return this.context.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], new Map());
}
async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<RawMessage> {
const msgInfos = msgIds.map(id => {
return { msgId: id, senderShowName: this.core.selfInfo.nick };
});
const data = await this.core.eventWrapper.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 (const msgRecord of msgRecords) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) {
return true;
}
}
return false;
},
msgInfos,
srcPeer,
destPeer,
[],
new Map()
);
(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 (const msgRecord of msgRecords) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) {
return true;
}
}
return false;
},
msgInfos,
srcPeer,
destPeer,
[],
new Map(),
);
for (const msg of data[1]) {
const arkElement = msg.elements.find(ele => ele.arkElement);
if (!arkElement) {
@ -253,6 +278,7 @@ export class NTQQMsgApi {
}
throw new Error('转发消息超时');
}
async markallMsgAsRead() {
return this.context.session.getMsgService().setAllC2CAndGroupMsgRead();
}

View File

@ -275,9 +275,11 @@ export class NTQQUserApi {
}
return uid;
}
async getUinByUidV1(Uid: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent<(Uin: string[]) => Promise<{ uinInfo: Map<string, string> }>>
const ret = await this.core.eventWrapper.callNoListenerEvent<(Uin: string[]) => Promise<{
uinInfo: Map<string, string>
}>>
('NodeIKernelUixConvertService/getUin', 5000, [Uid]);
let uin = ret.uinInfo.get(Uid);
if (!uin) {
@ -317,6 +319,7 @@ export class NTQQUserApi {
return this.core.eventWrapper.callNoListenerEvent<(Uin: string) => Promise<UserDetailInfoByUin>>
('NodeIKernelProfileService/getUserDetailInfoByUin', 5000, Uin);
}
async forceFetchClientKey() {
return await this.context.session.getTicketService().forceFetchClientKey('');
}

View File

@ -71,7 +71,7 @@ export class NTQQWebApi {
end: '40',
sort: '1',
gc: GroupCode,
bkn: this.getBknFromCookie(cookieObject)
bkn: this.getBknFromCookie(cookieObject),
}).toString()
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) {
@ -92,7 +92,7 @@ export class NTQQWebApi {
end: (i * 40).toString(),
sort: '1',
gc: GroupCode,
bkn: this.getBknFromCookie(cookieObject)
bkn: this.getBknFromCookie(cookieObject),
}).toString()
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
retList.push(ret);
@ -288,10 +288,10 @@ export class NTQQWebApi {
private cookieToString(cookieObject: any) {
return Object.entries(cookieObject).map(([key, value]) => `${key}=${value}`).join('; ');
}
public getBknFromCookie(cookieObject: any) {
const sKey = cookieObject.skey as string;
let hash = 5381;
for (let i = 0; i < sKey.length; i++) {
const code = sKey.charCodeAt(i);

View File

@ -1,16 +1,15 @@
import { NTApiContext, WrapperNodeApi } from "@/core/wrapper";
import path from "node:path";
import fs from "node:fs";
import { InstanceContext } from "./wrapper";
import { NTEventChannel } from "@/common/framework/event";
import { proxiedListenerOf } from "@/common/utils/proxy-handler";
import { MsgListener, ProfileListener } from "./listeners";
import { sleep } from "@/common/utils/helper";
import { SelfInfo, LineDevice, SelfStatusInfo } from "./entities";
import { LegacyNTEventWrapper } from "@/common/framework/event-legacy";
import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from "./apis";
import os from "node:os";
import { NTQQCollectionApi } from "./apis/collection";
import { NTApiContext, WrapperNodeApi } from '@/core/wrapper';
import path from 'node:path';
import fs from 'node:fs';
import { InstanceContext } from './wrapper';
import { proxiedListenerOf } from '@/common/utils/proxy-handler';
import { MsgListener, ProfileListener } from './listeners';
import { SelfInfo, SelfStatusInfo } from './entities';
import { LegacyNTEventWrapper } from '@/common/framework/event-legacy';
import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from './apis';
import os from 'node:os';
import { NTQQCollectionApi } from './apis/collection';
export enum NapCatCoreWorkingEnv {
Unknown = 0,
Shell = 1,
@ -36,6 +35,7 @@ export class NapCatCore {
NapCatTempPath: string;
// runtime info, not readonly
selfInfo: SelfInfo;
// 通过构造器递过去的 runtime info 应该尽量少
constructor(context: InstanceContext, selfInfo: SelfInfo) {
this.selfInfo = selfInfo;
@ -50,7 +50,7 @@ export class NapCatCore {
FriendApi: new NTQQFriendApi(this.context, this),
MsgApi: new NTQQMsgApi(this.context, this),
UserApi: new NTQQUserApi(this.context, this),
GroupApi: new NTQQGroupApi(this.context, this)
GroupApi: new NTQQGroupApi(this.context, this),
};
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
@ -60,9 +60,11 @@ export class NapCatCore {
fs.mkdirSync(this.NapCatTempPath, { recursive: true });
}
}
getApiContext() {
return this.ApiContext;
}
get dataPath(): string {
let result = this.context.wrapper.util.getNTUserDataInfoConfig();
if (!result) {
@ -76,11 +78,11 @@ export class NapCatCore {
async initNapCatCoreListeners() {
const msgListener = new MsgListener();
msgListener.onRecvMsg = (msg) => {
console.log("RecvMsg", msg);
console.log('RecvMsg', msg);
};
//await sleep(2500);
this.context.session.getMsgService().addKernelMsgListener(
new this.context.wrapper.NodeIKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger))
new this.context.wrapper.NodeIKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger)),
);
const profileListener = new ProfileListener();
@ -95,7 +97,7 @@ export class NapCatCore {
// }
};
this.context.session.getProfileService().addKernelProfileListener(
new this.context.wrapper.NodeIKernelProfileListener(proxiedListenerOf(profileListener, this.context.logger))
new this.context.wrapper.NodeIKernelProfileListener(proxiedListenerOf(profileListener, this.context.logger)),
);
}
}

View File

@ -12,12 +12,12 @@ export interface CacheScanResult {
string, // 「缓存数据」大小
string, // 「其他数据」大小
string, // 未知
]
];
}
export interface ChatCacheList {
pageCount: number;
infos: ChatCacheListItem[]
infos: ChatCacheListItem[];
}
export interface ChatCacheListItem {

View File

@ -1,10 +1,12 @@
import { QQLevel, Sex } from './user';
export enum GroupListUpdateType {
REFRESHALL,
GETALL,
MODIFIED,
REMOVE
}
export interface Group {
groupCode: string,
createTime?: string,//高版本才有
@ -56,9 +58,9 @@ export interface GroupMember {
uid: string; // 加密的字符串
uin: string; // QQ号
isRobot: boolean;
sex?: Sex
qqLevel?: QQLevel
sex?: Sex;
qqLevel?: QQLevel;
isChangeRole: boolean;
joinTime: string;
lastSpeakTime: string;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,116 +1,120 @@
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, // 其他人取消管理员
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[];
doubt: boolean;
nextStartSeq: string;
notifies: GroupNotify[];
}
export enum GroupNotifyStatus {
IGNORE = 0,
WAIT_HANDLE = 1,
APPROVE = 2,
REJECT = 3
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
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
approve = 1,
reject = 2
}
export enum BuddyReqType {
KMEINITIATOR,
KPEERINITIATOR,
KMEAGREED,
KMEAGREEDANDADDED,
KPEERAGREED,
KPEERAGREEDANDADDED,
KPEERREFUSED,
KMEREFUSED,
KMEIGNORED,
KMEAGREEANYONE,
KMESETQUESTION,
KMEAGREEANDADDFAILED,
KMSGINFO,
KMEINITIATORWAITPEERCONFIRM
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
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[];
unreadNums: number;
buddyReqs: FriendRequest[];
}
export enum MemberExtSourceType {
DEFAULTTYPE = 0,
TITLETYPE = 1,
NEWGROUPTYPE = 2,
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
}
}
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
};
}

View File

@ -11,6 +11,7 @@ export interface CustomMusicSignPostData {
image?: string,
singer?: string
}
export interface MiniAppLuaJsonType {
prompt: string,
title: string,
@ -20,4 +21,4 @@ export interface MiniAppLuaJsonType {
tagIcon: string,
source: string,
sourcelogo: string,
}
}

View File

@ -1,15 +1,17 @@
import { SelfInfo } from "./user";
import { SelfInfo } from './user';
export interface LineDevice {
instanceId: number
clientType: number
devUid: string
instanceId: number;
clientType: number;
devUid: string;
}
export interface OBLineDevice {
app_id: string;
device_name: string;
device_kind: string;
}
export interface CoreCache {
selfInfo: SelfInfo,
DeviceList: OBLineDevice[]

View File

@ -3,12 +3,14 @@ export enum Sex {
female = 2,
unknown = 255,
}
export interface BuddyCategoryType {
categoryId: number;
categroyName: string;
categroyMbCount: number;
buddyList: User[];
}
export interface CoreInfo {
uid: string;
uin: string;
@ -173,20 +175,23 @@ export interface SimpleInfo {
otherFlags: any | null;
intimate: any | null;
}
export interface FriendV2 extends SimpleInfo {
categoryId?: number;
categroyName?: string;
}
export interface SelfStatusInfo {
uid: string
status: number
extStatus: number
termType: number
netType: number
iconType: number
customStatus: any
setTime: string
}
uid: string;
status: number;
extStatus: number;
termType: number;
netType: number;
iconType: number;
customStatus: any;
setTime: string;
}
export interface UserDetailInfoListenerArg {
uid: string;
uin: string;
@ -194,6 +199,7 @@ export interface UserDetailInfoListenerArg {
commonExt: CommonExt;
photoWall: PhotoWall;
}
export interface ModifyProfileParams {
nick: string,
longNick: string,
@ -212,11 +218,12 @@ export interface BuddyProfileLikeReq {
start: number;
limit: number;
}
export interface QQLevel {
crownNum: number;
sunNum: number;
moonNum: number;
starNum: number
starNum: number;
}
export interface User {
@ -228,7 +235,7 @@ export interface User {
remark?: string;
sex?: Sex;
qqLevel?: QQLevel;
qid?: string
qid?: string;
birthday_year?: number;
birthday_month?: number;
birthday_day?: number;
@ -239,7 +246,7 @@ export interface User {
homeTown?: string; //"0-0-0";
makeFriendCareer?: number;
pos?: string;
eMail?: string
eMail?: string;
phoneNum?: string;
college?: string;
country?: string;
@ -281,12 +288,14 @@ export interface SelfInfo extends User {
online?: boolean;
}
export interface Friend extends User { }
export interface Friend extends User {
}
export enum BizKey {
KPRIVILEGEICON,
KPHOTOWALL
}
export interface UserDetailInfoByUinV2 {
result: number,
errMsg: string,
@ -298,6 +307,7 @@ export interface UserDetailInfoByUinV2 {
photoWall: null
}
}
export interface UserDetailInfoByUin {
result: number,
errMsg: string,
@ -355,4 +365,4 @@ export interface UserDetailInfoByUin {
pendantId: string,
vipNameColorId: string
}
}
}

View File

@ -21,41 +21,44 @@ export enum WebHonorType {
*/
EMOTION = 'emotion'
}
export interface WebApiGroupMember {
uin: number
role: number
g: number
join_time: number
last_speak_time: number
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
};
card: string;
tags: string;
flag: number;
nick: string;
qage: number;
rm: number;
}
export 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
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//时间
u: number;//发送者
fid: string;//fid
pubt: number;//时间
msg: {
text: string
text_face: string
@ -65,21 +68,22 @@ export interface WebApiGroupNoticeFeed {
w: string,
h: string
}[]
}
type: number
fn: number
cn: number
vn: number
};
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
};
read_num: number;
is_read: number;
is_all_confirm: number;
}
export interface WebApiGroupNoticeRet {
ec: number
em: string
@ -100,26 +104,28 @@ export interface WebApiGroupNoticeRet {
svrt: number
ad: number
}
export 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
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
retcode: number;
retmsg: string;
data: {
msg_list: GroupEssenceMsg[]
is_end: boolean
group_role: number
config_page_url: string
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,25 @@ import { LogWrapper } from '@/common/utils/log';
import { RequestUtil } from '@/common/utils/request';
interface ServerRkeyData {
group_rkey: string;
private_rkey: string;
expired_time: number;
group_rkey: string;
private_rkey: string;
expired_time: number;
}
export class RkeyManager {
serverUrl: string = '';
logger: LogWrapper;
private rkeyData: ServerRkeyData = {
group_rkey: '',
private_rkey: '',
expired_time: 0
expired_time: 0,
};
logger: LogWrapper;
constructor(serverUrl: string, logger: LogWrapper) {
this.logger = logger;
this.serverUrl = serverUrl;
}
async getRkey() {
if (this.isExpired()) {
try {
@ -35,8 +37,9 @@ export class RkeyManager {
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`);
return now > this.rkeyData.expired_time;
}
async refreshRkey(): Promise<any> {
//刷新rkey
//刷新rkey
this.rkeyData = await RequestUtil.HttpGetJson<ServerRkeyData>(this.serverUrl, 'GET');
}
}

View File

@ -3,52 +3,53 @@ import { BuddyCategoryType, FriendRequestNotify } from '@/core/entities';
export type OnBuddyChangeParams = BuddyCategoryType[]
interface IBuddyListener {
onBuddyListChangedV2(arg: unknown): void,//V2版本 还没兼容
onBuddyListChangedV2(arg: unknown): void,//V2版本 还没兼容
onBuddyListChange(arg: OnBuddyChangeParams): void,
onBuddyListChange(arg: OnBuddyChangeParams): void,
onBuddyInfoChange(arg: unknown): void,
onBuddyInfoChange(arg: unknown): void,
onBuddyDetailInfoChange(arg: unknown): void,
onBuddyDetailInfoChange(arg: unknown): void,
onNickUpdated(arg: unknown): void,
onNickUpdated(arg: unknown): void,
onBuddyRemarkUpdated(arg: unknown): void,
onBuddyRemarkUpdated(arg: unknown): void,
onAvatarUrlUpdated(arg: unknown): void,
onAvatarUrlUpdated(arg: unknown): void,
onBuddyReqChange(arg: FriendRequestNotify): void,
onBuddyReqChange(arg: FriendRequestNotify): void,
onBuddyReqUnreadCntChange(arg: unknown): void,
onBuddyReqUnreadCntChange(arg: unknown): void,
onCheckBuddySettingResult(arg: unknown): void,
onCheckBuddySettingResult(arg: unknown): void,
onAddBuddyNeedVerify(arg: unknown): void,
onAddBuddyNeedVerify(arg: unknown): void,
onSmartInfos(arg: unknown): void,
onSmartInfos(arg: unknown): void,
onSpacePermissionInfos(arg: unknown): void,
onSpacePermissionInfos(arg: unknown): void,
onDoubtBuddyReqChange(arg: unknown): void,
onDoubtBuddyReqChange(arg: unknown): void,
onDoubtBuddyReqUnreadNumChange(arg: unknown): void,
onDoubtBuddyReqUnreadNumChange(arg: unknown): void,
onBlockChanged(arg: unknown): void,
onBlockChanged(arg: unknown): void,
onAddMeSettingChanged(arg: unknown): void,
onAddMeSettingChanged(arg: unknown): void,
onDelBatchBuddyInfos(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;
// 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.');
//throw new Error('Method not implemented.');
}
onAddBuddyNeedVerify(arg: unknown) {
}

View File

@ -1,27 +1,33 @@
export interface IKernelFileAssistantListener {
onFileStatusChanged(...args: unknown[]): unknown;
onFileStatusChanged(...args: unknown[]): unknown;
onSessionListChanged(...args: unknown[]): unknown;
onSessionListChanged(...args: unknown[]): unknown;
onSessionChanged(...args: unknown[]): unknown;
onSessionChanged(...args: unknown[]): unknown;
onFileListChanged(...args: unknown[]): unknown;
onFileListChanged(...args: unknown[]): unknown;
onFileSearch(...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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IKernelFileAssistantListener): NodeIKernelFileAssistantListener;
}
export class KernelFileAssistantListener implements IKernelFileAssistantListener {
onFileStatusChanged(...args: unknown[]) { }
onFileStatusChanged(...args: unknown[]) {
}
onSessionListChanged(...args: unknown[]) { }
onSessionListChanged(...args: unknown[]) {
}
onSessionChanged(...args: unknown[]) { }
onSessionChanged(...args: unknown[]) {
}
onFileListChanged(...args: unknown[]) { }
onFileListChanged(...args: unknown[]) {
}
onFileSearch(...args: unknown[]) { }
onFileSearch(...args: unknown[]) {
}
}

View File

@ -1,64 +1,65 @@
import { Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/core/entities';
interface IGroupListener {
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): void;
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): void;
onGroupExtListUpdate(...args: unknown[]): void;
onGroupExtListUpdate(...args: unknown[]): void;
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): void;
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): void;
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void;
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void;
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void;
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void;
onGroupDetailInfoChange(...args: unknown[]): void;
onGroupDetailInfoChange(...args: unknown[]): void;
onGroupAllInfoChange(...args: unknown[]): void;
onGroupAllInfoChange(...args: unknown[]): void;
onGroupsMsgMaskResult(...args: unknown[]): void;
onGroupsMsgMaskResult(...args: unknown[]): void;
onGroupConfMemberChange(...args: unknown[]): void;
onGroupConfMemberChange(...args: unknown[]): void;
onGroupBulletinChange(...args: unknown[]): void;
onGroupBulletinChange(...args: unknown[]): void;
onGetGroupBulletinListResult(...args: unknown[]): void;
onGetGroupBulletinListResult(...args: unknown[]): void;
onMemberListChange(arg: {
sceneId: string,
ids: string[],
infos: Map<string, GroupMember>,
finish: boolean,
hasRobot: boolean
}): 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;
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>): void;
onSearchMemberChange(...args: unknown[]): void;
onSearchMemberChange(...args: unknown[]): void;
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void;
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void;
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void;
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void;
onGroupStatisticInfoChange(...args: unknown[]): void;
onGroupStatisticInfoChange(...args: unknown[]): void;
onJoinGroupNotify(...args: unknown[]): void;
onJoinGroupNotify(...args: unknown[]): void;
onShutUpMemberListChanged(...args: unknown[]): void;
onShutUpMemberListChanged(...args: unknown[]): void;
onGroupBulletinRemindNotify(...args: unknown[]): void;
onGroupBulletinRemindNotify(...args: unknown[]): void;
onGroupFirstBulletinNotify(...args: unknown[]): void;
onGroupFirstBulletinNotify(...args: unknown[]): void;
onJoinGroupNoVerifyFlag(...args: unknown[]): void;
onJoinGroupNoVerifyFlag(...args: unknown[]): void;
onGroupArkInviteStateResult(...args: unknown[]): void;
// 发现于Win 9.9.9 23159
onGroupMemberLevelInfoChange(...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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IGroupListener): NodeIKernelGroupListener;
}
export class GroupListener implements IGroupListener {
@ -66,6 +67,7 @@ export class GroupListener implements IGroupListener {
onGroupMemberLevelInfoChange(...args: unknown[]): void {
}
onGetGroupBulletinListResult(...args: unknown[]) {
}
@ -127,12 +129,12 @@ export class GroupListener implements IGroupListener {
}
onMemberListChange(arg: {
sceneId: string,
ids: string[],
infos: Map<string, GroupMember>, // uid -> GroupMember
finish: boolean,
hasRobot: boolean
}) {
sceneId: string,
ids: string[],
infos: Map<string, GroupMember>, // uid -> GroupMember
finish: boolean,
hasRobot: boolean
}) {
}
onSearchMemberChange(...args: unknown[]) {
@ -146,6 +148,7 @@ export class DebugGroupListener implements IGroupListener {
onGroupMemberLevelInfoChange(...args: unknown[]): void {
console.log('onGroupMemberLevelInfoChange:', ...args);
}
onGetGroupBulletinListResult(...args: unknown[]) {
console.log('onGetGroupBulletinListResult:', ...args);
}

View File

@ -1,42 +1,42 @@
export interface IKernelLoginListener {
onLoginConnected(...args: any[]): void;
onLoginConnected(...args: any[]): void;
onLoginDisConnected(...args: any[]): void;
onLoginDisConnected(...args: any[]): void;
onLoginConnecting(...args: any[]): void;
onLoginConnecting(...args: any[]): void;
onQRCodeGetPicture(...args: any[]): void;
onQRCodeGetPicture(...args: any[]): void;
onQRCodeLoginPollingStarted(...args: any[]): void;
onQRCodeLoginPollingStarted(...args: any[]): void;
onQRCodeSessionUserScaned(...args: any[]): void;
onQRCodeSessionUserScaned(...args: any[]): void;
onQRCodeLoginSucceed(...args: any[]): void;
onQRCodeLoginSucceed(...args: any[]): void;
onQRCodeSessionFailed(...args: any[]): void;
onQRCodeSessionFailed(...args: any[]): void;
onLoginFailed(...args: any[]): void;
onLoginFailed(...args: any[]): void;
onLogoutSucceed(...args: any[]): void;
onLogoutSucceed(...args: any[]): void;
onLogoutFailed(...args: any[]): void;
onLogoutFailed(...args: any[]): void;
onUserLoggedIn(...args: any[]): void;
onUserLoggedIn(...args: any[]): void;
onQRCodeSessionQuickLoginFailed(...args: any[]): void;
onQRCodeSessionQuickLoginFailed(...args: any[]): void;
onPasswordLoginFailed(...args: any[]): void;
onPasswordLoginFailed(...args: any[]): void;
OnConfirmUnusualDeviceFailed(...args: any[]): void;
OnConfirmUnusualDeviceFailed(...args: any[]): void;
onQQLoginNumLimited(...args: any[]): void;
onQQLoginNumLimited(...args: any[]): void;
onLoginState(...args: any[]): void;
onLoginState(...args: any[]): void;
}
export interface NodeIKernelLoginListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IKernelLoginListener): NodeIKernelLoginListener;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IKernelLoginListener): NodeIKernelLoginListener;
}
export class LoginListener implements IKernelLoginListener {
@ -50,10 +50,10 @@ export class LoginListener implements IKernelLoginListener {
}
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);
// 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 {
@ -97,12 +97,12 @@ export class LoginListener implements IKernelLoginListener {
}
export interface QRCodeLoginSucceedResult {
account: string;
mainAccount: string;
uin: string; //拿UIN
uid: string; //拿UID
nickName: string; //一般是空的 拿不到
gender: number;
age: number;
faceUrl: string;//一般是空的 拿不到
account: string;
mainAccount: string;
uin: string; //拿UIN
uid: string; //拿UID
nickName: string; //一般是空的 拿不到
gender: number;
age: number;
faceUrl: string;//一般是空的 拿不到
}

View File

@ -1,37 +1,39 @@
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
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
retCode: number;
retMsg: string;
clientWording: string;
isEnd: boolean;
item: Array<any>;
allFileCount: string;
nextIndex: string;
reqId: string;
}
// {
// sessionType: 1,
// chatType: 100,
@ -41,194 +43,195 @@ export interface onGroupFileInfoUpdateParamType {
// sig: '0x'
// }
export interface TempOnRecvParams {
sessionType: number,//1
chatType: ChatType,//100
peerUid: string,//uid
groupCode: string,//gc
fromNick: string,//gc name
sig: string,
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;
onAddSendMsg(msgRecord: RawMessage): void;
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void;
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void;
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void;
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void;
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void;
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void;
onContactUnreadCntUpdate(hashMap: unknown): void;
onContactUnreadCntUpdate(hashMap: unknown): void;
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void;
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void;
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void;
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void;
onEmojiDownloadComplete(emojiNotifyInfo: unknown): void;
onEmojiDownloadComplete(emojiNotifyInfo: unknown): void;
onEmojiResourceUpdate(emojiResourceInfo: unknown): void;
onEmojiResourceUpdate(emojiResourceInfo: unknown): void;
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onFileMsgCome(arrayList: unknown): void;
onFileMsgCome(arrayList: unknown): void;
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onFirstViewGroupGuildMapping(arrayList: unknown): void;
onFirstViewGroupGuildMapping(arrayList: unknown): void;
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void;
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void;
onGroupFileInfoAdd(groupItem: unknown): void;
onGroupFileInfoAdd(groupItem: unknown): void;
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType): void;
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType): void;
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void;
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void;
onGroupTransferInfoAdd(groupItem: unknown): void;
onGroupTransferInfoAdd(groupItem: unknown): void;
onGroupTransferInfoUpdate(groupFileListResult: unknown): void;
onGroupTransferInfoUpdate(groupFileListResult: unknown): void;
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void;
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void;
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void;
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void;
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void;
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void;
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void;
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void;
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void;
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void;
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void;
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void;
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void;
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void;
onInputStatusPush(inputStatusInfo: unknown): void;
onInputStatusPush(inputStatusInfo: unknown): void;
onKickedOffLine(kickedInfo: unknown): void;
onKickedOffLine(kickedInfo: unknown): void;
onLineDev(arrayList: unknown): void;
onLineDev(arrayList: unknown): void;
onLogLevelChanged(j2: unknown): void;
onLogLevelChanged(j2: unknown): void;
onMsgAbstractUpdate(arrayList: unknown): void;
onMsgAbstractUpdate(arrayList: unknown): void;
onMsgBoxChanged(arrayList: unknown): void;
onMsgBoxChanged(arrayList: unknown): void;
onMsgDelete(contact: unknown, arrayList: unknown): void;
onMsgDelete(contact: unknown, arrayList: unknown): void;
onMsgEventListUpdate(hashMap: unknown): void;
onMsgEventListUpdate(hashMap: unknown): void;
onMsgInfoListAdd(arrayList: unknown): void;
onMsgInfoListAdd(arrayList: unknown): void;
onMsgInfoListUpdate(msgList: RawMessage[]): void;
onMsgInfoListUpdate(msgList: RawMessage[]): void;
onMsgQRCodeStatusChanged(i2: unknown): void;
onMsgQRCodeStatusChanged(i2: unknown): void;
onMsgRecall(i2: unknown, str: unknown, j2: unknown): void;
onMsgRecall(i2: unknown, str: unknown, j2: unknown): void;
onMsgSecurityNotify(msgRecord: unknown): void;
onMsgSecurityNotify(msgRecord: unknown): void;
onMsgSettingUpdate(msgSetting: unknown): void;
onMsgSettingUpdate(msgSetting: unknown): void;
onNtFirstViewMsgSyncEnd(): void;
onNtFirstViewMsgSyncEnd(): void;
onNtMsgSyncEnd(): void;
onNtMsgSyncEnd(): void;
onNtMsgSyncStart(): void;
onNtMsgSyncStart(): void;
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onRecvGroupGuildFlag(i2: unknown): void;
onRecvGroupGuildFlag(i2: unknown): void;
onRecvMsg(...arrayList: unknown[]): void;
onRecvMsg(...arrayList: unknown[]): void;
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void;
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void;
onRecvOnlineFileMsg(arrayList: unknown): void;
onRecvOnlineFileMsg(arrayList: unknown): void;
onRecvS2CMsg(arrayList: unknown): void;
onRecvS2CMsg(arrayList: unknown): void;
onRecvSysMsg(arrayList: unknown): void;
onRecvSysMsg(arrayList: unknown): void;
onRecvUDCFlag(i2: unknown): void;
onRecvUDCFlag(i2: unknown): void;
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void;
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void;
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void;
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void;
onRichMediaUploadComplete(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;
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;
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void;
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void;
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void;
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): void;
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): void;
onUnreadCntAfterFirstView(hashMap: unknown): void;
onUnreadCntAfterFirstView(hashMap: unknown): void;
onUnreadCntUpdate(hashMap: unknown): void;
onUnreadCntUpdate(hashMap: unknown): void;
onUserChannelTabStatusChanged(z: unknown): void;
onUserChannelTabStatusChanged(z: unknown): void;
onUserOnlineStatusChanged(z: unknown): void;
onUserOnlineStatusChanged(z: unknown): void;
onUserTabStatusChanged(arrayList: unknown): void;
onUserTabStatusChanged(arrayList: unknown): void;
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
// 第一次发现于Linux
onUserSecQualityChanged(...args: unknown[]): void;
// 第一次发现于Linux
onUserSecQualityChanged(...args: unknown[]): void;
onMsgWithRichLinkInfoUpdate(...args: unknown[]): void;
onMsgWithRichLinkInfoUpdate(...args: unknown[]): void;
onRedTouchChanged(...args: unknown[]): void;
onRedTouchChanged(...args: unknown[]): void;
// 第一次发现于Win 9.9.9 23159
onBroadcastHelperProgerssUpdate(...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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IKernelMsgListener): NodeIKernelMsgListener;
}
@ -505,6 +508,7 @@ export class MsgListener implements IKernelMsgListener {
onRedTouchChanged(...args: unknown[]) {
}
// 第一次发现于Win 9.9.9-23159
onBroadcastHelperProgerssUpdate(...args: unknown[]) {

View File

@ -1,26 +1,29 @@
import { User, UserDetailInfoListenerArg } from '@/core/entities';
interface IProfileListener {
onProfileSimpleChanged(...args: unknown[]): void;
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void;
onProfileDetailInfoChanged(profile: User): void;
onProfileSimpleChanged(...args: unknown[]): void;
onStatusUpdate(...args: unknown[]): void;
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void;
onSelfStatusChanged(...args: unknown[]): void;
onProfileDetailInfoChanged(profile: User): void;
onStrangerRemarkChanged(...args: unknown[]): 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;
// 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[]) {
}

View File

@ -18,15 +18,15 @@ export interface NodeIKernelRecentContactListener extends IKernelRecentContactLi
}
export class KernelRecentContactListener implements IKernelRecentContactListener {
onDeletedContactsNotify(...args: unknown[]) {
onDeletedContactsNotify(...args: unknown[]) {
}
onRecentContactNotification(...args: unknown[]) {
onRecentContactNotification(...args: unknown[]) {
}
onMsgUnreadCountUpdate(...args: unknown[]) {
onMsgUnreadCountUpdate(...args: unknown[]) {
}
@ -34,11 +34,11 @@ export class KernelRecentContactListener implements IKernelRecentContactListener
}
onRecentContactListChanged(...args: unknown[]) {
onRecentContactListChanged(...args: unknown[]) {
}
onRecentContactListChangedVer2(...args: unknown[]) {
onRecentContactListChangedVer2(...args: unknown[]) {
}
}

View File

@ -1,5 +1,3 @@
export interface IKernelRobotListener {
onRobotFriendListChanged(...args: unknown[]): void;
@ -14,15 +12,15 @@ export interface NodeIKernelRobotListener extends IKernelRobotListener {
}
export class KernelRobotListener implements IKernelRobotListener {
onRobotFriendListChanged(...args: unknown[]){
onRobotFriendListChanged(...args: unknown[]) {
}
onRobotListChanged(...args: unknown[]){
onRobotListChanged(...args: unknown[]) {
}
onRobotProfileChanged(...args: unknown[]){
onRobotProfileChanged(...args: unknown[]) {
}
}

View File

@ -1,20 +1,20 @@
export interface ISessionListener {
onNTSessionCreate(args: unknown): void;
onNTSessionCreate(args: unknown): void;
onGProSessionCreate(args: unknown): void;
onGProSessionCreate(args: unknown): void;
onSessionInitComplete(args: unknown): void;
onSessionInitComplete(args: unknown): void;
onOpentelemetryInit(args: unknown): void;
onOpentelemetryInit(args: unknown): void;
onUserOnlineResult(args: unknown): void;
onUserOnlineResult(args: unknown): void;
onGetSelfTinyId(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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: ISessionListener): NodeIKernelSessionListener;
}
export class SessionListener implements ISessionListener {

View File

@ -10,6 +10,7 @@ export interface IStorageCleanListener {
onChatCleanDone(args: unknown): void;
}
export interface NodeIKernelStorageCleanListener extends IStorageCleanListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IStorageCleanListener): NodeIKernelStorageCleanListener;
@ -27,6 +28,7 @@ export class StorageCleanListener implements IStorageCleanListener {
onCleanCacheStorageChanged(args: unknown) {
}
onFinishScan(args: unknown) {
}
@ -34,4 +36,4 @@ export class StorageCleanListener implements IStorageCleanListener {
onChatCleanDone(args: unknown) {
}
}
}

View File

@ -1,9 +1,10 @@
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 {
}
}

View File

@ -1,4 +1,3 @@
export * from './NodeIKernelSessionListener';
export * from './NodeIKernelLoginListener';
export * from './NodeIKernelMsgListener';

View File

@ -42,5 +42,5 @@ export interface NodeIKernelAlbumService {
doQunLike(...args: any[]): unknown;// needs 5 arguments
getRedPoints(...args: any[]): unknown;// needs 3 arguments
}
}

View File

@ -4,7 +4,7 @@ export interface NodeIKernelAvatarService {
removeAvatarListener(arg: unknown): unknown;
getAvatarPath(arg1: unknown, arg2: unknown): unknown;
forceDownloadAvatar(uid: string, useCache: number): Promise<unknown>;
getGroupAvatarPath(arg1: unknown, arg2: unknown): unknown;
@ -28,4 +28,4 @@ export interface NodeIKernelAvatarService {
forceDownloadAvatarByUin(arg1: unknown, arg2: unknown): unknown;
isNull(): boolean;
}
}

View File

@ -1,128 +1,131 @@
import { Friend } from '@/core/entities';
import { GeneralCallResult } from '@/core/services/common';
import { NodeIKernelBuddyListener } from '@/core/listeners';
export enum BuddyListReqType {
KNOMAL,
KLETTER
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;
// 26702 以上
getBuddyListV2(callFrom: string, reqType: BuddyListReqType): Promise<GeneralCallResult & {
data: Array<{
categoryId: number,
categorySortId: number,
categroyName: string,
categroyMbCount: number,
onlineCount: number,
buddyUids: Array<string>
}>
}>;
getAllBuddyCount(): number;
//26702 以上
getBuddyListFromCache(callFrom: string): Promise<Array<
{
categoryId: number,//9999应该跳过 那是兜底数据吧
categorySortId: number,//排序方式
categroyName: string,//分类名
categroyMbCount: number,//不懂
onlineCount: number,//在线数目
buddyUids: Array<string>//Uids
}>>;
removeKernelBuddyListener(listener: unknown): void;
// 以下为原生方法
addKernelBuddyListener(listener: NodeIKernelBuddyListener): number;
/**
* @deprecated
* @param nocache 使
*/
getBuddyList(nocache: boolean): Promise<GeneralCallResult>;
getAllBuddyCount(): number;
getBuddyNick(uid: number): string;
removeKernelBuddyListener(listener: unknown): void;
getBuddyRemark(uid: number): string;
/**
* @deprecated
* @param nocache 使
*/
getBuddyList(nocache: boolean): Promise<GeneralCallResult>;
setBuddyRemark(uid: number, remark: string): void;
getBuddyNick(uid: number): string;
getAvatarUrl(uid: number): string;
getBuddyRemark(uid: number): string;
isBuddy(uid: string): boolean;
setBuddyRemark(uid: number, remark: string): void;
getCategoryNameWithUid(uid: number): string;
getAvatarUrl(uid: number): string;
getTargetBuddySetting(uid: number): unknown;
isBuddy(uid: string): boolean;
getTargetBuddySettingByType(uid: number, type: number): unknown;
getCategoryNameWithUid(uid: number): string;
getBuddyReqUnreadCnt(): number;
getTargetBuddySetting(uid: number): unknown;
getBuddyReq(): unknown;
getTargetBuddySettingByType(uid: number, type: number): unknown;
delBuddyReq(uid: number): void;
getBuddyReqUnreadCnt(): number;
clearBuddyReqUnreadCnt(): void;
getBuddyReq(): unknown;
reqToAddFriends(uid: number, msg: string): void;
delBuddyReq(uid: number): void;
setSpacePermission(uid: number, permission: number): void;
clearBuddyReqUnreadCnt(): void;
approvalFriendRequest(arg: {
friendUid: string;
reqTime: string;
accept: boolean;
}): Promise<void>;
reqToAddFriends(uid: number, msg: string): void;
delBuddy(uid: number): void;
setSpacePermission(uid: number, permission: number): void;
delBatchBuddy(uids: number[]): void;
approvalFriendRequest(arg: {
friendUid: string;
reqTime: string;
accept: boolean;
}): Promise<void>;
getSmartInfos(uid: number): unknown;
delBuddy(uid: number): void;
setBuddyCategory(uid: number, category: number): void;
delBatchBuddy(uids: number[]): void;
setBatchBuddyCategory(uids: number[], category: number): void;
getSmartInfos(uid: number): unknown;
addCategory(category: string): void;
setBuddyCategory(uid: number, category: number): void;
delCategory(category: string): void;
setBatchBuddyCategory(uids: number[], category: number): void;
renameCategory(oldCategory: string, newCategory: string): void;
addCategory(category: string): void;
resortCategory(categorys: string[]): void;
delCategory(category: string): void;
pullCategory(uid: number, category: string): void;
renameCategory(oldCategory: string, newCategory: string): void;
setTop(uid: number, isTop: boolean): void;
resortCategory(categorys: string[]): void;
SetSpecialCare(uid: number, isSpecialCare: boolean): void;
pullCategory(uid: number, category: string): void;
setMsgNotify(uid: number, isNotify: boolean): void;
setTop(uid: number, isTop: boolean): void;
hasBuddyList(): boolean;
SetSpecialCare(uid: number, isSpecialCare: boolean): void;
setBlock(uid: number, isBlock: boolean): void;
setMsgNotify(uid: number, isNotify: boolean): void;
isBlocked(uid: number): boolean;
hasBuddyList(): boolean;
modifyAddMeSetting(setting: unknown): void;
setBlock(uid: number, isBlock: boolean): void;
getAddMeSetting(): unknown;
isBlocked(uid: number): boolean;
getDoubtBuddyReq(): unknown;
modifyAddMeSetting(setting: unknown): void;
getDoubtBuddyUnreadNum(): number;
getAddMeSetting(): unknown;
approvalDoubtBuddyReq(uid: number, isAgree: boolean): void;
getDoubtBuddyReq(): unknown;
delDoubtBuddyReq(uid: number): void;
getDoubtBuddyUnreadNum(): number;
delAllDoubtBuddyReq(): void;
approvalDoubtBuddyReq(uid: number, isAgree: boolean): void;
reportDoubtBuddyReqUnread(): void;
delDoubtBuddyReq(uid: number): void;
getBuddyRecommendContactArkJson(uid: string, phoneNumber: string): Promise<unknown>;
delAllDoubtBuddyReq(): void;
isNull(): boolean;
reportDoubtBuddyReqUnread(): void;
getBuddyRecommendContactArkJson(uid: string, phoneNumber: string): Promise<unknown>;
isNull(): boolean;
}

View File

@ -1,4 +1,4 @@
import { GeneralCallResult } from "./common";
import { GeneralCallResult } from './common';
export interface NodeIKernelCollectionService {
addKernelCollectionListener(...args: any[]): unknown;//needs 1 arguments
@ -14,45 +14,45 @@ export interface NodeIKernelCollectionService {
count: number,
searchDown: boolean
}): Promise<GeneralCallResult &
{
collectionSearchList: {
collectionItemList: Array<
{
cid: string,
type: number,
status: number,
author: {
{
collectionSearchList: {
collectionItemList: Array<
{
cid: string,
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
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
@ -88,4 +88,4 @@ export interface NodeIKernelCollectionService {
editCollectionItemAfterFastUpload(...args: any[]): unknown;//needs 2 arguments
createNewCollectionItem(...args: any[]): unknown;//needs 1 arguments
}
}

View File

@ -1,5 +1,7 @@
export interface NodeIKernelDbToolsService {
depositDatabase(...args: unknown[]): unknown;
backupDatabase(...args: unknown[]): unknown;
retrieveDatabase(...args: unknown[]): unknown;
depositDatabase(...args: unknown[]): unknown;
backupDatabase(...args: unknown[]): unknown;
retrieveDatabase(...args: unknown[]): unknown;
}

View File

@ -1,3 +1,3 @@
export interface NodeIKernelECDHService{
}
export interface NodeIKernelECDHService {
}

View File

@ -11,239 +11,254 @@ 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,
getMemberCommonInfo(Req: {
groupCode: string,
postscript: string
}
}): Promise<void>;
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>;
setTop(groupCode: string, isTop: boolean): void;
//26702
getGroupMemberLevelInfo(groupCode: string): Promise<unknown>;
getGroupBulletin(groupCode: string): unknown;
//26702
getGroupHonorList(groupCodes: Array<string>): unknown;
deleteGroupBulletin(groupCode: string, seq: string): void;
getUinByUids(uins: string[]): Promise<{
errCode: number,
errMsg: string,
uins: Map<string, string>
}>;
publishGroupBulletin(groupCode: string, pskey: string, data: any): Promise<GeneralCallResult>;
getUidByUins(uins: string[]): Promise<{
errCode: number,
errMsg: string,
uids: Map<string, string>
}>;
publishInstructionForNewcomers(groupCode: string, arg: unknown): void;
//26702(其实更早 但是我不知道)
checkGroupMemberCache(arrayList: Array<string>): Promise<unknown>;
uploadGroupBulletinPic(groupCode: string, pskey: string, imagePath: string): Promise<GeneralCallResult & {
errCode: number;
picInfo?: {
id: string,
width: number,
height: number
}
}>;
//26702(其实更早 但是我不知道)
getGroupLatestEssenceList(groupCode: string): Promise<unknown>;
downloadGroupBulletinRichMedia(groupCode: string): 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>;
getGroupBulletinList(groupCode: string): unknown;
//26702(其实更早 但是我不知道)
isEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
getGroupStatisticInfo(groupCode: string): unknown;
//26702(其实更早 但是我不知道)
queryCachedEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
getGroupRemainAtTimes(groupCode: string): number;
//26702(其实更早 但是我不知道)
fetchGroupEssenceList(Req: {
groupCode: string,
pageStart: number,
pageLimit: number
}, Arg: unknown): Promise<unknown>;
getJoinGroupNoVerifyFlag(groupCode: string): 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
}
}>;
getGroupArkInviteState(groupCode: string): unknown;
setHeader(uid: string, path: string): unknown;
reqToJoinGroup(groupCode: string, arg: unknown): void;
addKernelGroupListener(listener: NodeIKernelGroupListener): number;
setGroupShutUp(groupCode: string, shutUp: boolean): void;
removeKernelGroupListener(listenerId: unknown): void;
getGroupShutUpMemberList(groupCode: string): unknown[];
createMemberListScene(groupCode: string, scene: string): string;
setMemberShutUp(groupCode: string, memberTimes: { uid: string, timeStamp: number }[]): Promise<void>;
destroyMemberListScene(SceneId: string): void;
getGroupRecommendContactArkJson(groupCode: string): unknown;
//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 }
}>;
getJoinGroupLink(groupCode: string): unknown;
getPrevMemberList(): unknown;
modifyGroupExtInfo(groupCode: string, arg: unknown): void;
monitorMemberList(): unknown;
//需要提前判断是否存在 高版本新增
addGroupEssence(param: {
groupCode: string
msgRandom: number,
msgSeq: number
}): Promise<unknown>;
//需要提前判断是否存在 高版本新增
removeGroupEssence(param: {
groupCode: string
msgRandom: number,
msgSeq: number
}): Promise<unknown>;
searchMember(sceneId: string, keywords: string[]): unknown;
isNull(): boolean;
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;
}

View File

@ -1,82 +1,83 @@
import { NodeIKernelLoginListener } from '@/core/listeners/NodeIKernelLoginListener';
export interface LoginInitConfig {
machineId: '';
appid: string;
platVer: string;
commonPath: string;
clientVer: string;
hostName: string;
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;
}
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;
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; // 是否可以自动登录
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 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;
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(): NodeIKernelLoginService;
addKernelLoginListener(listener: NodeIKernelLoginListener): number;
removeKernelLoginListener(listener: number): void;
addKernelLoginListener(listener: NodeIKernelLoginListener): number;
initConfig(config: LoginInitConfig): void;
removeKernelLoginListener(listener: number): void;
getLoginMiscData(cb: (r: unknown) => void): void;
initConfig(config: LoginInitConfig): void;
getLoginList(): Promise<{
result: number, // 0是ok
LocalLoginInfoList: LoginListItem[]
}>;
getLoginMiscData(cb: (r: unknown) => void): void;
quickLoginWithUin(uin: string): Promise<QuickLoginResult>;
getLoginList(): Promise<{
result: number, // 0是ok
LocalLoginInfoList: LoginListItem[]
}>;
passwordLogin(param: passwordLoginArgType): Promise<any>;
quickLoginWithUin(uin: string): Promise<QuickLoginResult>;
getQRCodePicture(): boolean;
passwordLogin(param: passwordLoginArgType): Promise<any>;
getQRCodePicture(): boolean;
}

View File

@ -22,6 +22,6 @@ export interface NodeIKernelMsgBackupService {
start(...args: any[]): unknown;// needs 1 arguments
stop(...args: any[]): unknown;// needs 1 arguments
pause(...args: any[]): unknown;// needs 2 arguments
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,17 @@
import { GeneralCallResult } from "./common";
import { GeneralCallResult } from './common';
//没扒干净 因为用不着
export interface NodeIKernelNodeMiscService {
getMiniAppPath(): unknown;
setMiniAppVersion(version:string): 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环境 且完成校验破解 才能实现发包 有点抽象了
}
}

View File

@ -1,36 +1,36 @@
export interface NodeIKernelOnlineStatusService {
addKernelOnlineStatusListener(listener: unknown): void;
addKernelOnlineStatusListener(listener: unknown): void;
removeKernelOnlineStatusListener(listenerId: unknown): void;
removeKernelOnlineStatusListener(listenerId: unknown): void;
getShouldShowAIOStatusAnimation(arg: unknown): unknown;
getShouldShowAIOStatusAnimation(arg: unknown): unknown;
setReadLikeList(arg: unknown): unknown;
setReadLikeList(arg: unknown): unknown;
getLikeList(arg: unknown): unknown;
getLikeList(arg: unknown): unknown;
setLikeStatus(arg: unknown): unknown;
setLikeStatus(arg: unknown): unknown;
getAggregationPageEntrance(): unknown;
getAggregationPageEntrance(): unknown;
didClickAggregationPageEntrance(): unknown;
didClickAggregationPageEntrance(): unknown;
getAggregationGroupModels(): unknown;
getAggregationGroupModels(): unknown;
// {
// "businessType": 1,
// "uins": [
// "1627126029",
// "66600000",
// "71702575"
// ]
// }
// {
// "businessType": 1,
// "uins": [
// "1627126029",
// "66600000",
// "71702575"
// ]
// }
checkLikeStatus(param: {
businessType: number,
uins: string[]
}): Promise<any>;
checkLikeStatus(param: {
businessType: number,
uins: string[]
}): Promise<any>;
isNull(): boolean;
isNull(): boolean;
}

View File

@ -1,22 +1,21 @@
import { BuddyProfileLikeReq } from "../entities/user";
import { GeneralCallResult } from "./common";
import { BuddyProfileLikeReq, GeneralCallResult } from '@/core';
export interface NodeIKernelProfileLikeService {
addKernelProfileLikeListener(listener: NodeIKernelProfileLikeService): void;
addKernelProfileLikeListener(listener: NodeIKernelProfileLikeService): void;
removeKernelProfileLikeListener(listener: unknown): void;
removeKernelProfileLikeListener(listener: unknown): void;
setBuddyProfileLike(...args: unknown[]): { result: number, errMsg: string, succCounts: number };
setBuddyProfileLike(...args: unknown[]): { result: number, errMsg: string, succCounts: number };
getBuddyProfileLike(req: BuddyProfileLikeReq): Promise<GeneralCallResult & {
"info": {
"userLikeInfos": Array<any>,
"friendMaxVotes": number,
"start": number
}
}>;
getBuddyProfileLike(req: BuddyProfileLikeReq): Promise<GeneralCallResult & {
'info': {
'userLikeInfos': Array<any>,
'friendMaxVotes': number,
'start': number
}
}>;
getProfileLikeScidResourceInfo(...args: unknown[]): void;
getProfileLikeScidResourceInfo(...args: unknown[]): void;
isNull(): boolean;
isNull(): boolean;
}

View File

@ -1,103 +1,109 @@
import { AnyCnameRecord } from 'node:dns';
import { BaseInfo, BizKey, CoreInfo, ModifyProfileParams, SimpleInfo, UserDetailInfoByUin } from '../entities';
import { BizKey, ModifyProfileParams, SimpleInfo, UserDetailInfoByUin } from '../entities';
import { NodeIKernelProfileListener } from '../listeners';
import { GeneralCallResult } from '@/core/services/common';
export enum UserDetailSource {
KDB,
KSERVER
KDB,
KSERVER
}
export enum ProfileBizType {
KALL,
KBASEEXTEND,
KVAS,
KQZONE,
KOTHER
KALL,
KBASEEXTEND,
KVAS,
KQZONE,
KOTHER
}
export interface NodeIKernelProfileService {
getUidByUin(callfrom: string, uin: Array<string>): Promise<Map<string,string>>;//uin->uid
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>>;
getUinByUid(callfrom: string, uid: Array<string>): Promise<Map<string, string>>;
fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>;
// {
// coreInfo: CoreInfo,
// baseInfo: BaseInfo,
// status: null,
// vasInfo: null,
// relationFlags: null,
// otherFlags: null,
// intimate: null
// }
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>;
addKernelProfileListener(listener: NodeIKernelProfileListener): number;
fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>;
removeKernelProfileListener(listenerId: number): void;
addKernelProfileListener(listener: NodeIKernelProfileListener): number;
prepareRegionConfig(...args: unknown[]): unknown;
removeKernelProfileListener(listenerId: number): void;
getLocalStrangerRemark(): Promise<AnyCnameRecord>;
prepareRegionConfig(...args: unknown[]): unknown;
enumCountryOptions(): Array<string>;
getLocalStrangerRemark(): Promise<AnyCnameRecord>;
enumProvinceOptions(Country: string): Array<string>;
enumCountryOptions(): Array<string>;
enumCityOptions(Country: string, Province: string): unknown;
enumProvinceOptions(Country: string): Array<string>;
enumAreaOptions(...args: unknown[]): unknown;
enumCityOptions(Country: string, Province: string): 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;
enumAreaOptions(...args: unknown[]): unknown;
modifySelfProfile(...args: unknown[]): Promise<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;
modifyDesktopMiniProfile(param: ModifyProfileParams): Promise<GeneralCallResult>;
modifySelfProfile(...args: unknown[]): Promise<unknown>;
setNickName(NickName: string): Promise<unknown>;
modifyDesktopMiniProfile(param: ModifyProfileParams): Promise<GeneralCallResult>;
setLongNick(longNick: string): Promise<unknown>;
setNickName(NickName: string): Promise<unknown>;
setBirthday(...args: unknown[]): Promise<unknown>;
setLongNick(longNick: string): Promise<unknown>;
setGander(...args: unknown[]): Promise<unknown>;
setBirthday(...args: unknown[]): Promise<unknown>;
setHeader(arg: string): Promise<unknown>;
setGander(...args: unknown[]): Promise<unknown>;
setRecommendImgFlag(...args: unknown[]): Promise<unknown>;
setHeader(arg: string): Promise<unknown>;
getUserSimpleInfo(force: boolean, uids: string[],): Promise<unknown>;
setRecommendImgFlag(...args: unknown[]): Promise<unknown>;
getUserDetailInfo(uid: string): Promise<unknown>;
getUserSimpleInfo(force: boolean, uids: string[]): Promise<unknown>;
getUserDetailInfoWithBizInfo(uid: string, Biz: BizKey[]): Promise<GeneralCallResult>;
getUserDetailInfo(uid: string): Promise<unknown>;
getUserDetailInfoByUin(uin: string): Promise<UserDetailInfoByUin>;
getUserDetailInfoWithBizInfo(uid: string, Biz: BizKey[]): Promise<GeneralCallResult>;
getZplanAvatarInfos(args: string[]): Promise<unknown>;
getUserDetailInfoByUin(uin: string): Promise<UserDetailInfoByUin>;
getStatus(uid: string): Promise<unknown>;
getZplanAvatarInfos(args: string[]): Promise<unknown>;
startStatusPolling(isForceReset: boolean): Promise<unknown>;
getStatus(uid: string): Promise<unknown>;
getSelfStatus(): Promise<unknown>;
//
setdisableEmojiShortCuts(...args: unknown[]): unknown;
startStatusPolling(isForceReset: boolean): Promise<unknown>;
getProfileQzonePicInfo(uid: string, type: number, force: boolean): Promise<unknown>;
getSelfStatus(): Promise<unknown>;
//profileService.getCoreInfo("UserRemarkServiceImpl::getStrangerRemarkByUid", arrayList);
getCoreInfo(name: string, arg: any[]): unknown;
//m429253e12.getOtherFlag("FriendListInfoCache_getKernelDataAndPutCache", new ArrayList<>());
isNull(): boolean;
//
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;
}

View File

@ -1,6 +1,7 @@
import { ChatType, Peer } from "../entities";
import { NodeIKernelRecentContactListener } from "../listeners/NodeIKernelRecentContactListener";
import { GeneralCallResult } from "./common";
import { ChatType, Peer } from '../entities';
import { NodeIKernelRecentContactListener } from '../listeners/NodeIKernelRecentContactListener';
import { GeneralCallResult } from './common';
export interface FSABRecentContactParams {
anchorPointContact: {
contactId: string;
@ -12,6 +13,7 @@ export interface FSABRecentContactParams {
count: number;
fetchOld: boolean;
}
// {
// "anchorPointContact": {
// "contactId": "",
@ -34,16 +36,17 @@ export interface NodeIKernelRecentContactService {
enterOrExitMsgList(...args: unknown[]): unknown; // 1 arguments
/*!---!*/getRecentContactListSnapShot(count: number): Promise<GeneralCallResult & {
/*!---!*/
getRecentContactListSnapShot(count: number): Promise<GeneralCallResult & {
info: {
errCode: number,
errMsg: string,
sortedContactList: Array<number>,
changedList: Array<{
remark: any;
peerName: any;
sendMemberName: any;
sendNickName: any;
remark: any;
peerName: any;
sendMemberName: any;
sendNickName: any;
peerUid: string; peerUin: string, msgTime: string, chatType: ChatType, msgId: string
}>
}
@ -55,7 +58,8 @@ export interface NodeIKernelRecentContactService {
jumpToSpecifyRecentContact(...args: unknown[]): unknown; // 1 arguments
/*!---!*/fetchAndSubscribeABatchOfRecentContact(params: FSABRecentContactParams): unknown; // 1 arguments
/*!---!*/
fetchAndSubscribeABatchOfRecentContact(params: FSABRecentContactParams): unknown; // 1 arguments
addRecentContact(peer: Peer): unknown;
@ -96,4 +100,4 @@ export interface NodeIKernelRecentContactService {
setAllGameMsgRead(): unknown;
getRecentContactListSync(): unknown;
}
}

View File

@ -1,5 +1,6 @@
import { GetFileListParam, MessageElement, Peer, SendMessageElement } from "../entities";
import { GeneralCallResult } from "./common";
import { GetFileListParam, MessageElement, Peer } from '../entities';
import { GeneralCallResult } from './common';
export enum UrlFileDownloadType {
KUNKNOWN,
KURLFILEDOWNLOADPRIVILEGEICON,
@ -8,6 +9,7 @@ export enum UrlFileDownloadType {
KURLFILEDOWNLOADCOMMON,
KURLFILEDOWNLOADINSTALLAPP
}
export enum RMBizTypeEnum {
KUNKNOWN,
KC2CFILE,
@ -25,6 +27,7 @@ export enum RMBizTypeEnum {
KGUILDPTT,
KGUILDVIDEO
}
export interface CommonFileInfo {
bizType: number;
chatType: number;
@ -39,12 +42,13 @@ export interface CommonFileInfo {
msgTime: string;
parent: string;
peerUid: string;
picThumbPath: Array<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 {
@ -77,7 +81,10 @@ export interface NodeIKernelRichMediaService {
// 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 & {
getVideoPlayUrlV2(peer: Peer, msgId: string, elemId: string, videoCodecFormat: number, exParams: {
downSourceType: number,
triggerType: number
}): Promise<GeneralCallResult & {
urlResult: {
v4IpUrl: [],
v6IpUrl: [],
@ -127,7 +134,9 @@ export interface NodeIKernelRichMediaService {
//arg双端number
isFileExpired(arg: number): unknown;
deleteGroupFolder(GroupCode: string, FolderId: string): Promise<GeneralCallResult & { groupFileCommonResult: { retCode: number, retMsg: string, clientWording: string } }>;
deleteGroupFolder(GroupCode: string, FolderId: string): Promise<GeneralCallResult & {
groupFileCommonResult: { retCode: number, retMsg: string, clientWording: string }
}>;
//参数与getVideoPlayUrlInVisit一样
downloadRichMediaInVisit(arg: {
@ -144,8 +153,10 @@ export interface NodeIKernelRichMediaService {
ele: MessageElement,
useHttps: boolean
}): unknown;
//arg3为“”
downloadFileForModelId(peer: Peer, ModelId: string[], arg3: string): unknown;
//第三个参数 Array<Type>
// this.fileId = "";
// this.fileName = "";
@ -165,7 +176,9 @@ export interface NodeIKernelRichMediaService {
downloadFileForFileInfo(fileInfo: CommonFileInfo[], savePath: string): unknown;
createGroupFolder(GroupCode: string, FolderName: string): Promise<GeneralCallResult & { resultWithGroupItem: { result: any, groupItem: Array<any> } }>
createGroupFolder(GroupCode: string, FolderName: string): Promise<GeneralCallResult & {
resultWithGroupItem: { result: any, groupItem: Array<any> }
}>;
downloadFile(commonFile: CommonFileInfo, arg2: unknown, arg3: unknown, savePath: string): unknown;
@ -218,6 +231,7 @@ export interface NodeIKernelRichMediaService {
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 & {
@ -232,7 +246,10 @@ export interface NodeIKernelRichMediaService {
getScreenOCR(path: string): Promise<unknown>;
batchGetGroupFileCount(Gids: Array<string>): Promise<GeneralCallResult & { groupCodes: Array<string>, groupFileCounts: Array<number> }>;
batchGetGroupFileCount(Gids: Array<string>): Promise<GeneralCallResult & {
groupCodes: Array<string>,
groupFileCounts: Array<number>
}>;
queryPicDownloadSize(arg: unknown): unknown;
@ -263,4 +280,4 @@ export interface NodeIKernelRichMediaService {
}): Promise<unknown>;
isNull(): boolean;
}
}

View File

@ -1,4 +1,4 @@
import { NodeIKernelRobotListener } from "@/core/listeners";
import { NodeIKernelRobotListener } from '@/core/listeners';
export interface NodeIKernelRobotService {
fetchGroupRobotStoreDiscovery(arg: unknown): unknown;
@ -29,7 +29,7 @@ export interface NodeIKernelRobotService {
setRobotPickTts(arg1: unknown, arg2: unknown): unknown;
getRobotUinRange(data: any): Promise<{ response: { robotUinRanges: any } }>
getRobotUinRange(data: any): Promise<{ response: { robotUinRanges: any } }>;
isNull(): boolean;
}

View File

@ -1,4 +1,4 @@
import { ChatType } from "../entities";
import { ChatType } from '../entities';
export interface NodeIKernelSearchService {
addKernelSearchListener(...args: any[]): unknown;// needs 1 arguments
@ -90,8 +90,7 @@ export interface NodeIKernelSearchService {
hasModifyConfGroupName: boolean,
groupName: string,
remark: string
}>
,
}>,
dataLineChatInfo: [],
tmpChatInfo: [],
msgId: string,

View File

@ -1,41 +1,41 @@
import { NodeIKernelStorageCleanListener } from "@/core/listeners";
import { GeneralCallResult } from "./common";
import { NodeIKernelStorageCleanListener } from '@/core/listeners';
import { GeneralCallResult } from './common';
export interface NodeIKernelStorageCleanService {
addKernelStorageCleanListener(Listener: NodeIKernelStorageCleanListener): number;
addKernelStorageCleanListener(Listener: NodeIKernelStorageCleanListener): number;
removeKernelStorageCleanListener(ListenerId: number): void;
removeKernelStorageCleanListener(ListenerId: number): void;
addCacheScanedPaths(arg: unknown): unknown;
addCacheScanedPaths(arg: unknown): unknown;
addFilesScanedPaths(arg: unknown): unknown;
addFilesScanedPaths(arg: unknown): unknown;
scanCache(): Promise<GeneralCallResult & {
size: string[]
}>;
scanCache(): Promise<GeneralCallResult & {
size: string[]
}>;
addReportData(arg: unknown): unknown;
addReportData(arg: unknown): unknown;
reportData(): unknown;
reportData(): unknown;
getChatCacheInfo(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown): unknown;
getChatCacheInfo(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown): unknown;
getFileCacheInfo(arg1: unknown, arg2: unknown, arg3: unknown, arg44: unknown, args5: unknown): unknown;
getFileCacheInfo(arg1: unknown, arg2: unknown, arg3: unknown, arg44: unknown, args5: unknown): unknown;
clearChatCacheInfo(arg1: unknown, arg2: unknown): unknown;
clearChatCacheInfo(arg1: unknown, arg2: unknown): unknown;
clearCacheDataByKeys(arg: unknown): unknown;
clearCacheDataByKeys(arg: unknown): unknown;
setSilentScan(arg: unknown): unknown;
setSilentScan(arg: unknown): unknown;
closeCleanWindow(): unknown;
closeCleanWindow(): unknown;
clearAllChatCacheInfo(): unknown;
clearAllChatCacheInfo(): unknown;
endScan(arg: unknown): unknown;
endScan(arg: unknown): unknown;
addNewDownloadOrUploadFile(arg: unknown): unknown;
addNewDownloadOrUploadFile(arg: unknown): unknown;
isNull(): boolean;
isNull(): boolean;
}

View File

@ -6,5 +6,5 @@ export interface NodeIKernelTianShuService {
requesTianShuNumeralRe(...args: any[]): unknown;//d needs 1 arguments
reportTianShuNumeralRed(...args: any[]): unknown;// needs 1 arguments
}
}

View File

@ -1,12 +1,12 @@
import { forceFetchClientKeyRetType } from "./common";
import { forceFetchClientKeyRetType } from './common';
export interface NodeIKernelTicketService {
addKernelTicketListener(listener: unknown): void;
addKernelTicketListener(listener: unknown): void;
removeKernelTicketListener(listenerId: unknown): void;
removeKernelTicketListener(listenerId: unknown): void;
forceFetchClientKey(arg: string): Promise<forceFetchClientKeyRetType>;
forceFetchClientKey(arg: string): Promise<forceFetchClientKeyRetType>;
isNull(): boolean;
}
isNull(): boolean;
}

View File

@ -1,4 +1,4 @@
import { GeneralCallResult } from "./common";
import { GeneralCallResult } from './common';
export interface NodeIKernelTipOffService {
@ -8,7 +8,9 @@ export interface NodeIKernelTipOffService {
tipOffSendJsData(args: unknown[]): Promise<unknown>;//2
getPskey(domainList: string[], nocache: boolean): Promise<GeneralCallResult & { domainPskeyMap: Map<string, string> }>;//2
getPskey(domainList: string[], nocache: boolean): Promise<GeneralCallResult & {
domainPskeyMap: Map<string, string>
}>;//2
tipOffSendJsData(args: unknown[]): Promise<unknown>;//2
@ -17,4 +19,4 @@ export interface NodeIKernelTipOffService {
encodeUinAesInfo(args: unknown[]): Promise<unknown>;//2
isNull(): boolean;
}
}

View File

@ -1,6 +1,6 @@
export interface NodeIKernelUnitedConfigService{
export interface NodeIKernelUnitedConfigService {
addKernelUnitedConfigListener(...args: any[]): unknown;// needs 1 arguments
removeKernelUnitedConfigListener(...args: any[]): unknown;// needs 1 arguments
fetchUnitedCommendConfig(...args: any[]): unknown;// needs 1 arguments

View File

@ -1,4 +1,4 @@
import { MessageElement, Peer } from "../entities";
import { MessageElement, Peer } from '../entities';
export interface NodeIkernelTestPerformanceService {
insertMsg(MsgParam: {
@ -11,4 +11,4 @@ export interface NodeIkernelTestPerformanceService {
numPerTime: number
}, msg: Array<MessageElement>): Promise<unknown>;
}
}

View File

@ -2,13 +2,15 @@ export enum GeneralCallResultStatus {
OK = 0,
// ERROR = 1,
}
export interface GeneralCallResult{
export interface GeneralCallResult {
result: GeneralCallResultStatus,
errMsg: string
}
export interface forceFetchClientKeyRetType extends GeneralCallResult {
url: string;
keyIndex: string;
clientKey: string;
expireTime: string;
}
}

View File

@ -1,10 +1,8 @@
import { LogWrapper } from "@/common/utils/log";
import { QQBasicInfoWrapper } from "@/common/utils/QQBasicInfo";
import { NapCatCoreWorkingEnv } from "@/core";
import { NodeIKernelLoginService } from '@/core';
import { WrapperNodeApi, NodeIQQNTWrapperSession } from "@/core";
import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from "../apis";
import { NTQQCollectionApi } from "../apis/collection";
import { LogWrapper } from '@/common/utils/log';
import { QQBasicInfoWrapper } from '@/common/utils/QQBasicInfo';
import { NapCatCoreWorkingEnv, NodeIKernelLoginService, NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core';
import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from '../apis';
import { NTQQCollectionApi } from '../apis/collection';
import { NapCatPathWrapper } from '@/common/framework/napcat';
export interface InstanceContext {

View File

@ -1,7 +1,7 @@
import path from "node:path";
import fs from "node:fs";
import { PlatformType, VendorType, WrapperSessionInitConfig } from "./wrapper";
import { getMachineId, hostname, systemName, systemVersion } from "@/common/utils/system";
import path from 'node:path';
import fs from 'node:fs';
import { PlatformType, VendorType, WrapperSessionInitConfig } from './wrapper';
import { getMachineId, hostname, systemName, systemVersion } from '@/common/utils/system';
export async function genSessionConfig(QQVersionAppid: string, QQVersion: string, selfUin: string, selfUid: string, account_path: string): Promise<WrapperSessionInitConfig> {
const downloadPath = path.join(account_path, 'NapCat', 'temp');
@ -11,7 +11,7 @@ export async function genSessionConfig(QQVersionAppid: string, QQVersion: string
selfUin,
selfUid,
desktopPathConfig: {
account_path // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
account_path, // 可以通过NodeQQNTWrapperUtil().getNTUserDataInfoConfig()获取
},
clientVer: QQVersion, // 9.9.8-22355
a2: '',
@ -34,7 +34,7 @@ export async function genSessionConfig(QQVersionAppid: string, QQVersion: string
osVersion: '',
bundleId: '',
serverUrl: '',
fixedAfterHitKeys: ['']
fixedAfterHitKeys: [''],
},
defaultFileDownloadPath: downloadPath,
deviceInfo: {
@ -47,9 +47,9 @@ export async function genSessionConfig(QQVersionAppid: string, QQVersion: string
osVer: systemVersion,
vendorOsName: systemName,
setMute: false,
vendorType: VendorType.KNOSETONIOS
vendorType: VendorType.KNOSETONIOS,
},
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}'
deviceConfig: '{"appearance":{"isSplitViewMode":true},"msg":{}}',
};
return config;
}

View File

@ -1,43 +1,42 @@
import path from "node:path";
import fs from "node:fs";
import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from "../adapters";
import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from '../adapters';
import {
NodeIKernelSessionListener,
NodeIKernelMsgListener,
NodeIKernelLoginListener,
NodeIKernelBuddyListener,
NodeIKernelGroupListener,
NodeIKernelLoginListener,
NodeIKernelMsgListener,
NodeIKernelProfileListener,
} from "../listeners";
NodeIKernelSessionListener,
} from '../listeners';
import {
NodeIKernelLoginService,
NodeIKernelMsgService,
NodeIKernelAvatarService,
NodeIKernelBuddyService,
NodeIKernelGroupService,
NodeIKernelProfileService,
NodeIKernelLoginService,
NodeIKernelMsgService,
NodeIKernelProfileLikeService,
NodeIKernelProfileService,
NodeIKernelRichMediaService,
NodeIKernelTicketService,
NodeIKernelTipOffService,
NodeIKernelRichMediaService,
NodeIKernelAvatarService,
} from "../services";
import { NodeIKernelStorageCleanService } from "../services/NodeIKernelStorageCleanService";
import { NodeIKernelRobotService } from "../services/NodeIKernelRobotService";
import { NodeIKernelNodeMiscService } from "../services/NodeIKernelNodeMiscService";
import { NodeIKernelUixConvertService } from "../services/NodeIKernelUixConvertService";
import { NodeIKernelMsgBackupService } from "../services/NodeIKernelMsgBackupService";
import { NodeIKernelAlbumService } from "../services/NodeIKernelAlbumService";
import { NodeIKernelTianShuService } from "../services/NodeIKernelTianShuService";
import { NodeIKernelUnitedConfigService } from "../services/NodeIKernelUnitedConfigService";
import { NodeIKernelSearchService } from "../services/NodeIKernelSearchService";
import { NodeIKernelCollectionService } from "../services/NodeIKernelCollectionService";
import { NodeIKernelRecentContactService } from "../services/NodeIKernelRecentContactService";
import { NodeIKernelMSFService } from "../services/NodeIKernelMSFService";
import { NodeIkernelTestPerformanceService } from "../services/NodeIkernelTestPerformanceService";
import { NodeIKernelECDHService } from "../services/NodeIKernelECDHService";
} from '../services';
import { NodeIKernelStorageCleanService } from '../services/NodeIKernelStorageCleanService';
import { NodeIKernelRobotService } from '../services/NodeIKernelRobotService';
import { NodeIKernelNodeMiscService } from '../services/NodeIKernelNodeMiscService';
import { NodeIKernelUixConvertService } from '../services/NodeIKernelUixConvertService';
import { NodeIKernelMsgBackupService } from '../services/NodeIKernelMsgBackupService';
import { NodeIKernelAlbumService } from '../services/NodeIKernelAlbumService';
import { NodeIKernelTianShuService } from '../services/NodeIKernelTianShuService';
import { NodeIKernelUnitedConfigService } from '../services/NodeIKernelUnitedConfigService';
import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService';
import { NodeIKernelCollectionService } from '../services/NodeIKernelCollectionService';
import { NodeIKernelRecentContactService } from '../services/NodeIKernelRecentContactService';
import { NodeIKernelMSFService } from '../services/NodeIKernelMSFService';
import { NodeIkernelTestPerformanceService } from '../services/NodeIkernelTestPerformanceService';
import { NodeIKernelECDHService } from '../services/NodeIKernelECDHService';
export interface NodeQQNTWrapperUtil {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new (): NodeQQNTWrapperUtil;
new(): NodeQQNTWrapperUtil;
getNTUserDataInfoConfig(): string;
@ -110,7 +109,7 @@ export interface NodeQQNTWrapperUtil {
arg1: unknown,
arg2: unknown,
arg3: number,
arg4: number
arg4: number,
): unknown;
reportCountIndicators(
@ -118,7 +117,7 @@ export interface NodeQQNTWrapperUtil {
arg1: Map<unknown, unknown>,
arg2: string,
arg3: number,
arg4: boolean
arg4: boolean,
): unknown;
reportValueIndicators(
@ -126,7 +125,7 @@ export interface NodeQQNTWrapperUtil {
arg1: Map<unknown, unknown>,
arg2: string,
arg3: boolean,
arg4: number
arg4: number,
): unknown;
checkNewUserDataSaveDirAvailable(arg0: string): unknown;
@ -150,13 +149,13 @@ export interface NodeQQNTWrapperUtil {
export interface NodeIQQNTWrapperSession {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new (): NodeIQQNTWrapperSession;
new(): NodeIQQNTWrapperSession;
init(
wrapperSessionInitConfig: WrapperSessionInitConfig,
nodeIDependsAdapter: NodeIDependsAdapter,
nodeIDispatcherAdapter: NodeIDispatcherAdapter,
nodeIKernelSessionListener: NodeIKernelSessionListener
nodeIKernelSessionListener: NodeIKernelSessionListener,
): void;
startNT(n: 0): void;
@ -270,7 +269,8 @@ export interface EnginInitDesktopConfig {
export interface NodeIQQNTWrapperEngine {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new (): NodeIQQNTWrapperEngine;
new(): NodeIQQNTWrapperEngine;
initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void;
}
@ -292,6 +292,7 @@ export interface WrapperNodeApi {
NodeIKernelProfileService: NodeIKernelProfileService;
NodeIKernelProfileListener: NodeIKernelProfileListener;
}
export enum PlatformType {
KUNKNOWN,
KANDROID,
@ -299,12 +300,14 @@ export enum PlatformType {
KWINDOWS,
KMAC,
}
export enum DeviceType {
KUNKNOWN,
KPHONE,
KPAD,
KCOMPUTER,
}
//推送类型
export enum VendorType {
KNOSETONIOS = 0,
@ -315,6 +318,7 @@ export enum VendorType {
KSUPPORTVIVOPUSH = 5,
KUNSUPPORTANDROIDPUSH = 1,
}
export interface WrapperSessionInitConfig {
selfUin: string;
selfUid: string;

View File

@ -1,6 +1,6 @@
{
"fileLog": true,
"consoleLog": true,
"fileLogLevel": "debug",
"consoleLogLevel": "info"
}
"fileLog": true,
"consoleLog": true,
"fileLogLevel": "debug",
"consoleLogLevel": "info"
}

View File

@ -1,31 +1,31 @@
{
"http": {
"enable": false,
"host": "",
"port": 3000,
"secret": "",
"enableHeart": false,
"enablePost": false,
"postUrls": []
},
"ws": {
"enable": false,
"host": "",
"port": 3001
},
"reverseWs": {
"enable": false,
"urls": []
},
"GroupLocalTime": {
"Record": false,
"RecordList": []
},
"debug": false,
"heartInterval": 30000,
"messagePostFormat": "array",
"enableLocalFile2Url": true,
"musicSignUrl": "",
"reportSelfMessage": false,
"token": ""
}
"http": {
"enable": false,
"host": "",
"port": 3000,
"secret": "",
"enableHeart": false,
"enablePost": false,
"postUrls": []
},
"ws": {
"enable": false,
"host": "",
"port": 3001
},
"reverseWs": {
"enable": false,
"urls": []
},
"GroupLocalTime": {
"Record": false,
"RecordList": []
},
"debug": false,
"heartInterval": 30000,
"messagePostFormat": "array",
"enableLocalFile2Url": true,
"musicSignUrl": "",
"reportSelfMessage": false,
"token": ""
}

View File

@ -27,9 +27,9 @@ process.dlopen = (module, filename, flags = os.constants.dlopen.RTLD_LAZY) => {
if (args[ArgIndex] instanceof Object) {
let HookArg = {};
for (let ListenerName in args[ArgIndex]) {
HookArg[ListenerName] = function (...ListenerData) {
HookArg[ListenerName] = function(...ListenerData) {
try {
if (ListenerName === "onSessionInitComplete") {
if (ListenerName === 'onSessionInitComplete') {
//回调成功
initCallBack.forEach((cb) => cb(...ListenerData));
clearHook();
@ -110,15 +110,15 @@ async function fetchServices(timeout = 10000) {
pollForNTInitializationCheck(),
new Promise((resolve) => {
setTimeout(() => resolve(false), timeout);
})
}),
]).then(result => result ?
{ wrapperSession, wrapperNodeApi, wrapperLoginService } :
Promise.reject()
Promise.reject(),
);
}
async function NCInit() {
console.log("[NapCat] [Info] 开始初始化NapCat");
console.log('[NapCat] [Info] 开始初始化NapCat');
try {
const { wrapperSession, wrapperLoginService } = await fetchServices();
@ -127,7 +127,7 @@ async function NCInit() {
await NCoreInitFramework(wrapperSession, wrapperLoginService, registerInitCallback);
//console.log("[NapCat] [Info] NapCat初始化完成");
} catch (error) {
console.error("[NapCat] [Error] 初始化NapCat失败", error);
console.error('[NapCat] [Error] 初始化NapCat失败', error);
}
}

View File

@ -1,24 +1,23 @@
import { NapCatPathWrapper } from "@/common/framework/napcat";
import { LogWrapper } from "@/common/utils/log";
import { proxiedListenerOf } from "@/common/utils/proxy-handler";
import { QQBasicInfoWrapper } from "@/common/utils/QQBasicInfo";
import { NapCatCore, NapCatCoreWorkingEnv, loadQQWrapper } from "@/core/core";
import { InstanceContext } from "@/core";
import { SelfInfo } from "@/core/entities";
import { LoginListener } from "@/core/listeners";
import { NodeIKernelLoginService } from "@/core/services";
import { WrapperNodeApi, NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper";
import { NapCatOneBot11Adapter } from "@/onebot/main";
import { sleep } from "@/common/utils/helper";
import { NapCatPathWrapper } from '@/common/framework/napcat';
import { LogWrapper } from '@/common/utils/log';
import { proxiedListenerOf } from '@/common/utils/proxy-handler';
import { QQBasicInfoWrapper } from '@/common/utils/QQBasicInfo';
import { loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv } from '@/core/core';
import { InstanceContext } from '@/core';
import { SelfInfo } from '@/core/entities';
import { LoginListener } from '@/core/listeners';
import { NodeIKernelLoginService } from '@/core/services';
import { NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core/wrapper/wrapper';
import { NapCatOneBot11Adapter } from '@/onebot/main';
//Framework ES入口文件
export async function NCoreInitFramework(
session: NodeIQQNTWrapperSession,
loginService: NodeIKernelLoginService,
registerInitCallback: (callback: () => void) => void
registerInitCallback: (callback: () => void) => void,
) {
//在进入本层前是否登录未进行判断
console.log("NapCat Framework App Loading...");
console.log('NapCat Framework App Loading...');
const pathWrapper = new NapCatPathWrapper();
const logger = new LogWrapper(pathWrapper.logsPath);
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
@ -62,7 +61,7 @@ export class NapCatFramework {
loginService: NodeIKernelLoginService,
selfInfo: SelfInfo,
basicInfoWrapper: QQBasicInfoWrapper,
pathWrapper: NapCatPathWrapper
pathWrapper: NapCatPathWrapper,
) {
this.context = {
workingEnv: NapCatCoreWorkingEnv.Framework,
@ -71,7 +70,7 @@ export class NapCatFramework {
logger,
loginService,
basicInfoWrapper,
pathWrapper
pathWrapper,
};
this.core = new NapCatCore(this.context, selfInfo);
}

View File

@ -11,10 +11,12 @@ class BaseAction<PayloadType, ReturnDataType> {
private validate: undefined | ValidateFunction<any> = undefined;
PayloadSchema: any = undefined;
OneBotContext: NapCatOneBot11Adapter;
constructor(onebotContext:NapCatOneBot11Adapter,coreContext: NapCatCore) {
constructor(onebotContext: NapCatOneBot11Adapter, coreContext: NapCatCore) {
this.OneBotContext = onebotContext;
this.CoreContext = coreContext;
}
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
if (this.PayloadSchema) {
this.validate = new Ajv({ allowUnionTypes: true }).compile(this.PayloadSchema);
@ -26,11 +28,11 @@ class BaseAction<PayloadType, ReturnDataType> {
});
return {
valid: false,
message: errorMessages.join('\n') as string || '未知错误'
message: errorMessages.join('\n') as string || '未知错误',
};
}
return {
valid: true
valid: true,
};
}

View File

@ -10,7 +10,7 @@ export class OB11Response {
data: data,
message: message,
wording: message,
echo: null
echo: null,
};
}

View File

@ -1,11 +1,12 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
rawData: { type: 'string' },
brief: { type: 'string' }
brief: { type: 'string' },
},
required: ['brief', 'rawData'],
} as const satisfies JSONSchema;
@ -15,12 +16,13 @@ type Payload = FromSchema<typeof SchemaData>;
export class CreateCollection extends BaseAction<Payload, any> {
actionName = ActionName.CreateCollection;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
return await this.CoreContext.getApiContext().CollectionApi.createCollection(
this.CoreContext.selfInfo.uin,
this.CoreContext.selfInfo.uid,
this.CoreContext.selfInfo.nick,
payload.brief, payload.rawData
payload.brief, payload.rawData,
);
}
}

View File

@ -1,11 +1,12 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
const SchemaData = {
type: 'object',
properties: {
count: { type: 'number' },
}
},
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -13,8 +14,9 @@ type Payload = FromSchema<typeof SchemaData>;
export class FetchCustomFace extends BaseAction<Payload, string[]> {
actionName = ActionName.FetchCustomFace;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
//48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa
//48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa
const ret = await this.CoreContext.getApiContext().MsgApi.fetchFavEmojiList(payload.count || 48);
return ret.emojiInfoList.map(e => e.url);
}

View File

@ -12,9 +12,9 @@ const SchemaData = {
emojiId: { type: 'string' },
emojiType: { type: 'string' },
message_id: { type: ['string', 'number'] },
count: { type: 'number' }
count: { type: 'number' },
},
required: ['emojiId', 'emojiType', 'message_id']
required: ['emojiId', 'emojiType', 'message_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -22,10 +22,11 @@ type Payload = FromSchema<typeof SchemaData>;
export class FetchEmojiLike extends BaseAction<Payload, any> {
actionName = ActionName.FetchEmojiLike;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if(!msgIdPeer) throw new Error('消息不存在');
if (!msgIdPeer) throw new Error('消息不存在');
const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
return await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, payload.count);
}

View File

@ -1,4 +1,3 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
@ -7,7 +6,7 @@ const SchemaData = {
type: 'object',
properties: {
category: { type: 'number' },
count: { type: 'number' }
count: { type: 'number' },
},
required: ['category', 'count'],
} as const satisfies JSONSchema;
@ -17,6 +16,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetCollectionList extends BaseAction<Payload, any> {
actionName = ActionName.GetCollectionList;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQCollectionApi = this.CoreContext.getApiContext().CollectionApi;
return await NTQQCollectionApi.getAllCollection(payload.category, payload.count);

View File

@ -1,4 +1,3 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { OB11Constructor } from '@/onebot/helper/constructor';

View File

@ -1,11 +1,10 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQGroupApi } from '@/core/apis/group';
interface OB11GroupRequestNotify {
group_id: number,
user_id: number,
flag: string
group_id: number,
user_id: number,
flag: string
}
export default class GetGroupAddRequest extends BaseAction<null, OB11GroupRequestNotify[] | null> {

View File

@ -1,7 +1,9 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
export class GetProfileLike extends BaseAction<void, any> {
actionName = ActionName.GetProfileLike;
protected async _handle(payload: void) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.getProfileLike(this.CoreContext.selfInfo.uid);

View File

@ -1,11 +1,11 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis';
export class GetRobotUinRange extends BaseAction<void, Array<any>> {
actionName = ActionName.GetRobotUinRange;
protected async _handle(payload: void) {
// console.log(await NTQQUserApi.getRobotUinRange());
// console.log(await NTQQUserApi.getRobotUinRange());
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
return await NTQQUserApi.getRobotUinRange();
}

View File

@ -9,7 +9,7 @@ const SchemaData = {
properties: {
image: { type: 'string' },
},
required: ['image']
required: ['image'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -17,9 +17,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class OCRImage extends BaseAction<Payload, any> {
actionName = ActionName.OCRImage;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi;
const { path, isLocal, errMsg,success } = (await uri2local(this.CoreContext.NapCatTempPath,payload.image));
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.image));
if (!success) {
throw `OCR ${payload.image}失败,image字段可能格式不正确`;
}
@ -27,7 +28,8 @@ export class OCRImage extends BaseAction<Payload, any> {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQSystemApi.ORCImage(path);
if (!isLocal) {
fs.unlink(path, () => { });
fs.unlink(path, () => {
});
}
if (!ret) {
throw `OCR ${payload.file}失败`;
@ -35,11 +37,13 @@ export class OCRImage extends BaseAction<Payload, any> {
return ret.result;
}
if (!isLocal) {
fs.unlink(path, () => { });
fs.unlink(path, () => {
});
}
throw `OCR ${payload.file}失败,文件可能不存在`;
}
}
export class IOCRImage extends OCRImage {
actionName = ActionName.IOCRImage;
}

View File

@ -1,17 +1,18 @@
import BaseAction from '../BaseAction';
import { ActionName, BaseCheckResult } from '../types';
import * as fs from 'node:fs';
import { NTQQUserApi } from '@/core/apis/user';
import { checkFileReceived, uri2local } from '@/common/utils/file';
// import { log } from "../../../common/utils";
interface Payload {
file: string,
groupCode: string
file: string,
groupCode: string
}
export default class SetGroupHeader extends BaseAction<Payload, any> {
actionName = ActionName.SetGroupHeader;
// 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string' || !payload.groupCode || typeof payload.groupCode != 'string') {
@ -24,6 +25,7 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
valid: true,
};
}
protected async _handle(payload: Payload): Promise<any> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file));
@ -34,7 +36,8 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQGroupApi.setGroupAvatar(payload.groupCode, path);
if (!isLocal) {
fs.unlink(path, () => { });
fs.unlink(path, () => {
});
}
if (!ret) {
throw `头像${payload.file}设置失败,api无返回`;
@ -48,7 +51,8 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
return ret;
} else {
if (!isLocal) {
fs.unlink(path, () => { });
fs.unlink(path, () => {
});
}
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
}

View File

@ -1,7 +1,5 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
@ -9,7 +7,7 @@ const SchemaData = {
properties: {
longNick: { type: 'string' },
},
required: [ 'longNick'],
required: ['longNick'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -17,6 +15,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetLongNick extends BaseAction<Payload, any> {
actionName = ActionName.SetLongNick;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.setLongNick(payload.longNick);

View File

@ -1,6 +1,5 @@
import BaseAction from '../BaseAction';
import { ActionName, BaseCheckResult } from '../types';
import { NTQQUserApi } from '@/core/apis';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// 设置在线状态
@ -9,7 +8,7 @@ const SchemaData = {
properties: {
status: { type: 'number' },
extStatus: { type: 'number' },
batteryStatus: { type: 'number' }
batteryStatus: { type: 'number' },
},
required: ['status', 'extStatus', 'batteryStatus'],
} as const satisfies JSONSchema;
@ -19,13 +18,14 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetOnlineStatus extends BaseAction<Payload, null> {
actionName = ActionName.SetOnlineStatus;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
// 可设置状态
// { status: 10, extStatus: 1027, batteryStatus: 0 }
// { status: 30, extStatus: 0, batteryStatus: 0 }
// { status: 50, extStatus: 0, batteryStatus: 0 }
// { status: 60, extStatus: 0, batteryStatus: 0 }
// { status: 70, extStatus: 0, batteryStatus: 0 }
// 可设置状态
// { status: 10, extStatus: 1027, batteryStatus: 0 }
// { status: 30, extStatus: 0, batteryStatus: 0 }
// { status: 50, extStatus: 0, batteryStatus: 0 }
// { status: 60, extStatus: 0, batteryStatus: 0 }
// { status: 70, extStatus: 0, batteryStatus: 0 }
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.setSelfOnlineStatus(payload.status, payload.extStatus, payload.batteryStatus);
if (ret.result !== 0) {

View File

@ -2,12 +2,14 @@ import BaseAction from '../BaseAction';
import { ActionName, BaseCheckResult } from '../types';
import * as fs from 'node:fs';
import { checkFileReceived, uri2local } from '@/common/utils/file';
interface Payload {
file: string
file: string;
}
export default class SetAvatar extends BaseAction<Payload, null> {
actionName = ActionName.SetQQAvatar;
// 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string') {
@ -20,6 +22,7 @@ export default class SetAvatar extends BaseAction<Payload, null> {
valid: true,
};
}
protected async _handle(payload: Payload): Promise<null> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file));
@ -30,7 +33,8 @@ export default class SetAvatar extends BaseAction<Payload, null> {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQUserApi.setQQAvatar(path);
if (!isLocal) {
fs.unlink(path, () => { });
fs.unlink(path, () => {
});
}
if (!ret) {
throw `头像${payload.file}设置失败,api无返回`;
@ -43,7 +47,8 @@ export default class SetAvatar extends BaseAction<Payload, null> {
}
} else {
if (!isLocal) {
fs.unlink(path, () => { });
fs.unlink(path, () => {
});
}
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
}

View File

@ -1,4 +1,3 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
@ -8,7 +7,7 @@ const SchemaData = {
properties: {
nick: { type: 'string' },
longNick: { type: 'string' },
sex: { type: 'number' }//传Sex值建议传0
sex: { type: 'number' },//传Sex值建议传0
},
required: ['nick', 'longNick', 'sex'],
} as const satisfies JSONSchema;
@ -18,6 +17,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetSelfProfile extends BaseAction<Payload, any | null> {
actionName = ActionName.SetSelfProfile;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.modifySelfProfile({
@ -25,7 +25,7 @@ export class SetSelfProfile extends BaseAction<Payload, any | null> {
longNick: payload.longNick,
sex: payload.sex,
birthday: { birthday_year: '', birthday_month: '', birthday_day: '' },
location: undefined
location: undefined,
});
return ret;
}

View File

@ -1,6 +1,5 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQSystemApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
@ -8,8 +7,8 @@ const SchemaData = {
properties: {
words: {
type: 'array',
items: { type: 'string' }
}
items: { type: 'string' },
},
},
required: ['words'],
} as const satisfies JSONSchema;
@ -19,6 +18,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class TranslateEnWordToZn extends BaseAction<Payload, Array<any> | null> {
actionName = ActionName.TranslateEnWordToZn;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi;
const ret = await NTQQSystemApi.translateEnWordToZn(payload.words);

View File

@ -17,6 +17,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class sharePeer extends BaseAction<Payload, any> {
actionName = ActionName.SharePeer;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
@ -27,20 +28,23 @@ export class sharePeer extends BaseAction<Payload, any> {
}
}
}
const SchemaDataGroupEx = {
type: 'object',
properties: {
group_id: { type: 'string' },
},
required: ['group_id']
required: ['group_id'],
} as const satisfies JSONSchema;
type PayloadGroupEx = FromSchema<typeof SchemaDataGroupEx>;
export class shareGroupEx extends BaseAction<PayloadGroupEx, any> {
actionName = ActionName.ShareGroupEx;
PayloadSchema = SchemaDataGroupEx;
protected async _handle(payload: PayloadGroupEx) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id);
}
}
}

View File

@ -1,13 +1,14 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
file_id: { type: 'string' },
},
required: ['group_id', 'file_id']
required: ['group_id', 'file_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -15,6 +16,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class DelGroupFile extends BaseAction<Payload, any> {
actionName = ActionName.DelGroupFile;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
return await NTQQGroupApi.DelGroupFile(payload.group_id.toString(), [payload.file_id]);

View File

@ -1,7 +1,6 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
const SchemaData = {
type: 'object',
@ -9,7 +8,7 @@ const SchemaData = {
group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' },
},
required: ['group_id', 'folder_id']
required: ['group_id', 'folder_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -17,6 +16,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class DelGroupFileFolder extends BaseAction<Payload, any> {
actionName = ActionName.DelGroupFileFolder;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
return (await NTQQGroupApi.DelGroupFileFolder(payload.group_id.toString(), payload.folder_id)).groupFileCommonResult;

View File

@ -6,26 +6,28 @@ import { ChatType, ElementType, FileElement, Peer, RawMessage, VideoElement } fr
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
export interface GetFilePayload {
file: string; // 文件名或者fileUuid
file: string; // 文件名或者fileUuid
}
export interface GetFileResponse {
file?: string; // path
url?: string;
file_size?: string;
file_name?: string;
base64?: string;
file?: string; // path
url?: string;
file_size?: string;
file_name?: string;
base64?: string;
}
const GetFileBase_PayloadSchema = {
type: 'object',
properties: {
file: { type: 'string' }
file: { type: 'string' },
},
required: ['file']
required: ['file'],
} as const satisfies JSONSchema;
export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
PayloadSchema: any = GetFileBase_PayloadSchema;
private getElement(msg: RawMessage): { id: string, element: VideoElement | FileElement } {
let element = msg.elements.find(e => e.fileElement);
if (!element) {
@ -38,6 +40,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
}
return { id: element.elementId, element: element.fileElement };
}
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
@ -45,9 +48,9 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQFileApi = this.CoreContext.getApiContext().FileApi;
let UuidData: {
high: string;
low: string;
} | undefined;
high: string;
low: string;
} | undefined;
try {
UuidData = UUIDConverter.decode(payload.file);
if (UuidData) {
@ -87,7 +90,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
file: downloadPath,
url: downloadPath,
file_size: fileSize,
file_name: fileName
file_name: fileName,
};
if (true/*enableLocalFile2Url*/) {
try {
@ -127,7 +130,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
file: downloadPath,
url: downloadPath,
file_size: NTSearchNameResult[0].fileSize.toString(),
file_name: NTSearchNameResult[0].fileName
file_name: NTSearchNameResult[0].fileName,
};
if (true/*enableLocalFile2Url*/) {
try {
@ -182,24 +185,24 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
// // }
// }
// }
// // log('file found', cache);
// const res: GetFileResponse = {
// file: cache.path,
// url: cache.url,
// file_size: cache.size.toString(),
// file_name: cache.name
// };
// if (enableLocalFile2Url) {
// if (!cache.url) {
// try {
// res.base64 = await fs.readFile(cache.path, 'base64');
// } catch (e) {
// throw new Error('文件下载失败. ' + e);
// }
// }
// }
//return res;
// }
// // log('file found', cache);
// const res: GetFileResponse = {
// file: cache.path,
// url: cache.url,
// file_size: cache.size.toString(),
// file_name: cache.name
// };
// if (enableLocalFile2Url) {
// if (!cache.url) {
// try {
// res.base64 = await fs.readFile(cache.path, 'base64');
// } catch (e) {
// throw new Error('文件下载失败. ' + e);
// }
// }
// }
//return res;
}
}
@ -207,20 +210,21 @@ const GetFile_PayloadSchema = {
type: 'object',
properties: {
file_id: { type: 'string' },
file: { type: 'string' }
file: { type: 'string' },
},
required: ['file_id']
required: ['file_id'],
} as const satisfies JSONSchema;
type GetFile_Payload_Internal = FromSchema<typeof GetFile_PayloadSchema>;
interface GetFile_Payload extends GetFile_Payload_Internal {
file: string
file: string;
}
export default class GetFile extends GetFileBase {
actionName = ActionName.GetFile;
PayloadSchema = GetFile_PayloadSchema;
protected async _handle(payload: GetFile_Payload): Promise<GetFileResponse> {
payload.file = payload.file_id;
return super._handle(payload);

View File

@ -1,14 +1,13 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQGroupApi, NTQQUserApi } from '@/core/apis';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
},
required: ['group_id']
required: ['group_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
@ -16,6 +15,7 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileCount extends BaseAction<Payload, { count: number }> {
actionName = ActionName.GetGroupFileCount;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const ret = await NTQQGroupApi.GetGroupFileCount([payload.group_id?.toString()]);

Some files were not shown because too many files have changed in this diff Show More