feat: 大规模去耦合

Moved various helper, event, and utility files from napcat-common to napcat-core/helper for better modularity and separation of concerns. Updated imports across packages to reflect new file locations. Removed unused dependencies from napcat-common and added them to napcat-core where needed. Also consolidated type definitions and cleaned up tsconfig settings for improved compatibility.
This commit is contained in:
手瓜一十雪 2025-11-15 13:36:33 +08:00
parent df824d77ae
commit ad4a108781
50 changed files with 87 additions and 465 deletions

View File

@ -16,14 +16,9 @@
}
},
"dependencies": {
"compressing": "^1.10.1",
"json5": "^2.2.3",
"ajv": "^8.13.0",
"file-type": "^21.0.0",
"napcat-image-size": "workspace:*",
"napcat-core": "workspace:*",
"silk-wasm": "^3.6.1",
"winston": "^3.17.0"
"silk-wasm": "^3.6.1"
},
"devDependencies": {
"@types/node": "^22.0.1"

View File

@ -1,272 +0,0 @@
import { NodeIQQNTWrapperSession } from 'napcat-core/wrapper';
import { randomUUID } from 'crypto';
import { ListenerNamingMapping, ServiceNamingMapping } from 'napcat-core/index';
interface InternalMapKey {
timeout: number;
createtime: number;
func: (...arg: any[]) => any;
checker: ((...args: any[]) => boolean) | undefined;
}
type EnsureFunc<T> = T extends (...args: any) => any ? T : never;
type FuncKeys<T> = Extract<
{
[K in keyof T]: EnsureFunc<T[K]> extends never ? never : K;
}[keyof T],
string
>;
export type ListenerClassBase = Record<string, string>;
export class NTEventWrapper {
private readonly WrapperSession: NodeIQQNTWrapperSession | undefined; // WrapperSession
private readonly listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); // ListenerName-Unique -> Listener实例
private readonly EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); // tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
constructor(
wrapperSession: NodeIQQNTWrapperSession
) {
this.WrapperSession = wrapperSession;
}
createProxyDispatch(ListenerMainName: string) {
const dispatcherListenerFunc = this.dispatcherListener.bind(this);
return new Proxy(
{},
{
get(target: any, prop: any, receiver: any) {
if (typeof target[prop] === 'undefined') {
// 如果方法不存在返回一个函数这个函数调用existentMethod
return (...args: any[]) => {
dispatcherListenerFunc(ListenerMainName, prop, ...args).then();
};
}
// 如果方法存在,正常返回
return Reflect.get(target, prop, receiver);
},
}
);
}
createEventFunction<
Service extends keyof ServiceNamingMapping,
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
T extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
const eventNameArr = eventName.split('/');
type eventType = {
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>>; };
};
if (eventNameArr.length > 1) {
const serviceName = 'get' + (eventNameArr[0]?.replace('NodeIKernel', '') ?? '');
const eventName = eventNameArr[1];
const services = (this.WrapperSession as unknown as eventType)[serviceName]?.();
if (!services || !eventName) {
return undefined;
}
let event = services[eventName];
// 重新绑定this
event = event?.bind(services);
if (event) {
return event as T;
}
return undefined;
}
return undefined;
}
createListenerFunction<T> (listenerMainName: string, uniqueCode: string = ''): T {
const existListener = this.listenerManager.get(listenerMainName + uniqueCode);
if (!existListener) {
const Listener = this.createProxyDispatch(listenerMainName);
const ServiceSubName = /^NodeIKernel(.*?)Listener$/.exec(listenerMainName)![1];
const Service = `NodeIKernel${ServiceSubName}Service/addKernel${ServiceSubName}Listener`;
// @ts-ignore
this.createEventFunction(Service)(Listener as T);
this.listenerManager.set(listenerMainName + uniqueCode, Listener);
return Listener as T;
}
return existListener as T;
}
// 统一回调清理事件
async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
this.EventTask.get(ListenerMainName)
?.get(ListenerSubName)
?.forEach((task, uuid) => {
if (task.createtime + task.timeout < Date.now()) {
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid);
return;
}
if (task?.checker?.(...args)) {
task.func(...args);
}
});
}
async callNoListenerEvent<
Service extends keyof ServiceNamingMapping,
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
>(
serviceAndMethod: `${Service}/${ServiceMethod}`,
...args: Parameters<EventType>
): Promise<Awaited<ReturnType<EventType>>> {
return (this.createEventFunction(serviceAndMethod))!(...args);
}
async registerListen<
Listener extends keyof ListenerNamingMapping,
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
>(
listenerAndMethod: `${Listener}/${ListenerMethod}`,
checker: (...args: Parameters<ListenerType>) => boolean,
waitTimes = 1,
timeout = 5000
) {
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
const ListenerNameList = listenerAndMethod.split('/');
const ListenerMainName = ListenerNameList[0] ?? '';
const ListenerSubName = ListenerNameList[1] ?? '';
const id = randomUUID();
let complete = 0;
let retData: Parameters<ListenerType> | undefined;
function sendDataCallback() {
if (complete === 0) {
reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
} else {
resolve(retData!);
}
}
const timeoutRef = setTimeout(sendDataCallback, timeout);
const eventCallback = {
timeout,
createtime: Date.now(),
checker,
func: (...args: Parameters<ListenerType>) => {
complete++;
retData = args;
if (complete >= waitTimes) {
clearTimeout(timeoutRef);
sendDataCallback();
}
},
};
if (!this.EventTask.get(ListenerMainName)) {
this.EventTask.set(ListenerMainName, new Map());
}
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
}
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
this.createListenerFunction(ListenerMainName);
});
}
async callNormalEventV2<
Service extends keyof ServiceNamingMapping,
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
Listener extends keyof ListenerNamingMapping,
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
>(
serviceAndMethod: `${Service}/${ServiceMethod}`,
listenerAndMethod: `${Listener}/${ListenerMethod}`,
args: Parameters<EventType>,
checkerEvent: (ret: Awaited<ReturnType<EventType>>) => boolean = () => true,
checkerListener: (...args: Parameters<ListenerType>) => boolean = () => true,
callbackTimesToWait = 1,
timeout = 5000
) {
const id = randomUUID();
let complete = 0;
let retData: Parameters<ListenerType> | undefined;
let retEvent: any = {};
function sendDataCallback(resolve: any, reject: any) {
if (complete === 0) {
reject(
new Error(
'Timeout: NTEvent serviceAndMethod:' +
serviceAndMethod +
' ListenerName:' +
listenerAndMethod +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n'
)
);
} else {
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
}
}
const ListenerNameList = listenerAndMethod.split('/');
const ListenerMainName = ListenerNameList[0] ?? '';
const ListenerSubName = ListenerNameList[1] ?? '';
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
(resolve, reject) => {
const timeoutRef = setTimeout(() => sendDataCallback(resolve, reject), timeout);
const eventCallback = {
timeout,
createtime: Date.now(),
checker: checkerListener,
func: (...args: any[]) => {
complete++;
retData = args as Parameters<ListenerType>;
if (complete >= callbackTimesToWait) {
clearTimeout(timeoutRef);
sendDataCallback(resolve, reject);
}
},
};
if (!this.EventTask.get(ListenerMainName)) {
this.EventTask.set(ListenerMainName, new Map());
}
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
}
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
this.createListenerFunction(ListenerMainName);
const eventResult = this.createEventFunction(serviceAndMethod)!(...(args));
const eventRetHandle = (eventData: any) => {
retEvent = eventData;
if (!checkerEvent(retEvent) && timeoutRef.hasRef()) {
clearTimeout(timeoutRef);
reject(
new Error(
'EventChecker Failed: NTEvent serviceAndMethod:' +
serviceAndMethod +
' ListenerName:' +
listenerAndMethod +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n'
)
);
}
};
if (eventResult instanceof Promise) {
eventResult.then((eventResult: any) => {
eventRetHandle(eventResult);
})
.catch(reject);
} else {
eventRetHandle(eventResult);
}
}
);
}
}

View File

@ -1,4 +1,4 @@
import { Peer } from 'napcat-core/index';
import { Peer } from './types';
import { randomUUID } from 'crypto';
class TimeBasedCache<K, V> {

View File

@ -1,10 +1,9 @@
import path from 'node:path';
import fs from 'fs';
import os from 'node:os';
import { QQLevel } from 'napcat-core/index';
import { QQVersionConfigType } from './types';
import { QQVersionConfigType, QQLevel } from './types';
export async function solveProblem<T extends (...arg: any[]) => any> (func: T, ...args: Parameters<T>): Promise<ReturnType<T> | undefined> {
export async function solveProblem<T extends (...arg: any[]) => any>(func: T, ...args: Parameters<T>): Promise<ReturnType<T> | undefined> {
return new Promise<ReturnType<T> | undefined>((resolve) => {
try {
const result = func(...args);
@ -15,7 +14,7 @@ export async function solveProblem<T extends (...arg: any[]) => any> (func: T, .
});
}
export async function solveAsyncProblem<T extends (...args: any[]) => Promise<any>> (func: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | undefined> {
export async function solveAsyncProblem<T extends (...args: any[]) => Promise<any>>(func: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | undefined> {
return new Promise<Awaited<ReturnType<T>> | undefined>((resolve) => {
func(...args).then((result) => {
resolve(result);
@ -25,18 +24,18 @@ export async function solveAsyncProblem<T extends (...args: any[]) => Promise<an
});
}
export function sleep (ms: number): Promise<void> {
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function PromiseTimer<T> (promise: Promise<T>, ms: number): Promise<T> {
export function PromiseTimer<T>(promise: Promise<T>, ms: number): Promise<T> {
const timeoutPromise = new Promise<T>((_resolve, reject) =>
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms)
);
return Promise.race([promise, timeoutPromise]);
}
export async function runAllWithTimeout<T> (tasks: Promise<T>[], timeout: number): Promise<T[]> {
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 }),
@ -49,15 +48,15 @@ export async function runAllWithTimeout<T> (tasks: Promise<T>[], timeout: number
.map((result) => (result as { status: 'fulfilled'; value: T; }).value);
}
export function isNull (value: any) {
export function isNull(value: any) {
return value === undefined || value === null;
}
export function isNumeric (str: string) {
export function isNumeric(str: string) {
return /^\d+$/.test(str);
}
export function truncateString (obj: any, maxLength = 500) {
export function truncateString(obj: any, maxLength = 500) {
if (obj !== null && typeof obj === 'object') {
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === 'string') {
@ -74,7 +73,7 @@ export function truncateString (obj: any, maxLength = 500) {
return obj;
}
export function isEqual (obj1: any, obj2: any) {
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;
@ -90,7 +89,7 @@ export function isEqual (obj1: any, obj2: any) {
return true;
}
export function getDefaultQQVersionConfigInfo (): QQVersionConfigType {
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
if (os.platform() === 'linux') {
return {
baseVersion: '3.2.12.28060',
@ -118,7 +117,7 @@ export function getDefaultQQVersionConfigInfo (): QQVersionConfigType {
};
}
export function getQQPackageInfoPath (exePath: string = '', version?: string): string {
export function getQQPackageInfoPath(exePath: string = '', version?: string): string {
if (process.env['NAPCAT_QQ_PACKAGE_INFO_PATH']) {
return process.env['NAPCAT_QQ_PACKAGE_INFO_PATH'];
}
@ -137,7 +136,7 @@ export function getQQPackageInfoPath (exePath: string = '', version?: string): s
return packagePath;
}
export function getQQVersionConfigPath (exePath: string = ''): string | undefined {
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
if (process.env['NAPCAT_QQ_VERSION_CONFIG_PATH']) {
return process.env['NAPCAT_QQ_VERSION_CONFIG_PATH'];
}
@ -166,7 +165,7 @@ export function getQQVersionConfigPath (exePath: string = ''): string | undefine
return configVersionInfoPath;
}
export function calcQQLevel (level?: QQLevel) {
export function calcQQLevel(level?: QQLevel) {
if (!level) return 0;
// const { penguinNum, crownNum, sunNum, moonNum, starNum } = level;
const { crownNum, sunNum, moonNum, starNum } = level;
@ -174,13 +173,13 @@ export function calcQQLevel (level?: QQLevel) {
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
}
export function stringifyWithBigInt (obj: any) {
export function stringifyWithBigInt(obj: any) {
return JSON.stringify(obj, (_key, value) =>
typeof value === 'bigint' ? value.toString() : value
);
}
export function parseAppidFromMajor (nodeMajor: string): string | undefined {
export function parseAppidFromMajor(nodeMajor: string): string | undefined {
const hexSequence = 'A4 09 00 00 00 35';
const sequenceBytes = Buffer.from(hexSequence.replace(/ /g, ''), 'hex');
const filePath = path.resolve(nodeMajor);

View File

@ -1,6 +1,5 @@
import { Peer } from 'napcat-core/index';
import crypto from 'crypto';
import { Peer } from './types';
export class LimitedHashTable<K, V> {
private readonly keyToValue: Map<K, V> = new Map();
private readonly valueToKey: Map<V, K> = new Map();

View File

@ -1,106 +0,0 @@
import fs from 'node:fs';
import { systemPlatform } from '@/napcat-common/src/system';
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath, parseAppidFromMajor } from './helper';
import AppidTable from 'napcat-core/external/appid.json';
import { LogWrapper } from '@/napcat-common/src/log';
import { getMajorPath } from 'napcat-core';
import { QQAppidTableType, QQPackageInfoType, QQVersionConfigType } from './types';
export class QQBasicInfoWrapper {
QQMainPath: string | undefined;
QQPackageInfoPath: string | undefined;
QQVersionConfigPath: string | undefined;
isQuickUpdate: boolean | undefined;
QQVersionConfig: QQVersionConfigType | undefined;
QQPackageInfo: QQPackageInfoType | undefined;
QQVersionAppid: string | undefined;
QQVersionQua: string | undefined;
context: { logger: LogWrapper; };
constructor (context: { logger: LogWrapper; }) {
// 基础目录获取
this.context = context;
this.QQMainPath = process.execPath;
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
// 基础信息获取 无快更则启用默认模板填充
this.isQuickUpdate = !!this.QQVersionConfigPath;
this.QQVersionConfig = this.isQuickUpdate
? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString())
: getDefaultQQVersionConfigInfo();
this.QQPackageInfoPath = getQQPackageInfoPath(this.QQMainPath, this.QQVersionConfig?.curVersion);
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
const { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
this.QQVersionAppid = IQQVersionAppid;
this.QQVersionQua = IQQVersionQua;
}
// 基础函数
getQQBuildStr () {
return this.QQVersionConfig?.curVersion.split('-')[1] ?? this.QQPackageInfo?.buildVersion;
}
getFullQQVersion () {
const version = this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version;
if (!version) throw new Error('QQ版本获取失败');
return version;
}
requireMinNTQQBuild (buildStr: string) {
const currentBuild = +(this.getQQBuildStr() ?? '0');
if (currentBuild === 0) throw new Error('QQBuildStr获取失败');
return currentBuild >= parseInt(buildStr);
}
// 此方法不要直接使用
getQUAFallback () {
const platformMapping: Partial<Record<NodeJS.Platform, string>> = {
win32: `V1_WIN_${this.getFullQQVersion()}_${this.getQQBuildStr()}_GW_B`,
darwin: `V1_MAC_${this.getFullQQVersion()}_${this.getQQBuildStr()}_GW_B`,
linux: `V1_LNX_${this.getFullQQVersion()}_${this.getQQBuildStr()}_GW_B`,
};
return platformMapping[systemPlatform] ?? (platformMapping.win32)!;
}
getAppIdFallback () {
const platformMapping: Partial<Record<NodeJS.Platform, string>> = {
win32: '537246092',
darwin: '537246140',
linux: '537246140',
};
return platformMapping[systemPlatform] ?? '537246092';
}
getAppidV2 (): { appid: string; qua: string; } {
// 通过已有表 性能好
const appidTbale = AppidTable as unknown as QQAppidTableType;
const fullVersion = this.getFullQQVersion();
if (fullVersion) {
const data = appidTbale[fullVersion];
if (data) {
return data;
}
}
// 通过Major拉取 性能差
try {
const majorAppid = this.getAppidV2ByMajor(fullVersion);
if (majorAppid) {
this.context.logger.log('[QQ版本兼容性检测] 当前版本Appid未内置 通过Major获取 为了更好的性能请尝试更新NapCat');
return { appid: majorAppid, qua: this.getQUAFallback() };
}
} catch {
this.context.logger.log('[QQ版本兼容性检测] 通过Major 获取Appid异常 请检测NapCat/QQNT是否正常');
}
// 最终兜底为老版本
this.context.logger.log('[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常');
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`);
return { appid: this.getAppIdFallback(), qua: this.getQUAFallback() };
}
getAppidV2ByMajor (QQVersion: string) {
const majorPath = getMajorPath(QQVersion);
const appid = parseAppidFromMajor(majorPath);
return appid;
}
}

View File

@ -15,3 +15,14 @@ export type QQVersionConfigType = {
export type QQAppidTableType = {
[key: string]: { appid: string, qua: string };
};
export interface Peer {
chatType: number; // 聊天类型
peerUid: string; // 对等方的唯一标识符
guildId?: string; // 可选的频道ID
}
export interface QQLevel {
crownNum: number;
sunNum: number;
moonNum: number;
starNum: number;
}

View File

@ -11,11 +11,11 @@
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": "src",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"strict": true,
"noImplicitAny": true,
"noImplicitAny": false,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"alwaysStrict": true,

View File

@ -15,9 +15,9 @@ import {
} from '@/napcat-core/index';
import { isNumeric, solveAsyncProblem } from 'napcat-common/src/helper';
import { LimitedHashTable } from 'napcat-common/src/message-unique';
import { NTEventWrapper } from 'napcat-common/src/event';
import { CancelableTask, TaskExecutor } from 'napcat-common/src/cancel-task';
import { createGroupDetailInfoV2Param, createGroupExtFilter, createGroupExtInfo } from '../data';
import { NTEventWrapper } from '../helper/event';
export class NTQQGroupApi {
context: InstanceContext;
@ -395,7 +395,7 @@ export class NTQQGroupApi {
'NodeIKernelGroupListener/onMemberInfoChange',
[groupCode, [uid], forced],
(ret) => ret.result === 0,
(params, _, members) => params === GroupCode && members.size > 0 && members.has(uid),
(params: string, _: any, members: Map<string, GroupMember>) => params === GroupCode && members.size > 0 && members.has(uid),
1,
forced ? 2500 : 250
);

View File

@ -1,9 +1,9 @@
import * as os from 'os';
import offset from '@/napcat-core/external/napi2native.json';
import { InstanceContext, NapCatCore } from '@/napcat-core/index';
import { LogWrapper } from 'napcat-common/src/log';
import { PacketClientSession } from '@/napcat-core/packet/clientSession';
import { napCatVersion } from 'napcat-common/src/version';
import { LogWrapper } from '../helper/log';
interface OffsetType {
[key: string]: {

View File

@ -2,10 +2,10 @@ import fsPromise from 'fs/promises';
import path from 'node:path';
import { randomUUID } from 'crypto';
import { EncodeResult, getDuration, getWavFileInfo, isSilk, isWav } from 'silk-wasm';
import { LogWrapper } from '@/napcat-common/src/log';
import { EncodeArgs } from '@/napcat-common/src/audio-worker';
import { FFmpegService } from '@/napcat-common/src/ffmpeg';
import { runTask } from './worker';
import { LogWrapper } from '@/napcat-core/helper/log';
import { EncodeArgs } from 'napcat-common/src/audio-worker';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { runTask } from 'napcat-common/src/worker';
import { fileURLToPath } from 'node:url';
const ALLOW_SAMPLE_RATE = [8000, 12000, 16000, 24000, 32000, 44100, 48000];

View File

@ -1,6 +1,6 @@
import path from 'node:path';
import fs from 'node:fs';
import type { NapCatCore } from 'napcat-core';
import type { NapCatCore } from '@/napcat-core';
import json5 from 'json5';
import Ajv, { AnySchema, ValidateFunction } from 'ajv';

View File

@ -1,4 +1,4 @@
import { ConfigBase } from 'napcat-common/src/config-base';
import { ConfigBase } from '@/napcat-core/helper/config-base';
import { NapCatCore } from '@/napcat-core/index';
import { Type, Static } from '@sinclair/typebox';
import { AnySchema } from 'ajv';

View File

@ -6,7 +6,7 @@ import * as os from 'os';
import * as compressing from 'compressing'; // 修正导入方式
import { pipeline } from 'stream/promises';
import { fileURLToPath } from 'url';
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
const downloadOri = 'https://github.com/NapNeko/ffmpeg-build/releases/download/v1.0.0/ffmpeg-7.1.1-win64.zip';
const urls = [

View File

@ -3,7 +3,7 @@
* FFmpeg
*/
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
import { FFmpegAddonAdapter } from './ffmpeg-addon-adapter';
import { FFmpegExecAdapter } from './ffmpeg-exec-adapter';
import type { IFFmpegAdapter } from './ffmpeg-adapter-interface';

View File

@ -10,7 +10,7 @@ import { promisify } from 'util';
import { fileTypeFromFile } from 'file-type';
import { imageSizeFallBack } from 'napcat-image-size/src/index';
import { downloadFFmpegIfNotExists } from './download-ffmpeg';
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
import type { IFFmpegAdapter, VideoInfoResult } from './ffmpeg-adapter-interface';
const execFileAsync = promisify(execFile);

View File

@ -3,7 +3,7 @@ import path from 'path';
import type { VideoInfo } from './video';
import { fileTypeFromFile } from 'file-type';
import { platform } from 'node:os';
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
import { FFmpegAdapterFactory } from './ffmpeg-adapter-factory';
import type { IFFmpegAdapter } from './ffmpeg-adapter-interface';

View File

@ -1,5 +1,5 @@
import * as crypto from 'node:crypto';
import { PacketMsg } from 'napcat-core/packet/message/message';
import { PacketMsg } from '@/napcat-core/packet/message/message';
interface ForwardMsgJson {
app: string

View File

@ -1,8 +1,8 @@
import winston, { format, transports } from 'winston';
import { truncateString } from './helper';
import { truncateString } from 'napcat-common/src/helper';
import path from 'node:path';
import fs from 'node:fs/promises';
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from 'napcat-core/index';
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/napcat-core/index';
import EventEmitter from 'node:events';
export enum LogLevel {
DEBUG = 'debug',

View File

@ -1,4 +1,4 @@
import { LogWrapper } from '@/napcat-common/src/log';
import { LogWrapper } from '@/napcat-core/helper/log';
export function proxyHandlerOf (logger: LogWrapper) {
return {

View File

@ -2,7 +2,7 @@ import fs from 'node:fs';
import { systemPlatform } from 'napcat-common/src/system';
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath, parseAppidFromMajor } from 'napcat-common/src/helper';
import AppidTable from '@/napcat-core/external/appid.json';
import { LogWrapper } from 'napcat-common/src/log';
import { LogWrapper } from './log';
import { getMajorPath } from '@/napcat-core/index';
import { QQAppidTableType, QQPackageInfoType, QQVersionConfigType } from 'napcat-common/src/types';

View File

@ -1,5 +1,5 @@
import { LogWrapper } from 'napcat-common/src/log';
import { RequestUtil } from 'napcat-common/src/request';
import { LogWrapper } from './log';
interface ServerRkeyData {
group_rkey: string;

View File

@ -16,19 +16,19 @@ import {
WrapperNodeApi,
WrapperSessionInitConfig,
} from '@/napcat-core/wrapper';
import { LogLevel, LogWrapper } from 'napcat-common/src/log';
import { LogLevel, LogWrapper } from '@/napcat-core/helper/log';
import { NodeIKernelLoginService } from '@/napcat-core/services';
import { QQBasicInfoWrapper } from 'napcat-common/src/qq-basic-info';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
import { NapCatPathWrapper } from 'napcat-common/src/path';
import path from 'node:path';
import fs from 'node:fs';
import { hostname, systemName, systemVersion } from 'napcat-common/src/system';
import { NTEventWrapper } from 'napcat-common/src/event';
import { NTEventWrapper } from '@/napcat-core/helper/event';
import { KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/napcat-core/types';
import { NapCatConfigLoader, NapcatConfigSchema } from '@/napcat-core/helper/config';
import os from 'node:os';
import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/napcat-core/listeners';
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { NTQQPacketApi } from './apis/packet';
import { NativePacketHandler } from './packet/handler/client';
import { container, ReceiverServiceRegistry } from './packet/handler/serviceRegister';

View File

@ -16,10 +16,14 @@
}
},
"dependencies": {
"winston": "^3.17.0",
"json5": "^2.2.3",
"@protobuf-ts/runtime": "^2.11.1",
"ajv": "^8.13.0",
"@sinclair/typebox": "^0.34.38",
"file-type": "^21.0.0",
"compressing": "^1.10.1",
"napcat-image-size": "workspace:*",
"napcat-common": "workspace:*",
"napcat-protobuf": "workspace:*"
},

View File

@ -1,5 +1,6 @@
import { LogLevel, LogWrapper } from 'napcat-common/src/log';
import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext';
import { LogWrapper, LogLevel } from '@/napcat-core/helper/log';
// TODO: check bind?
export class PacketLogger {

View File

@ -2,8 +2,8 @@ import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import { constants } from 'node:os';
import { LogWrapper } from 'napcat-common/src/log';
import offset from '@/napcat-core/external/packet.json';
import { LogWrapper } from '../../helper/log';
interface OffsetType {
[key: string]: {
recv: string;

View File

@ -33,7 +33,7 @@ import {
SendVideoElement,
Peer,
} from '@/napcat-core/index';
import { ForwardMsgBuilder } from 'napcat-common/src/forward-msg-builder';
import { ForwardMsgBuilder } from '@/napcat-core/helper/forward-msg-builder';
import { PacketMsg, PacketSendMsgElement } from '@/napcat-core/packet/message/message';
export type ParseElementFnR = [MessageElement, NapProtoDecodeStructType<typeof Elem> | null] | undefined;

View File

@ -11,7 +11,6 @@
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"strict": true,

View File

@ -1,16 +1,12 @@
import { NapCatPathWrapper } from 'napcat-common/src/path';
import { LogWrapper } from 'napcat-common/src/log';
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
import { QQBasicInfoWrapper } from 'napcat-common/src/qq-basic-info';
import { InstanceContext, loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv } from 'napcat-core/index';
import { SelfInfo } from 'napcat-core/types';
import { NodeIKernelLoginListener } from 'napcat-core/listeners';
import { NodeIKernelLoginService } from 'napcat-core/services';
import { NodeIQQNTWrapperSession, WrapperNodeApi } from 'napcat-core/wrapper';
import { InitWebUi, WebUiConfig, webUiRuntimePort } from 'napcat-webui-backend/index';
import { NapCatOneBot11Adapter } from 'napcat-onebot/index';
import { FFmpegService } from 'napcat-common/src/ffmpeg';
import { NativePacketHandler } from 'napcat-core/packet/handler/client';
import { FFmpegService } from 'napcat-core/helper/ffmpeg/ffmpeg';
import { LogWrapper } from 'napcat-core/helper/log';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
import { InstanceContext, loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv, NodeIKernelLoginListener, NodeIKernelLoginService, NodeIQQNTWrapperSession, SelfInfo, WrapperNodeApi } from '@/napcat-core';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
// Framework ES入口文件
export async function getWebUiUrl () {

View File

@ -11,7 +11,6 @@
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"strict": true,

View File

@ -2,7 +2,7 @@ import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile';
import { ActionName } from '@/napcat-onebot/action/router';
import { promises as fs } from 'fs';
import { decode } from 'silk-wasm';
import { FFmpegService } from 'napcat-common/src/ffmpeg';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
const out_format = ['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac'];

View File

@ -11,7 +11,7 @@ import { decodeCQCode } from '@/napcat-onebot/helper/cqcode';
import { MessageUnique } from 'napcat-common/src/message-unique';
import { ChatType, ElementType, NapCatCore, Peer, RawMessage, SendArkElement, SendMessageElement } from 'napcat-core';
import { OneBotAction } from '@/napcat-onebot/action/OneBotAction';
import { ForwardMsgBuilder } from 'napcat-common/src/forward-msg-builder';
import { ForwardMsgBuilder } from '@/napcat-core/helper/forward-msg-builder';
import { stringifyWithBigInt } from 'napcat-common/src/helper';
import { PacketMsg } from 'napcat-core/packet/message/message';
import { rawMsgWithSendMsg } from 'napcat-core/packet/message/converter';

View File

@ -5,7 +5,7 @@ import { NetworkAdapterConfig } from '@/napcat-onebot/config/config';
import { StreamPacket, StreamStatus } from './StreamBasic';
import fs from 'fs';
import { decode } from 'silk-wasm';
import { FFmpegService } from 'napcat-common/src/ffmpeg';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { BaseDownloadStream, DownloadResult } from './BaseDownloadStream';
const out_format = ['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac'];

View File

@ -1,10 +1,9 @@
import { NapCatOneBot11Adapter } from '@/napcat-onebot/index';
import { encodeSilk } from 'napcat-common/src/audio';
import { FFmpegService } from 'napcat-common/src/ffmpeg';
import { encodeSilk } from '@/napcat-core/helper/audio';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { calculateFileMD5 } from 'napcat-common/src/file';
import { defaultVideoThumbB64 } from 'napcat-common/src/video';
import { ElementType, NapCatCore, PicElement, PicSubType, SendFileElement, SendPicElement, SendPttElement, SendVideoElement } from 'napcat-core';
import { getFileTypeForSendType } from 'napcat-core/helper/msg';
import { imageSizeFallBack } from 'napcat-image-size';
@ -13,6 +12,7 @@ import { fileTypeFromFile } from 'file-type';
import pathLib from 'node:path';
import fsPromises from 'fs/promises';
import fs from 'fs';
import { defaultVideoThumbB64 } from '@/napcat-core/helper/ffmpeg/video';
export class OneBotFileApi {
obContext: NapCatOneBot11Adapter;
core: NapCatCore;

View File

@ -36,7 +36,7 @@ import { uriToLocalFile } from 'napcat-common/src/file';
import { RequestUtil } from 'napcat-common/src/request';
import fsPromise from 'node:fs/promises';
import { OB11FriendAddNoticeEvent } from '@/napcat-onebot/event/notice/OB11FriendAddNoticeEvent';
import { ForwardMsgBuilder } from 'napcat-common/src/forward-msg-builder';
import { ForwardMsgBuilder } from '@/napcat-core/helper/forward-msg-builder';
import { NapProtoMsg } from 'napcat-protobuf';
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '../event/notice/OB11GroupDecreaseEvent';

View File

@ -1,4 +1,4 @@
import { ConfigBase } from 'napcat-common/src/config-base';
import { ConfigBase } from 'napcat-core/helper/config-base';
import type { NapCatCore } from 'napcat-core';
import { OneBotConfig } from './config';
import { AnySchema } from 'ajv';

View File

@ -38,7 +38,6 @@ import { ActionMap, createActionMap } from '@/napcat-onebot/action';
import { WebUiDataRuntime } from 'napcat-webui-backend/src/helper/Data';
import { OB11InputStatusEvent } from '@/napcat-onebot/event/notice/OB11InputStatusEvent';
import { MessageUnique } from 'napcat-common/src/message-unique';
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
import { OB11FriendRequestEvent } from '@/napcat-onebot/event/request/OB11FriendRequest';
import { OB11GroupRequestEvent } from '@/napcat-onebot/event/request/OB11GroupRequest';
import { OB11FriendRecallNoticeEvent } from '@/napcat-onebot/event/notice/OB11FriendRecallNoticeEvent';
@ -54,6 +53,7 @@ import { IOB11NetworkAdapter } from '@/napcat-onebot/network/adapter';
import { OB11HttpSSEServerAdapter } from './network/http-server-sse';
import { OB11PluginMangerAdapter } from './network/plugin-manger';
import { existsSync } from 'node:fs';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { OneBotFileApi } from './api/file';
interface ApiListType {

View File

@ -1,5 +1,5 @@
import { NetworkAdapterConfig } from '@/napcat-onebot/config/config';
import { LogWrapper } from 'napcat-common/src/log';
import { LogWrapper } from 'napcat-core/helper/log';
import { NapCatCore } from 'napcat-core';
import { NapCatOneBot11Adapter } from '@/napcat-onebot/index';
import { ActionMap } from '@/napcat-onebot/action';

View File

@ -11,7 +11,6 @@
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"strict": true,

View File

@ -1,6 +1,5 @@
import type { SelfInfo } from 'napcat-core/types';
import type { SelfInfo } from 'napcat-core/index';
import { LogWrapper } from 'napcat-common/src/log';
import { NodeIKernelLoginListener, NodeIKernelSessionListener } from 'napcat-core/listeners';
import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from 'napcat-core/adapters';
import { NapCatPathWrapper } from 'napcat-common/src/path';
@ -17,9 +16,7 @@ import {
WrapperNodeApi,
WrapperSessionInitConfig,
} from 'napcat-core';
import { QQBasicInfoWrapper } from 'napcat-common/src/qq-basic-info';
import { hostname, systemVersion } from 'napcat-common/src/system';
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
import path from 'path';
import fs from 'fs';
import os from 'os';
@ -31,9 +28,12 @@ import { WebUiDataRuntime } from 'napcat-webui-backend/src/helper/Data';
import { napCatVersion } from 'napcat-common/src/version';
import { NodeIO3MiscListener } from 'napcat-core/listeners/NodeIO3MiscListener';
import { sleep } from 'napcat-common/src/helper';
import { FFmpegService } from 'napcat-common/src/ffmpeg';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { connectToNamedPipe } from './pipe';
import { NativePacketHandler } from 'napcat-core/packet/handler/client';
import { LogWrapper } from '@/napcat-core/helper/log';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
// NapCat Shell App ES 入口文件
async function handleUncaughtExceptions (logger: LogWrapper) {
process.on('uncaughtException', (err) => {

View File

@ -1,4 +1,4 @@
import { LogWrapper } from 'napcat-common/src/log';
import { LogWrapper } from 'napcat-core/helper/log';
import * as net from 'net';
import * as process from 'process';
import { Writable } from 'stream';

View File

@ -11,7 +11,6 @@
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"strict": true,

View File

@ -7,7 +7,6 @@ import type { WebUiConfigType } from './src/types';
import { createServer } from 'http';
import { randomUUID } from 'node:crypto';
import { createServer as createHttpsServer } from 'https';
import { LogWrapper } from 'napcat-common/src/log';
import { NapCatPathWrapper } from 'napcat-common/src/path';
import { WebUiConfigWrapper } from '@/napcat-webui-backend/src/helper/config';
import { ALLRouter } from '@/napcat-webui-backend/src/router';
@ -20,6 +19,7 @@ import multer from 'multer';
import * as net from 'node:net';
import { WebUiDataRuntime } from './src/helper/Data';
import { existsSync, readFileSync } from 'node:fs'; // 引入multer用于错误捕获
import { LogWrapper } from '@/napcat-core/helper/log';
// 实例化Express
const app = express();

View File

@ -1,6 +1,6 @@
import type { RequestHandler } from 'express';
import { sendError, sendSuccess } from '../utils/response';
import { logSubscription } from 'napcat-common/src/log';
import { logSubscription } from 'napcat-core/helper/log';
import { terminalManager } from '../terminal/terminal_manager';
import { WebUiConfig } from '@/napcat-webui-backend/index';
// 判断是否是 macos

View File

@ -2,11 +2,11 @@
import { WebUiConfig } from '../../index';
import { AuthHelper } from '../helper/SignToken';
import type { WebUiCredentialJson } from '@/napcat-webui-backend/src/types';
import { LogWrapper } from 'napcat-common/src/log';
import { WebSocket, WebSocketServer } from 'ws';
import os from 'os';
import { IPty, spawn as ptySpawn } from 'napcat-pty';
import { randomUUID } from 'crypto';
import { LogWrapper } from '@/napcat-core/helper/log';
interface TerminalInstance {
pty: IPty; // 改用 PTY 实例

View File

@ -11,7 +11,6 @@
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"strict": true,