mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-18 20:30:08 +08:00
Add ESLint config and update code style
Introduced a new eslint.config.js using neostandard and added related devDependencies. Updated codebase for consistent formatting, spacing, and function declarations. Minor refactoring and cleanup across multiple files to improve readability and maintain code style compliance.
This commit is contained in:
parent
1990761ad6
commit
fa80441e36
52
eslint.config.js
Normal file
52
eslint.config.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import neostandard from 'neostandard';
|
||||||
|
|
||||||
|
/** 尾随逗号 */
|
||||||
|
const commaDangle = val => {
|
||||||
|
if (val?.rules?.['@stylistic/comma-dangle']?.[0] === 'warn') {
|
||||||
|
const rule = val?.rules?.['@stylistic/comma-dangle']?.[1];
|
||||||
|
Object.keys(rule).forEach(key => {
|
||||||
|
rule[key] = 'always-multiline';
|
||||||
|
});
|
||||||
|
val.rules['@stylistic/comma-dangle'][1] = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 三元表达式 */
|
||||||
|
if (val?.rules?.['@stylistic/indent']) {
|
||||||
|
val.rules['@stylistic/indent'][2] = {
|
||||||
|
...val.rules?.['@stylistic/indent']?.[2],
|
||||||
|
flatTernaryExpressions: true,
|
||||||
|
offsetTernaryExpressions: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 支持下划线 - 禁用 camelcase 规则 */
|
||||||
|
if (val?.rules?.camelcase) {
|
||||||
|
val.rules.camelcase = 'off';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 未使用的变量强制报错 */
|
||||||
|
if (val?.rules?.['@typescript-eslint/no-unused-vars']) {
|
||||||
|
val.rules['@typescript-eslint/no-unused-vars'] = ['error', {
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
caughtErrorsIgnorePattern: '^_',
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 忽略的文件 */
|
||||||
|
const ignores = [
|
||||||
|
'node_modules',
|
||||||
|
'**/dist/**',
|
||||||
|
'launcher',
|
||||||
|
];
|
||||||
|
|
||||||
|
const options = neostandard({
|
||||||
|
ts: true,
|
||||||
|
ignores,
|
||||||
|
semi: true, // 强制使用分号
|
||||||
|
}).map(commaDangle);
|
||||||
|
|
||||||
|
export default options;
|
||||||
@ -11,13 +11,17 @@
|
|||||||
"dev:shell": "pnpm --filter napcat-develop run dev || exit 1",
|
"dev:shell": "pnpm --filter napcat-develop run dev || exit 1",
|
||||||
"typecheck": "pnpm -r --if-present run typecheck",
|
"typecheck": "pnpm -r --if-present run typecheck",
|
||||||
"test": "pnpm --filter napcat-test run test",
|
"test": "pnpm --filter napcat-test run test",
|
||||||
"test:ui": "pnpm --filter napcat-test run test:ui"
|
"test:ui": "pnpm --filter napcat-test run test:ui",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lint:fix": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
"@vitejs/plugin-react-swc": "^4.2.2",
|
"@vitejs/plugin-react-swc": "^4.2.2",
|
||||||
"@vitest/ui": "^4.0.9",
|
"@vitest/ui": "^4.0.9",
|
||||||
|
"eslint": "^9.39.1",
|
||||||
"inversify": "^7.10.4",
|
"inversify": "^7.10.4",
|
||||||
|
"neostandard": "^0.12.2",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"typescript": "^5.3.0",
|
"typescript": "^5.3.0",
|
||||||
"vite": "^6.4.1",
|
"vite": "^6.4.1",
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import fs from 'fs';
|
|||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import { QQVersionConfigType, QQLevel } 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) => {
|
return new Promise<ReturnType<T> | undefined>((resolve) => {
|
||||||
try {
|
try {
|
||||||
const result = func(...args);
|
const result = func(...args);
|
||||||
@ -14,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) => {
|
return new Promise<Awaited<ReturnType<T>> | undefined>((resolve) => {
|
||||||
func(...args).then((result) => {
|
func(...args).then((result) => {
|
||||||
resolve(result);
|
resolve(result);
|
||||||
@ -24,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));
|
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) =>
|
const timeoutPromise = new Promise<T>((_resolve, reject) =>
|
||||||
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms)
|
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms)
|
||||||
);
|
);
|
||||||
return Promise.race([promise, timeoutPromise]);
|
return Promise.race([promise, timeoutPromise]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runAllWithTimeout<T>(tasks: Promise<T>[], timeout: number): Promise<T[]> {
|
export async function runAllWithTimeout<T> (tasks: Promise<T>[], timeout: number): Promise<T[]> {
|
||||||
const wrappedTasks = tasks.map((task) =>
|
const wrappedTasks = tasks.map((task) =>
|
||||||
PromiseTimer(task, timeout).then(
|
PromiseTimer(task, timeout).then(
|
||||||
(result) => ({ status: 'fulfilled', value: result }),
|
(result) => ({ status: 'fulfilled', value: result }),
|
||||||
@ -48,15 +48,15 @@ export async function runAllWithTimeout<T>(tasks: Promise<T>[], timeout: number)
|
|||||||
.map((result) => (result as { status: 'fulfilled'; value: T; }).value);
|
.map((result) => (result as { status: 'fulfilled'; value: T; }).value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNull(value: any) {
|
export function isNull (value: any) {
|
||||||
return value === undefined || value === null;
|
return value === undefined || value === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNumeric(str: string) {
|
export function isNumeric (str: string) {
|
||||||
return /^\d+$/.test(str);
|
return /^\d+$/.test(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function truncateString(obj: any, maxLength = 500) {
|
export function truncateString (obj: any, maxLength = 500) {
|
||||||
if (obj !== null && typeof obj === 'object') {
|
if (obj !== null && typeof obj === 'object') {
|
||||||
Object.keys(obj).forEach((key) => {
|
Object.keys(obj).forEach((key) => {
|
||||||
if (typeof obj[key] === 'string') {
|
if (typeof obj[key] === 'string') {
|
||||||
@ -73,7 +73,7 @@ export function truncateString(obj: any, maxLength = 500) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEqual(obj1: any, obj2: any) {
|
export function isEqual (obj1: any, obj2: any) {
|
||||||
if (obj1 === obj2) return true;
|
if (obj1 === obj2) return true;
|
||||||
if (obj1 == null || obj2 == null) return false;
|
if (obj1 == null || obj2 == null) return false;
|
||||||
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
|
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
|
||||||
@ -89,7 +89,7 @@ export function isEqual(obj1: any, obj2: any) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
export function getDefaultQQVersionConfigInfo (): QQVersionConfigType {
|
||||||
if (os.platform() === 'linux') {
|
if (os.platform() === 'linux') {
|
||||||
return {
|
return {
|
||||||
baseVersion: '3.2.12.28060',
|
baseVersion: '3.2.12.28060',
|
||||||
@ -117,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']) {
|
if (process.env['NAPCAT_QQ_PACKAGE_INFO_PATH']) {
|
||||||
return process.env['NAPCAT_QQ_PACKAGE_INFO_PATH'];
|
return process.env['NAPCAT_QQ_PACKAGE_INFO_PATH'];
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ export function getQQPackageInfoPath(exePath: string = '', version?: string): st
|
|||||||
return packagePath;
|
return packagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
|
export function getQQVersionConfigPath (exePath: string = ''): string | undefined {
|
||||||
if (process.env['NAPCAT_QQ_VERSION_CONFIG_PATH']) {
|
if (process.env['NAPCAT_QQ_VERSION_CONFIG_PATH']) {
|
||||||
return process.env['NAPCAT_QQ_VERSION_CONFIG_PATH'];
|
return process.env['NAPCAT_QQ_VERSION_CONFIG_PATH'];
|
||||||
}
|
}
|
||||||
@ -165,7 +165,7 @@ export function getQQVersionConfigPath(exePath: string = ''): string | undefined
|
|||||||
return configVersionInfoPath;
|
return configVersionInfoPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calcQQLevel(level?: QQLevel) {
|
export function calcQQLevel (level?: QQLevel) {
|
||||||
if (!level) return 0;
|
if (!level) return 0;
|
||||||
// const { penguinNum, crownNum, sunNum, moonNum, starNum } = level;
|
// const { penguinNum, crownNum, sunNum, moonNum, starNum } = level;
|
||||||
const { crownNum, sunNum, moonNum, starNum } = level;
|
const { crownNum, sunNum, moonNum, starNum } = level;
|
||||||
@ -173,13 +173,13 @@ export function calcQQLevel(level?: QQLevel) {
|
|||||||
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stringifyWithBigInt(obj: any) {
|
export function stringifyWithBigInt (obj: any) {
|
||||||
return JSON.stringify(obj, (_key, value) =>
|
return JSON.stringify(obj, (_key, value) =>
|
||||||
typeof value === 'bigint' ? value.toString() : 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 hexSequence = 'A4 09 00 00 00 35';
|
||||||
const sequenceBytes = Buffer.from(hexSequence.replace(/ /g, ''), 'hex');
|
const sequenceBytes = Buffer.from(hexSequence.replace(/ /g, ''), 'hex');
|
||||||
const filePath = path.resolve(nodeMajor);
|
const filePath = path.resolve(nodeMajor);
|
||||||
|
|||||||
@ -19,4 +19,4 @@ class Store {
|
|||||||
|
|
||||||
const store = new Store();
|
const store = new Store();
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|||||||
@ -25,4 +25,4 @@ export interface QQLevel {
|
|||||||
sunNum: number;
|
sunNum: number;
|
||||||
moonNum: number;
|
moonNum: number;
|
||||||
starNum: number;
|
starNum: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const napCatVersion = (typeof import.meta?.env !== 'undefined' && import.meta.env.VITE_NAPCAT_VERSION) || 'alpha';
|
export const napCatVersion = (typeof import.meta?.env !== 'undefined' && import.meta.env.VITE_NAPCAT_VERSION) || 'alpha';
|
||||||
|
|
||||||
|
|||||||
@ -24,4 +24,4 @@ export class NodeIDependsAdapter {
|
|||||||
|
|
||||||
// console.log('[NodeIDependsAdapter] onSendMsfReply', _seq, _cmd, _uk1, _uk2, Buffer.from(_rsp.pbBuffer).toString('hex'));
|
// console.log('[NodeIDependsAdapter] onSendMsfReply', _seq, _cmd, _uk1, _uk2, Buffer.from(_rsp.pbBuffer).toString('hex'));
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export class NTQQFileApi {
|
|||||||
'http://ss.xingzhige.com/music_card/rkey',
|
'http://ss.xingzhige.com/music_card/rkey',
|
||||||
'https://secret-service.bietiaop.com/rkeys',
|
'https://secret-service.bietiaop.com/rkeys',
|
||||||
],
|
],
|
||||||
this.context.logger
|
this.context.logger
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,6 @@ export class NTQQFileApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async downloadFileForModelId (peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) {
|
async downloadFileForModelId (peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) {
|
||||||
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
|
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
|
||||||
'NodeIKernelRichMediaService/downloadFileForModelId',
|
'NodeIKernelRichMediaService/downloadFileForModelId',
|
||||||
|
|||||||
@ -25,18 +25,18 @@ export class NTEventWrapper {
|
|||||||
private readonly listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); // ListenerName-Unique -> Listener实例
|
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}
|
private readonly EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); // tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||||
|
|
||||||
constructor(
|
constructor (
|
||||||
wrapperSession: NodeIQQNTWrapperSession
|
wrapperSession: NodeIQQNTWrapperSession
|
||||||
) {
|
) {
|
||||||
this.WrapperSession = wrapperSession;
|
this.WrapperSession = wrapperSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
createProxyDispatch(ListenerMainName: string) {
|
createProxyDispatch (ListenerMainName: string) {
|
||||||
const dispatcherListenerFunc = this.dispatcherListener.bind(this);
|
const dispatcherListenerFunc = this.dispatcherListener.bind(this);
|
||||||
return new Proxy(
|
return new Proxy(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
get(target: any, prop: any, receiver: any) {
|
get (target: any, prop: any, receiver: any) {
|
||||||
if (typeof target[prop] === 'undefined') {
|
if (typeof target[prop] === 'undefined') {
|
||||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||||
return (...args: any[]) => {
|
return (...args: any[]) => {
|
||||||
@ -94,7 +94,7 @@ export class NTEventWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 统一回调清理事件
|
// 统一回调清理事件
|
||||||
async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
async dispatcherListener (ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||||
this.EventTask.get(ListenerMainName)
|
this.EventTask.get(ListenerMainName)
|
||||||
?.get(ListenerSubName)
|
?.get(ListenerSubName)
|
||||||
?.forEach((task, uuid) => {
|
?.forEach((task, uuid) => {
|
||||||
@ -137,7 +137,7 @@ export class NTEventWrapper {
|
|||||||
let complete = 0;
|
let complete = 0;
|
||||||
let retData: Parameters<ListenerType> | undefined;
|
let retData: Parameters<ListenerType> | undefined;
|
||||||
|
|
||||||
function sendDataCallback() {
|
function sendDataCallback () {
|
||||||
if (complete === 0) {
|
if (complete === 0) {
|
||||||
reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
|
reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
|
||||||
} else {
|
} else {
|
||||||
@ -191,7 +191,7 @@ export class NTEventWrapper {
|
|||||||
let retData: Parameters<ListenerType> | undefined;
|
let retData: Parameters<ListenerType> | undefined;
|
||||||
let retEvent: any = {};
|
let retEvent: any = {};
|
||||||
|
|
||||||
function sendDataCallback(resolve: any, reject: any) {
|
function sendDataCallback (resolve: any, reject: any) {
|
||||||
if (complete === 0) {
|
if (complete === 0) {
|
||||||
reject(
|
reject(
|
||||||
new Error(
|
new Error(
|
||||||
|
|||||||
@ -68,13 +68,13 @@ export class FFmpegAddonAdapter implements IFFmpegAdapter {
|
|||||||
const addon = this.ensureAddon();
|
const addon = this.ensureAddon();
|
||||||
const info = await addon.getVideoInfo(videoPath);
|
const info = await addon.getVideoInfo(videoPath);
|
||||||
|
|
||||||
let format = info.format.includes(',') ? info.format.split(',')[0] ?? info.format : info.format;
|
const format = info.format.includes(',') ? info.format.split(',')[0] ?? info.format : info.format;
|
||||||
console.log('[FFmpegAddonAdapter] Detected format:', format);
|
console.log('[FFmpegAddonAdapter] Detected format:', format);
|
||||||
return {
|
return {
|
||||||
width: info.width,
|
width: info.width,
|
||||||
height: info.height,
|
height: info.height,
|
||||||
duration: info.duration,
|
duration: info.duration,
|
||||||
format: format,
|
format,
|
||||||
thumbnail: info.image,
|
thumbnail: info.image,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,7 +53,6 @@ export class FFmpegService {
|
|||||||
throw new Error('FFmpeg service not initialized. Please call FFmpegService.init() first.');
|
throw new Error('FFmpeg service not initialized. Please call FFmpegService.init() first.');
|
||||||
}
|
}
|
||||||
return this.adapter.name;
|
return this.adapter.name;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export enum NapCatCoreWorkingEnv {
|
|||||||
Framework = 2,
|
Framework = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
|
export function loadQQWrapper (QQVersion: string): WrapperNodeApi {
|
||||||
if (process.env['NAPCAT_WRAPPER_PATH']) {
|
if (process.env['NAPCAT_WRAPPER_PATH']) {
|
||||||
const wrapperPath = process.env['NAPCAT_WRAPPER_PATH'];
|
const wrapperPath = process.env['NAPCAT_WRAPPER_PATH'];
|
||||||
const nativemodule: { exports: WrapperNodeApi; } = { exports: {} as WrapperNodeApi };
|
const nativemodule: { exports: WrapperNodeApi; } = { exports: {} as WrapperNodeApi };
|
||||||
@ -72,7 +72,7 @@ export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
|
|||||||
process.dlopen(nativemodule, wrapperNodePath);
|
process.dlopen(nativemodule, wrapperNodePath);
|
||||||
return nativemodule.exports;
|
return nativemodule.exports;
|
||||||
}
|
}
|
||||||
export function getMajorPath(QQVersion: string): string {
|
export function getMajorPath (QQVersion: string): string {
|
||||||
// major.node
|
// major.node
|
||||||
let appPath;
|
let appPath;
|
||||||
if (os.platform() === 'darwin') {
|
if (os.platform() === 'darwin') {
|
||||||
@ -105,7 +105,7 @@ export class NapCatCore {
|
|||||||
configLoader: NapCatConfigLoader;
|
configLoader: NapCatConfigLoader;
|
||||||
|
|
||||||
// 通过构造器递过去的 runtime info 应该尽量少
|
// 通过构造器递过去的 runtime info 应该尽量少
|
||||||
constructor(context: InstanceContext, selfInfo: SelfInfo) {
|
constructor (context: InstanceContext, selfInfo: SelfInfo) {
|
||||||
this.selfInfo = selfInfo;
|
this.selfInfo = selfInfo;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.util = this.context.wrapper.NodeQQNTWrapperUtil;
|
this.util = this.context.wrapper.NodeQQNTWrapperUtil;
|
||||||
@ -134,7 +134,7 @@ export class NapCatCore {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async initCore() {
|
async initCore () {
|
||||||
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
||||||
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
||||||
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
||||||
@ -163,7 +163,7 @@ export class NapCatCore {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get dataPath(): string {
|
get dataPath (): string {
|
||||||
let result = this.context.wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
let result = this.context.wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = path.resolve(os.homedir(), './.config/QQ');
|
result = path.resolve(os.homedir(), './.config/QQ');
|
||||||
@ -173,7 +173,7 @@ export class NapCatCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Renamed from 'InitDataListener'
|
// Renamed from 'InitDataListener'
|
||||||
async initNapCatCoreListeners() {
|
async initNapCatCoreListeners () {
|
||||||
const msgListener = new NodeIKernelMsgListener();
|
const msgListener = new NodeIKernelMsgListener();
|
||||||
|
|
||||||
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
|
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
|
||||||
@ -211,7 +211,7 @@ export class NapCatCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function genSessionConfig(
|
export async function genSessionConfig (
|
||||||
guid: string,
|
guid: string,
|
||||||
QQVersionAppid: string,
|
QQVersionAppid: string,
|
||||||
QQVersion: string,
|
QQVersion: string,
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext';
|
import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext';
|
||||||
import { LogWrapper, LogLevel } from '@/napcat-core/helper/log';
|
import { LogWrapper, LogLevel } from '@/napcat-core/helper/log';
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,6 @@ export class NativePacketHandler {
|
|||||||
this.logger.logError('NativePacketClient 加载出错:', error);
|
this.logger.logError('NativePacketClient 加载出错:', error);
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { TypedEventEmitter } from "./typeEvent";
|
import { TypedEventEmitter } from './typeEvent';
|
||||||
|
|
||||||
export interface AppEvents {
|
export interface AppEvents {
|
||||||
'event:emoji_like': { groupId: string; senderUin: string; emojiId: string, msgSeq: string, isAdd: boolean,count:number };
|
'event:emoji_like': { groupId: string; senderUin: string; emojiId: string, msgSeq: string, isAdd: boolean, count: number };
|
||||||
}
|
}
|
||||||
export const appEvent = new TypedEventEmitter<AppEvents>();
|
export const appEvent = new TypedEventEmitter<AppEvents>();
|
||||||
|
|||||||
@ -1,28 +1,28 @@
|
|||||||
import "reflect-metadata";
|
import 'reflect-metadata';
|
||||||
import { Container, injectable } from "inversify";
|
import { Container, injectable } from 'inversify';
|
||||||
import { NapCatCore } from "../..";
|
import { NapCatCore } from '../..';
|
||||||
import { TypedEventEmitter } from "./typeEvent";
|
import { TypedEventEmitter } from './typeEvent';
|
||||||
|
|
||||||
export const container = new Container();
|
export const container = new Container();
|
||||||
|
|
||||||
export const ReceiverServiceRegistry = new Map<string, new (...args: any[]) => ServiceBase>();
|
export const ReceiverServiceRegistry = new Map<string, new (...args: any[]) => ServiceBase>();
|
||||||
|
|
||||||
export abstract class ServiceBase {
|
export abstract class ServiceBase {
|
||||||
get core(): NapCatCore {
|
get core (): NapCatCore {
|
||||||
return container.get(NapCatCore);
|
return container.get(NapCatCore);
|
||||||
}
|
}
|
||||||
get event() {
|
|
||||||
return container.get(TypedEventEmitter);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract handler(seq: number, hex_data: string): Promise<void> | void;
|
get event () {
|
||||||
|
return container.get(TypedEventEmitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract handler (seq: number, hex_data: string): Promise<void> | void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReceiveService(serviceName: string) {
|
export function ReceiveService (serviceName: string) {
|
||||||
return function <T extends new (...args: any[]) => ServiceBase>(constructor: T) {
|
return function <T extends new (...args: any[]) => ServiceBase>(constructor: T) {
|
||||||
injectable()(constructor);
|
injectable()(constructor);
|
||||||
ReceiverServiceRegistry.set(serviceName, constructor);
|
ReceiverServiceRegistry.set(serviceName, constructor);
|
||||||
return constructor;
|
return constructor;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,37 +1,36 @@
|
|||||||
import { NapProtoMsg } from "napcat-protobuf";
|
import { NapProtoMsg } from 'napcat-protobuf';
|
||||||
import { ReceiveService, ServiceBase } from "../packet/handler/serviceRegister";
|
import { ReceiveService, ServiceBase } from '../packet/handler/serviceRegister';
|
||||||
import { GroupReactNotify, PushMsg } from "../packet/transformer/proto";
|
import { GroupReactNotify, PushMsg } from '../packet/transformer/proto';
|
||||||
|
|
||||||
@ReceiveService('trpc.msg.olpush.OlPushService.MsgPush')
|
@ReceiveService('trpc.msg.olpush.OlPushService.MsgPush')
|
||||||
export class OlPushService extends ServiceBase {
|
export class OlPushService extends ServiceBase {
|
||||||
async handler(_seq: number, hex_data: string) {
|
async handler (_seq: number, hex_data: string) {
|
||||||
const data = new NapProtoMsg(PushMsg).decode(Buffer.from(hex_data, 'hex'));
|
const data = new NapProtoMsg(PushMsg).decode(Buffer.from(hex_data, 'hex'));
|
||||||
if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) {
|
if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) {
|
||||||
const pbNotify = data.message.body?.msgContent?.slice(7);
|
const pbNotify = data.message.body?.msgContent?.slice(7);
|
||||||
if (!pbNotify) {
|
if (!pbNotify) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 开始解析Notify
|
// 开始解析Notify
|
||||||
const notify = new NapProtoMsg(GroupReactNotify).decode(pbNotify);
|
const notify = new NapProtoMsg(GroupReactNotify).decode(pbNotify);
|
||||||
if ((notify.field13 ?? 0) === 35) {
|
if ((notify.field13 ?? 0) === 35) {
|
||||||
// Group React Notify
|
// Group React Notify
|
||||||
const groupCode = notify.groupUin?.toString() ?? '';
|
const groupCode = notify.groupUin?.toString() ?? '';
|
||||||
const operatorUid = notify.groupReactionData?.data?.data?.groupReactionDataContent?.operatorUid ?? '';
|
const operatorUid = notify.groupReactionData?.data?.data?.groupReactionDataContent?.operatorUid ?? '';
|
||||||
const type = notify.groupReactionData?.data?.data?.groupReactionDataContent?.type ?? 0;
|
const type = notify.groupReactionData?.data?.data?.groupReactionDataContent?.type ?? 0;
|
||||||
const seq = notify.groupReactionData?.data?.data?.groupReactionTarget?.seq?.toString() ?? '';
|
const seq = notify.groupReactionData?.data?.data?.groupReactionTarget?.seq?.toString() ?? '';
|
||||||
const code = notify.groupReactionData?.data?.data?.groupReactionDataContent?.code ?? '';
|
const code = notify.groupReactionData?.data?.data?.groupReactionDataContent?.code ?? '';
|
||||||
const count = notify.groupReactionData?.data?.data?.groupReactionDataContent?.count ?? 0;
|
const count = notify.groupReactionData?.data?.data?.groupReactionDataContent?.count ?? 0;
|
||||||
const senderUin = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
const senderUin = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
||||||
this.event.emit('event:emoji_like', {
|
this.event.emit('event:emoji_like', {
|
||||||
groupId: groupCode,
|
groupId: groupCode,
|
||||||
senderUin: senderUin,
|
senderUin,
|
||||||
emojiId: code,
|
emojiId: code,
|
||||||
msgSeq: seq,
|
msgSeq: seq,
|
||||||
isAdd: type === 1,
|
isAdd: type === 1,
|
||||||
count: count
|
count,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@ export interface NodeIKernelBuddyService {
|
|||||||
}>;
|
}>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
getBuddyListFromCache (reqType: BuddyListReqType): Promise<Array<
|
getBuddyListFromCache (reqType: BuddyListReqType): Promise<Array<
|
||||||
{
|
{
|
||||||
categoryId: number, // 9999为特别关心
|
categoryId: number, // 9999为特别关心
|
||||||
|
|||||||
@ -23,13 +23,13 @@ type ElementBase<
|
|||||||
K extends keyof ElementFullBase,
|
K extends keyof ElementFullBase,
|
||||||
S extends Partial<{ [P in K]: keyof NonNullable<ElementFullBase[P]> | Array<keyof NonNullable<ElementFullBase[P]>> }> = object
|
S extends Partial<{ [P in K]: keyof NonNullable<ElementFullBase[P]> | Array<keyof NonNullable<ElementFullBase[P]>> }> = object
|
||||||
> = {
|
> = {
|
||||||
[P in K]:
|
[P in K]:
|
||||||
S[P] extends Array<infer U>
|
S[P] extends Array<infer U>
|
||||||
? Pick<NonNullable<ElementFullBase[P]>, U & keyof NonNullable<ElementFullBase[P]>>
|
? Pick<NonNullable<ElementFullBase[P]>, U & keyof NonNullable<ElementFullBase[P]>>
|
||||||
: S[P] extends keyof NonNullable<ElementFullBase[P]>
|
: S[P] extends keyof NonNullable<ElementFullBase[P]>
|
||||||
? Pick<NonNullable<ElementFullBase[P]>, S[P]>
|
? Pick<NonNullable<ElementFullBase[P]>, S[P]>
|
||||||
: NonNullable<ElementFullBase[P]>;
|
: NonNullable<ElementFullBase[P]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface TextElement {
|
export interface TextElement {
|
||||||
content: string;
|
content: string;
|
||||||
|
|||||||
@ -10,5 +10,5 @@ const NAPCAT_MJS_PATH = path.join(BASE_DIR, 'napcat', 'napcat.mjs');
|
|||||||
process.env.NAPCAT_WRAPPER_PATH = WRAPPER_NODE_PATH;
|
process.env.NAPCAT_WRAPPER_PATH = WRAPPER_NODE_PATH;
|
||||||
process.env.NAPCAT_QQ_PACKAGE_INFO_PATH = PACKAGE_JSON_PATH;
|
process.env.NAPCAT_QQ_PACKAGE_INFO_PATH = PACKAGE_JSON_PATH;
|
||||||
process.env.NAPCAT_QQ_VERSION_CONFIG_PATH = CONFIG_JSON_PATH;
|
process.env.NAPCAT_QQ_VERSION_CONFIG_PATH = CONFIG_JSON_PATH;
|
||||||
process.env.NAPCAT_DISABLE_PIPE = '1';
|
process.env.NAPCAT_DISABLE_PIPE = '1';
|
||||||
import(pathToFileURL(NAPCAT_MJS_PATH).href);
|
import(pathToFileURL(NAPCAT_MJS_PATH).href);
|
||||||
|
|||||||
@ -33,7 +33,7 @@ const BASE_DIR = path.join(versionsDir, selectedFolder, 'resources', 'app');
|
|||||||
console.log(`BASE_DIR: ${BASE_DIR}`);
|
console.log(`BASE_DIR: ${BASE_DIR}`);
|
||||||
const TARGET_DIR = path.join(__dirname, 'dist');
|
const TARGET_DIR = path.join(__dirname, 'dist');
|
||||||
const QQNT_FILE = path.join(__dirname, 'QQNT.dll');
|
const QQNT_FILE = path.join(__dirname, 'QQNT.dll');
|
||||||
const NAPCAT_MJS_PATH = path.join(__dirname, '..', 'napcat-shell','dist', 'napcat.mjs');
|
const NAPCAT_MJS_PATH = path.join(__dirname, '..', 'napcat-shell', 'dist', 'napcat.mjs');
|
||||||
|
|
||||||
const itemsToCopy = [
|
const itemsToCopy = [
|
||||||
'avif_convert.dll',
|
'avif_convert.dll',
|
||||||
@ -45,15 +45,15 @@ const itemsToCopy = [
|
|||||||
'opencv.dll',
|
'opencv.dll',
|
||||||
'package.json',
|
'package.json',
|
||||||
'QBar.dll',
|
'QBar.dll',
|
||||||
'wrapper.node'
|
'wrapper.node',
|
||||||
];
|
];
|
||||||
|
|
||||||
async function copyAll () {
|
async function copyAll () {
|
||||||
const qqntDllPath = path.join(TARGET_DIR, 'QQNT.dll');
|
const qqntDllPath = path.join(TARGET_DIR, 'QQNT.dll');
|
||||||
const configPath = path.join(TARGET_DIR, 'config.json');
|
const configPath = path.join(TARGET_DIR, 'config.json');
|
||||||
const allItemsExist = await fs.pathExists(qqntDllPath)
|
const allItemsExist = await fs.pathExists(qqntDllPath) &&
|
||||||
&& await fs.pathExists(configPath)
|
await fs.pathExists(configPath) &&
|
||||||
&& (await Promise.all(itemsToCopy.map(item => fs.pathExists(path.join(TARGET_DIR, item))))).every(exists => exists);
|
(await Promise.all(itemsToCopy.map(item => fs.pathExists(path.join(TARGET_DIR, item))))).every(exists => exists);
|
||||||
|
|
||||||
if (!allItemsExist) {
|
if (!allItemsExist) {
|
||||||
console.log('Copying required files...');
|
console.log('Copying required files...');
|
||||||
@ -79,4 +79,4 @@ async function copyAll () {
|
|||||||
await import(pathToFileURL(NAPCAT_MJS_PATH).href);
|
await import(pathToFileURL(NAPCAT_MJS_PATH).href);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyAll().catch(console.error);
|
copyAll().catch(console.error);
|
||||||
|
|||||||
@ -2,23 +2,23 @@ import cp from 'vite-plugin-cp';
|
|||||||
import { defineConfig, PluginOption, UserConfig } from 'vite';
|
import { defineConfig, PluginOption, UserConfig } from 'vite';
|
||||||
import path, { resolve } from 'path';
|
import path, { resolve } from 'path';
|
||||||
import nodeResolve from '@rollup/plugin-node-resolve';
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
import { autoIncludeTSPlugin } from "napcat-vite/vite-auto-include.js";
|
import { autoIncludeTSPlugin } from 'napcat-vite/vite-auto-include.js';
|
||||||
import { builtinModules } from 'module';
|
import { builtinModules } from 'module';
|
||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react-swc';
|
||||||
import napcatVersion from "napcat-vite/vite-plugin-version.js";
|
import napcatVersion from 'napcat-vite/vite-plugin-version.js';
|
||||||
//依赖排除
|
// 依赖排除
|
||||||
const external = [
|
const external = [
|
||||||
'silk-wasm',
|
'silk-wasm',
|
||||||
'ws',
|
'ws',
|
||||||
'express'
|
'express',
|
||||||
];
|
];
|
||||||
const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat();
|
const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat();
|
||||||
const FrameworkBaseConfigPlugin: PluginOption[] = [
|
const FrameworkBaseConfigPlugin: PluginOption[] = [
|
||||||
autoIncludeTSPlugin({
|
autoIncludeTSPlugin({
|
||||||
entries: [
|
entries: [
|
||||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
||||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') },
|
||||||
]
|
],
|
||||||
}),
|
}),
|
||||||
react({ tsDecorators: true }),
|
react({ tsDecorators: true }),
|
||||||
cp({
|
cp({
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { OneBotAction } from './OneBotAction';
|
import { OneBotAction } from './OneBotAction';
|
||||||
export const AutoRegisterRouter: Array<new (...args: any[]) => OneBotAction<unknown, unknown>> = [];
|
export const AutoRegisterRouter: Array<new (...args: any[]) => OneBotAction<unknown, unknown>> = [];
|
||||||
|
|
||||||
export function ActionHandler(target: new (...args: any[]) => OneBotAction<unknown, unknown>) {
|
export function ActionHandler (target: new (...args: any[]) => OneBotAction<unknown, unknown>) {
|
||||||
AutoRegisterRouter.push(target);
|
AutoRegisterRouter.push(target);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -138,7 +138,7 @@ import { TestDownloadStream } from './stream/TestStreamDownload';
|
|||||||
import { UploadFileStream } from './stream/UploadFileStream';
|
import { UploadFileStream } from './stream/UploadFileStream';
|
||||||
import { AutoRegisterRouter } from './auto-register';
|
import { AutoRegisterRouter } from './auto-register';
|
||||||
|
|
||||||
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
export function createActionMap (obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
||||||
const actionHandlers = [
|
const actionHandlers = [
|
||||||
new CleanStreamTempFile(obContext, core),
|
new CleanStreamTempFile(obContext, core),
|
||||||
new DownloadFileStream(obContext, core),
|
new DownloadFileStream(obContext, core),
|
||||||
@ -315,7 +315,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
|||||||
// function get<K extends keyof MapType>(key: K): MapType[K];
|
// function get<K extends keyof MapType>(key: K): MapType[K];
|
||||||
// function get<K extends keyof MapType>(key: K): null;
|
// function get<K extends keyof MapType>(key: K): null;
|
||||||
// function get<K extends keyof MapType>(key: K): HandlerUnion | null | MapType[K]
|
// function get<K extends keyof MapType>(key: K): HandlerUnion | null | MapType[K]
|
||||||
function get<K extends keyof MapType>(key: K): MapType[K] | undefined {
|
function get<K extends keyof MapType> (key: K): MapType[K] | undefined {
|
||||||
return _map.get(key as keyof MapType) as MapType[K] | undefined;
|
return _map.get(key as keyof MapType) as MapType[K] | undefined;
|
||||||
}
|
}
|
||||||
return { get };
|
return { get };
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { NapCatOneBot11Adapter } from '@/napcat-onebot/index';
|
import { NapCatOneBot11Adapter } from '@/napcat-onebot/index';
|
||||||
import { encodeSilk } from '@/napcat-core/helper/audio';
|
import { encodeSilk } from '@/napcat-core/helper/audio';
|
||||||
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
|
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
|
||||||
@ -14,169 +12,169 @@ import fsPromises from 'fs/promises';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { defaultVideoThumbB64 } from '@/napcat-core/helper/ffmpeg/video';
|
import { defaultVideoThumbB64 } from '@/napcat-core/helper/ffmpeg/video';
|
||||||
export class OneBotFileApi {
|
export class OneBotFileApi {
|
||||||
obContext: NapCatOneBot11Adapter;
|
obContext: NapCatOneBot11Adapter;
|
||||||
core: NapCatCore;
|
core: NapCatCore;
|
||||||
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
constructor (obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
||||||
this.obContext = obContext;
|
this.obContext = obContext;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createValidSendFileElement (context: SendMessageContext, filePath: string, fileName: string = '', folderId: string = ''): Promise<SendFileElement> {
|
||||||
|
const {
|
||||||
|
fileName: _fileName,
|
||||||
|
path,
|
||||||
|
fileSize,
|
||||||
|
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.FILE);
|
||||||
|
if (fileSize === 0) {
|
||||||
|
throw new Error('文件异常,大小为0');
|
||||||
}
|
}
|
||||||
async createValidSendFileElement(context: SendMessageContext, filePath: string, fileName: string = '', folderId: string = ''): Promise<SendFileElement> {
|
context.deleteAfterSentFiles.push(path);
|
||||||
const {
|
return {
|
||||||
fileName: _fileName,
|
elementType: ElementType.FILE,
|
||||||
path,
|
elementId: '',
|
||||||
fileSize,
|
fileElement: {
|
||||||
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.FILE);
|
fileName: fileName || _fileName,
|
||||||
if (fileSize === 0) {
|
folderId,
|
||||||
throw new Error('文件异常,大小为0');
|
filePath: path,
|
||||||
}
|
fileSize: fileSize.toString(),
|
||||||
context.deleteAfterSentFiles.push(path);
|
},
|
||||||
return {
|
};
|
||||||
elementType: ElementType.FILE,
|
}
|
||||||
elementId: '',
|
|
||||||
fileElement: {
|
async createValidSendPicElement (context: SendMessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise<SendPicElement> {
|
||||||
fileName: fileName || _fileName,
|
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
|
||||||
folderId,
|
if (fileSize === 0) {
|
||||||
filePath: path,
|
throw new Error('文件异常,大小为0');
|
||||||
fileSize: fileSize.toString(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
const imageSize = await imageSizeFallBack(picPath);
|
||||||
|
context.deleteAfterSentFiles.push(path);
|
||||||
|
return {
|
||||||
|
elementType: ElementType.PIC,
|
||||||
|
elementId: '',
|
||||||
|
picElement: {
|
||||||
|
md5HexStr: md5,
|
||||||
|
fileSize: fileSize.toString(),
|
||||||
|
picWidth: imageSize.width,
|
||||||
|
picHeight: imageSize.height,
|
||||||
|
fileName,
|
||||||
|
sourcePath: path,
|
||||||
|
original: true,
|
||||||
|
picType: await getFileTypeForSendType(picPath),
|
||||||
|
picSubType: subType,
|
||||||
|
fileUuid: '',
|
||||||
|
fileSubId: '',
|
||||||
|
thumbFileSize: 0,
|
||||||
|
summary,
|
||||||
|
} as PicElement,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async createValidSendPicElement(context: SendMessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise<SendPicElement> {
|
async createValidSendVideoElement (context: SendMessageContext, filePath: string, fileName: string = '', _diyThumbPath: string = ''): Promise<SendVideoElement> {
|
||||||
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
|
let videoInfo = {
|
||||||
if (fileSize === 0) {
|
width: 1920,
|
||||||
throw new Error('文件异常,大小为0');
|
height: 1080,
|
||||||
}
|
time: 15,
|
||||||
const imageSize = await imageSizeFallBack(picPath);
|
format: 'mp4',
|
||||||
context.deleteAfterSentFiles.push(path);
|
size: 0,
|
||||||
return {
|
filePath,
|
||||||
elementType: ElementType.PIC,
|
};
|
||||||
elementId: '',
|
let fileExt = 'mp4';
|
||||||
picElement: {
|
try {
|
||||||
md5HexStr: md5,
|
const tempExt = (await fileTypeFromFile(filePath))?.ext;
|
||||||
fileSize: fileSize.toString(),
|
if (tempExt) fileExt = tempExt;
|
||||||
picWidth: imageSize.width,
|
} catch (e) {
|
||||||
picHeight: imageSize.height,
|
this.core.context.logger.logError('获取文件类型失败', e);
|
||||||
fileName,
|
|
||||||
sourcePath: path,
|
|
||||||
original: true,
|
|
||||||
picType: await getFileTypeForSendType(picPath),
|
|
||||||
picSubType: subType,
|
|
||||||
fileUuid: '',
|
|
||||||
fileSubId: '',
|
|
||||||
thumbFileSize: 0,
|
|
||||||
summary,
|
|
||||||
} as PicElement,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
const newFilePath = `${filePath}.${fileExt}`;
|
||||||
|
fs.copyFileSync(filePath, newFilePath);
|
||||||
|
context.deleteAfterSentFiles.push(newFilePath);
|
||||||
|
filePath = newFilePath;
|
||||||
|
|
||||||
async createValidSendVideoElement(context: SendMessageContext, filePath: string, fileName: string = '', _diyThumbPath: string = ''): Promise<SendVideoElement> {
|
const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
|
||||||
let videoInfo = {
|
context.deleteAfterSentFiles.push(path);
|
||||||
width: 1920,
|
if (fileSize === 0) {
|
||||||
height: 1080,
|
throw new Error('文件异常,大小为0');
|
||||||
time: 15,
|
|
||||||
format: 'mp4',
|
|
||||||
size: 0,
|
|
||||||
filePath,
|
|
||||||
};
|
|
||||||
let fileExt = 'mp4';
|
|
||||||
try {
|
|
||||||
const tempExt = (await fileTypeFromFile(filePath))?.ext;
|
|
||||||
if (tempExt) fileExt = tempExt;
|
|
||||||
} catch (e) {
|
|
||||||
this.core.context.logger.logError('获取文件类型失败', e);
|
|
||||||
}
|
|
||||||
const newFilePath = `${filePath}.${fileExt}`;
|
|
||||||
fs.copyFileSync(filePath, newFilePath);
|
|
||||||
context.deleteAfterSentFiles.push(newFilePath);
|
|
||||||
filePath = newFilePath;
|
|
||||||
|
|
||||||
const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
|
|
||||||
context.deleteAfterSentFiles.push(path);
|
|
||||||
if (fileSize === 0) {
|
|
||||||
throw new Error('文件异常,大小为0');
|
|
||||||
}
|
|
||||||
const thumbDir = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`);
|
|
||||||
fs.mkdirSync(pathLib.dirname(thumbDir), { recursive: true });
|
|
||||||
const thumbPath = pathLib.join(pathLib.dirname(thumbDir), `${md5}_0.png`);
|
|
||||||
try {
|
|
||||||
videoInfo = await FFmpegService.getVideoInfo(filePath, thumbPath);
|
|
||||||
if (!fs.existsSync(thumbPath)) {
|
|
||||||
this.core.context.logger.logError('获取视频缩略图失败', new Error('缩略图不存在'));
|
|
||||||
throw new Error('获取视频缩略图失败');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.core.context.logger.logError('获取视频信息失败', e);
|
|
||||||
fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
|
|
||||||
}
|
|
||||||
if (_diyThumbPath) {
|
|
||||||
try {
|
|
||||||
await this.core.apis.FileApi.copyFile(_diyThumbPath, thumbPath);
|
|
||||||
} catch (e) {
|
|
||||||
this.core.context.logger.logError('复制自定义缩略图失败', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.deleteAfterSentFiles.push(thumbPath);
|
|
||||||
const thumbSize = (await fsPromises.stat(thumbPath)).size;
|
|
||||||
const thumbMd5 = await calculateFileMD5(thumbPath);
|
|
||||||
context.deleteAfterSentFiles.push(thumbPath);
|
|
||||||
|
|
||||||
const uploadName = (fileName || _fileName).toLocaleLowerCase().endsWith(`.${fileExt.toLocaleLowerCase()}`) ? (fileName || _fileName) : `${fileName || _fileName}.${fileExt}`;
|
|
||||||
return {
|
|
||||||
elementType: ElementType.VIDEO,
|
|
||||||
elementId: '',
|
|
||||||
videoElement: {
|
|
||||||
fileName: uploadName,
|
|
||||||
filePath: path,
|
|
||||||
videoMd5: md5,
|
|
||||||
thumbMd5,
|
|
||||||
fileTime: videoInfo.time,
|
|
||||||
thumbPath: new Map([[0, thumbPath]]),
|
|
||||||
thumbSize,
|
|
||||||
thumbWidth: videoInfo.width,
|
|
||||||
thumbHeight: videoInfo.height,
|
|
||||||
fileSize: fileSize.toString(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
const thumbDir = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`);
|
||||||
async createValidSendPttElement(_context: SendMessageContext, pttPath: string): Promise<SendPttElement> {
|
fs.mkdirSync(pathLib.dirname(thumbDir), { recursive: true });
|
||||||
const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
|
const thumbPath = pathLib.join(pathLib.dirname(thumbDir), `${md5}_0.png`);
|
||||||
if (!silkPath) {
|
try {
|
||||||
throw new Error('语音转换失败, 请检查语音文件是否正常');
|
videoInfo = await FFmpegService.getVideoInfo(filePath, thumbPath);
|
||||||
}
|
if (!fs.existsSync(thumbPath)) {
|
||||||
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(silkPath, ElementType.PTT);
|
this.core.context.logger.logError('获取视频缩略图失败', new Error('缩略图不存在'));
|
||||||
if (fileSize === 0) {
|
throw new Error('获取视频缩略图失败');
|
||||||
throw new Error('文件异常,大小为0');
|
}
|
||||||
}
|
} catch (e) {
|
||||||
if (converted) {
|
this.core.context.logger.logError('获取视频信息失败', e);
|
||||||
fsPromises.unlink(silkPath).then().catch((e) => this.core.context.logger.logError('删除临时文件失败', e));
|
fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
|
||||||
}
|
|
||||||
return {
|
|
||||||
elementType: ElementType.PTT,
|
|
||||||
elementId: '',
|
|
||||||
pttElement: {
|
|
||||||
fileName,
|
|
||||||
filePath: path,
|
|
||||||
md5HexStr: md5,
|
|
||||||
fileSize: fileSize.toString(),
|
|
||||||
duration: duration ?? 1,
|
|
||||||
formatType: 1,
|
|
||||||
voiceType: 1,
|
|
||||||
voiceChangeType: 0,
|
|
||||||
canConvert2Text: true,
|
|
||||||
waveAmplitudes: [
|
|
||||||
0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17,
|
|
||||||
],
|
|
||||||
fileSubId: '',
|
|
||||||
playState: 1,
|
|
||||||
autoConvertText: 0,
|
|
||||||
storeID: 0,
|
|
||||||
otherBusinessInfo: {
|
|
||||||
aiVoiceType: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (_diyThumbPath) {
|
||||||
|
try {
|
||||||
|
await this.core.apis.FileApi.copyFile(_diyThumbPath, thumbPath);
|
||||||
|
} catch (e) {
|
||||||
|
this.core.context.logger.logError('复制自定义缩略图失败', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.deleteAfterSentFiles.push(thumbPath);
|
||||||
|
const thumbSize = (await fsPromises.stat(thumbPath)).size;
|
||||||
|
const thumbMd5 = await calculateFileMD5(thumbPath);
|
||||||
|
context.deleteAfterSentFiles.push(thumbPath);
|
||||||
|
|
||||||
|
const uploadName = (fileName || _fileName).toLocaleLowerCase().endsWith(`.${fileExt.toLocaleLowerCase()}`) ? (fileName || _fileName) : `${fileName || _fileName}.${fileExt}`;
|
||||||
|
return {
|
||||||
|
elementType: ElementType.VIDEO,
|
||||||
|
elementId: '',
|
||||||
|
videoElement: {
|
||||||
|
fileName: uploadName,
|
||||||
|
filePath: path,
|
||||||
|
videoMd5: md5,
|
||||||
|
thumbMd5,
|
||||||
|
fileTime: videoInfo.time,
|
||||||
|
thumbPath: new Map([[0, thumbPath]]),
|
||||||
|
thumbSize,
|
||||||
|
thumbWidth: videoInfo.width,
|
||||||
|
thumbHeight: videoInfo.height,
|
||||||
|
fileSize: fileSize.toString(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async createValidSendPttElement (_context: SendMessageContext, pttPath: string): Promise<SendPttElement> {
|
||||||
|
const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
|
||||||
|
if (!silkPath) {
|
||||||
|
throw new Error('语音转换失败, 请检查语音文件是否正常');
|
||||||
|
}
|
||||||
|
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(silkPath, ElementType.PTT);
|
||||||
|
if (fileSize === 0) {
|
||||||
|
throw new Error('文件异常,大小为0');
|
||||||
|
}
|
||||||
|
if (converted) {
|
||||||
|
fsPromises.unlink(silkPath).then().catch((e) => this.core.context.logger.logError('删除临时文件失败', e));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
elementType: ElementType.PTT,
|
||||||
|
elementId: '',
|
||||||
|
pttElement: {
|
||||||
|
fileName,
|
||||||
|
filePath: path,
|
||||||
|
md5HexStr: md5,
|
||||||
|
fileSize: fileSize.toString(),
|
||||||
|
duration: duration ?? 1,
|
||||||
|
formatType: 1,
|
||||||
|
voiceType: 1,
|
||||||
|
voiceChangeType: 0,
|
||||||
|
canConvert2Text: true,
|
||||||
|
waveAmplitudes: [
|
||||||
|
0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17,
|
||||||
|
],
|
||||||
|
fileSubId: '',
|
||||||
|
playState: 1,
|
||||||
|
autoConvertText: 0,
|
||||||
|
storeID: 0,
|
||||||
|
otherBusinessInfo: {
|
||||||
|
aiVoiceType: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,12 +30,12 @@ import { NapCatOneBot11Adapter } from '..';
|
|||||||
export class OneBotGroupApi {
|
export class OneBotGroupApi {
|
||||||
obContext: NapCatOneBot11Adapter;
|
obContext: NapCatOneBot11Adapter;
|
||||||
core: NapCatCore;
|
core: NapCatCore;
|
||||||
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
constructor (obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
||||||
this.obContext = obContext;
|
this.obContext = obContext;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseGroupBanEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
async parseGroupBanEvent (GroupCode: string, grayTipElement: GrayTipElement) {
|
||||||
const groupElement = grayTipElement?.groupElement;
|
const groupElement = grayTipElement?.groupElement;
|
||||||
if (!groupElement?.shutUp) return undefined;
|
if (!groupElement?.shutUp) return undefined;
|
||||||
const memberUid = groupElement.shutUp.member.uid;
|
const memberUid = groupElement.shutUp.member.uid;
|
||||||
@ -66,7 +66,7 @@ export class OneBotGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseGroupEmojiLikeEventByGrayTip(
|
async parseGroupEmojiLikeEventByGrayTip (
|
||||||
groupCode: string,
|
groupCode: string,
|
||||||
grayTipElement: GrayTipElement
|
grayTipElement: GrayTipElement
|
||||||
) {
|
) {
|
||||||
@ -85,7 +85,7 @@ export class OneBotGroupApi {
|
|||||||
return await this.createGroupEmojiLikeEvent(groupCode, senderUin, msgSeq, emojiId, true, 1);
|
return await this.createGroupEmojiLikeEvent(groupCode, senderUin, msgSeq, emojiId, true, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createGroupEmojiLikeEvent(
|
async createGroupEmojiLikeEvent (
|
||||||
groupCode: string,
|
groupCode: string,
|
||||||
senderUin: string,
|
senderUin: string,
|
||||||
msgSeq: string,
|
msgSeq: string,
|
||||||
@ -121,7 +121,7 @@ export class OneBotGroupApi {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseCardChangedEvent(msg: RawMessage) {
|
async parseCardChangedEvent (msg: RawMessage) {
|
||||||
if (msg.senderUin && msg.senderUin !== '0') {
|
if (msg.senderUin && msg.senderUin !== '0') {
|
||||||
const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin);
|
const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin);
|
||||||
if (member && member.cardName !== msg.sendMemberName) {
|
if (member && member.cardName !== msg.sendMemberName) {
|
||||||
@ -137,7 +137,7 @@ export class OneBotGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerParseGroupReactEvent() {
|
async registerParseGroupReactEvent () {
|
||||||
this.obContext.core.context.packetHandler.onCmd('trpc.msg.olpush.OlPushService.MsgPush', async (packet) => {
|
this.obContext.core.context.packetHandler.onCmd('trpc.msg.olpush.OlPushService.MsgPush', async (packet) => {
|
||||||
const data = new NapProtoMsg(PushMsg).decode(Buffer.from(packet.hex_data, 'hex'));
|
const data = new NapProtoMsg(PushMsg).decode(Buffer.from(packet.hex_data, 'hex'));
|
||||||
if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) {
|
if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) {
|
||||||
@ -172,7 +172,7 @@ export class OneBotGroupApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerParseGroupReactEventByCore() {
|
async registerParseGroupReactEventByCore () {
|
||||||
this.core.event.on('event:emoji_like', async (data) => {
|
this.core.event.on('event:emoji_like', async (data) => {
|
||||||
console.log('Received emoji_like event from core:', data);
|
console.log('Received emoji_like event from core:', data);
|
||||||
const event = await this.createGroupEmojiLikeEvent(
|
const event = await this.createGroupEmojiLikeEvent(
|
||||||
@ -188,7 +188,8 @@ export class OneBotGroupApi {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async parsePaiYiPai(msg: RawMessage, jsonStr: string) {
|
|
||||||
|
async parsePaiYiPai (msg: RawMessage, jsonStr: string) {
|
||||||
const json = JSON.parse(jsonStr);
|
const json = JSON.parse(jsonStr);
|
||||||
// 判断业务类型
|
// 判断业务类型
|
||||||
// Poke事件
|
// Poke事件
|
||||||
@ -207,7 +208,7 @@ export class OneBotGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseOtherJsonEvent(msg: RawMessage, jsonStr: string, context: InstanceContext) {
|
async parseOtherJsonEvent (msg: RawMessage, jsonStr: string, context: InstanceContext) {
|
||||||
const json = JSON.parse(jsonStr);
|
const json = JSON.parse(jsonStr);
|
||||||
const type = json.items[json.items.length - 1]?.txt;
|
const type = json.items[json.items.length - 1]?.txt;
|
||||||
await this.core.apis.GroupApi.refreshGroupMemberCachePartial(msg.peerUid, msg.senderUid);
|
await this.core.apis.GroupApi.refreshGroupMemberCachePartial(msg.peerUid, msg.senderUid);
|
||||||
@ -229,7 +230,7 @@ export class OneBotGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseEssenceMsg(msg: RawMessage, jsonStr: string) {
|
async parseEssenceMsg (msg: RawMessage, jsonStr: string) {
|
||||||
const json = JSON.parse(jsonStr);
|
const json = JSON.parse(jsonStr);
|
||||||
const searchParams = new URL(json.items[0].jp).searchParams;
|
const searchParams = new URL(json.items[0].jp).searchParams;
|
||||||
const msgSeq = searchParams.get('msgSeq')!;
|
const msgSeq = searchParams.get('msgSeq')!;
|
||||||
@ -257,7 +258,7 @@ export class OneBotGroupApi {
|
|||||||
// 获取MsgSeq+Peer可获取具体消息
|
// 获取MsgSeq+Peer可获取具体消息
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseGroupUploadFileEvene(msg: RawMessage, element: FileElement, elementWrapper: MessageElement) {
|
async parseGroupUploadFileEvene (msg: RawMessage, element: FileElement, elementWrapper: MessageElement) {
|
||||||
return new OB11GroupUploadNoticeEvent(
|
return new OB11GroupUploadNoticeEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(msg.peerUid), parseInt(msg.senderUin || ''),
|
parseInt(msg.peerUid), parseInt(msg.senderUin || ''),
|
||||||
@ -273,7 +274,7 @@ export class OneBotGroupApi {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseGroupElement(msg: RawMessage, element: TipGroupElement, elementWrapper: GrayTipElement) {
|
async parseGroupElement (msg: RawMessage, element: TipGroupElement, elementWrapper: GrayTipElement) {
|
||||||
if (element.type === TipGroupElementType.KGROUPNAMEMODIFIED) {
|
if (element.type === TipGroupElementType.KGROUPNAMEMODIFIED) {
|
||||||
this.core.context.logger.logDebug('收到群名称变更事件', element);
|
this.core.context.logger.logDebug('收到群名称变更事件', element);
|
||||||
return new OB11GroupNameEvent(
|
return new OB11GroupNameEvent(
|
||||||
@ -301,7 +302,7 @@ export class OneBotGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseSelfInviteEvent(msg: RawMessage, inviterUin: string, inviteeUin: string) {
|
async parseSelfInviteEvent (msg: RawMessage, inviterUin: string, inviteeUin: string) {
|
||||||
return new OB11GroupIncreaseEvent(
|
return new OB11GroupIncreaseEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(msg.peerUid),
|
parseInt(msg.peerUid),
|
||||||
@ -311,7 +312,7 @@ export class OneBotGroupApi {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parse51TypeEvent(msg: RawMessage, grayTipElement: GrayTipElement) {
|
async parse51TypeEvent (msg: RawMessage, grayTipElement: GrayTipElement) {
|
||||||
// 神经腾讯 没了妈妈想出来的
|
// 神经腾讯 没了妈妈想出来的
|
||||||
// Warn 下面存在高并发危险
|
// Warn 下面存在高并发危险
|
||||||
if (grayTipElement.jsonGrayTipElement.jsonStr) {
|
if (grayTipElement.jsonGrayTipElement.jsonStr) {
|
||||||
@ -340,7 +341,7 @@ export class OneBotGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseGrayTipElement(msg: RawMessage, grayTipElement: GrayTipElement) {
|
async parseGrayTipElement (msg: RawMessage, grayTipElement: GrayTipElement) {
|
||||||
if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_GROUP) {
|
if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_GROUP) {
|
||||||
// 解析群组事件 由sysmsg解析
|
// 解析群组事件 由sysmsg解析
|
||||||
return await this.parseGroupElement(msg, grayTipElement.groupElement, grayTipElement);
|
return await this.parseGroupElement(msg, grayTipElement.groupElement, grayTipElement);
|
||||||
|
|||||||
@ -75,7 +75,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
actions: ActionMap;
|
actions: ActionMap;
|
||||||
private readonly bootTime = Date.now() / 1000;
|
private readonly bootTime = Date.now() / 1000;
|
||||||
recallEventCache = new Map<string, NodeJS.Timeout>();
|
recallEventCache = new Map<string, NodeJS.Timeout>();
|
||||||
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
constructor (core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath, OneBotConfigSchema);
|
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath, OneBotConfigSchema);
|
||||||
@ -91,7 +91,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.networkManager = new OB11NetworkManager();
|
this.networkManager = new OB11NetworkManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
async creatOneBotLog(ob11Config: OneBotConfig) {
|
async creatOneBotLog (ob11Config: OneBotConfig) {
|
||||||
let log = '[network] 配置加载\n';
|
let log = '[network] 配置加载\n';
|
||||||
for (const key of ob11Config.network.httpServers) {
|
for (const key of ob11Config.network.httpServers) {
|
||||||
log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`;
|
log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`;
|
||||||
@ -111,7 +111,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
async InitOneBot() {
|
async InitOneBot () {
|
||||||
const selfInfo = this.core.selfInfo;
|
const selfInfo = this.core.selfInfo;
|
||||||
const ob11Config = this.configLoader.configData;
|
const ob11Config = this.configLoader.configData;
|
||||||
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid, false)
|
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid, false)
|
||||||
@ -233,7 +233,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig): Promise<void> {
|
private async reloadNetwork (prev: OneBotConfig, now: OneBotConfig): Promise<void> {
|
||||||
const prevLog = await this.creatOneBotLog(prev);
|
const prevLog = await this.creatOneBotLog(prev);
|
||||||
const newLog = await this.creatOneBotLog(now);
|
const newLog = await this.creatOneBotLog(now);
|
||||||
this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`);
|
this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`);
|
||||||
@ -279,7 +279,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initMsgListener() {
|
private initMsgListener () {
|
||||||
const msgListener = new NodeIKernelMsgListener();
|
const msgListener = new NodeIKernelMsgListener();
|
||||||
msgListener.onRecvSysMsg = (msg) => {
|
msgListener.onRecvSysMsg = (msg) => {
|
||||||
this.apis.MsgApi.parseSysMessage(msg)
|
this.apis.MsgApi.parseSysMessage(msg)
|
||||||
@ -392,7 +392,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger));
|
this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBuddyListener() {
|
private initBuddyListener () {
|
||||||
const buddyListener = new NodeIKernelBuddyListener();
|
const buddyListener = new NodeIKernelBuddyListener();
|
||||||
|
|
||||||
buddyListener.onBuddyReqChange = async (reqs) => {
|
buddyListener.onBuddyReqChange = async (reqs) => {
|
||||||
@ -423,7 +423,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
.addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger));
|
.addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private initGroupListener() {
|
private initGroupListener () {
|
||||||
const groupListener = new NodeIKernelGroupListener();
|
const groupListener = new NodeIKernelGroupListener();
|
||||||
|
|
||||||
groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
|
groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
|
||||||
@ -516,7 +516,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
.addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger));
|
.addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitMsg(message: RawMessage) {
|
private async emitMsg (message: RawMessage) {
|
||||||
const network = await this.networkManager.getAllConfig();
|
const network = await this.networkManager.getAllConfig();
|
||||||
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
||||||
await Promise.allSettled([
|
await Promise.allSettled([
|
||||||
@ -525,7 +525,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleMsg(message: RawMessage, network: Array<NetworkAdapterConfig>) {
|
private async handleMsg (message: RawMessage, network: Array<NetworkAdapterConfig>) {
|
||||||
// 过滤无效消息
|
// 过滤无效消息
|
||||||
if (message.msgType === NTMsgType.KMSGTYPENULL) {
|
if (message.msgType === NTMsgType.KMSGTYPENULL) {
|
||||||
return;
|
return;
|
||||||
@ -545,7 +545,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSelfMessage(ob11Msg: {
|
private isSelfMessage (ob11Msg: {
|
||||||
stringMsg: OB11Message;
|
stringMsg: OB11Message;
|
||||||
arrayMsg: OB11Message;
|
arrayMsg: OB11Message;
|
||||||
}): boolean {
|
}): boolean {
|
||||||
@ -553,7 +553,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
ob11Msg.arrayMsg.user_id.toString() === this.core.selfInfo.uin;
|
ob11Msg.arrayMsg.user_id.toString() === this.core.selfInfo.uin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createMsgMap(network: Array<NetworkAdapterConfig>, ob11Msg: {
|
private createMsgMap (network: Array<NetworkAdapterConfig>, ob11Msg: {
|
||||||
stringMsg: OB11Message;
|
stringMsg: OB11Message;
|
||||||
arrayMsg: OB11Message;
|
arrayMsg: OB11Message;
|
||||||
}, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
|
}, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
|
||||||
@ -572,7 +572,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
return msgMap;
|
return msgMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleDebugNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, message: RawMessage) {
|
private handleDebugNetwork (network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, message: RawMessage) {
|
||||||
const debugNetwork = network.filter(e => e.enable && e.debug);
|
const debugNetwork = network.filter(e => e.enable && e.debug);
|
||||||
if (debugNetwork.length > 0) {
|
if (debugNetwork.length > 0) {
|
||||||
debugNetwork.forEach(adapter => {
|
debugNetwork.forEach(adapter => {
|
||||||
@ -586,7 +586,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleNotReportSelfNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
|
private handleNotReportSelfNetwork (network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
|
||||||
if (isSelfMsg) {
|
if (isSelfMsg) {
|
||||||
const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e)));
|
const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e)));
|
||||||
notReportSelfNetwork.forEach(adapter => {
|
notReportSelfNetwork.forEach(adapter => {
|
||||||
@ -595,7 +595,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleGroupEvent(message: RawMessage) {
|
private async handleGroupEvent (message: RawMessage) {
|
||||||
try {
|
try {
|
||||||
// 群名片修改事件解析 任何都该判断
|
// 群名片修改事件解析 任何都该判断
|
||||||
if (message.senderUin && message.senderUin !== '0') {
|
if (message.senderUin && message.senderUin !== '0') {
|
||||||
@ -628,7 +628,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handlePrivateMsgEvent(message: RawMessage) {
|
private async handlePrivateMsgEvent (message: RawMessage) {
|
||||||
try {
|
try {
|
||||||
if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) {
|
if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) {
|
||||||
// 灰条为单元素消息
|
// 灰条为单元素消息
|
||||||
@ -645,7 +645,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitRecallMsg(message: RawMessage, element: MessageElement) {
|
private async emitRecallMsg (message: RawMessage, element: MessageElement) {
|
||||||
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
||||||
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
|
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
|
||||||
if (message.chatType === ChatType.KCHATTYPEC2C) {
|
if (message.chatType === ChatType.KCHATTYPEC2C) {
|
||||||
@ -656,7 +656,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitFriendRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
private async emitFriendRecallMsg (message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
if (!operatorUid) return undefined;
|
if (!operatorUid) return undefined;
|
||||||
return new OB11FriendRecallNoticeEvent(
|
return new OB11FriendRecallNoticeEvent(
|
||||||
@ -666,7 +666,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
private async emitGroupRecallMsg (message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
if (!operatorUid) return undefined;
|
if (!operatorUid) return undefined;
|
||||||
const operatorId = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
const operatorId = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
||||||
|
|||||||
@ -7,18 +7,18 @@ type LowerCamelCase<S extends string> = CamelCaseHelper<S, false, true>;
|
|||||||
type CamelCaseHelper<
|
type CamelCaseHelper<
|
||||||
S extends string,
|
S extends string,
|
||||||
CapNext extends boolean,
|
CapNext extends boolean,
|
||||||
IsFirstChar extends boolean,
|
IsFirstChar extends boolean
|
||||||
> = S extends `${infer F}${infer R}`
|
> = S extends `${infer F}${infer R}`
|
||||||
? F extends '_'
|
? F extends '_'
|
||||||
? CamelCaseHelper<R, true, false>
|
? CamelCaseHelper<R, true, false>
|
||||||
: F extends `${number}`
|
: F extends `${number}`
|
||||||
? `${F}${CamelCaseHelper<R, true, false>}`
|
? `${F}${CamelCaseHelper<R, true, false>}`
|
||||||
: CapNext extends true
|
: CapNext extends true
|
||||||
? `${Uppercase<F>}${CamelCaseHelper<R, false, false>}`
|
? `${Uppercase<F>}${CamelCaseHelper<R, false, false>}`
|
||||||
: IsFirstChar extends true
|
: IsFirstChar extends true
|
||||||
? `${Lowercase<F>}${CamelCaseHelper<R, false, false>}`
|
? `${Lowercase<F>}${CamelCaseHelper<R, false, false>}`
|
||||||
: `${F}${CamelCaseHelper<R, false, false>}`
|
: `${F}${CamelCaseHelper<R, false, false>}`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
type ScalarTypeToTsType<T extends ScalarType> = T extends
|
type ScalarTypeToTsType<T extends ScalarType> = T extends
|
||||||
| ScalarType.DOUBLE
|
| ScalarType.DOUBLE
|
||||||
@ -28,36 +28,36 @@ type ScalarTypeToTsType<T extends ScalarType> = T extends
|
|||||||
| ScalarType.UINT32
|
| ScalarType.UINT32
|
||||||
| ScalarType.SFIXED32
|
| ScalarType.SFIXED32
|
||||||
| ScalarType.SINT32
|
| ScalarType.SINT32
|
||||||
? number
|
? number
|
||||||
: T extends ScalarType.INT64 | ScalarType.UINT64 | ScalarType.FIXED64 | ScalarType.SFIXED64 | ScalarType.SINT64
|
: T extends ScalarType.INT64 | ScalarType.UINT64 | ScalarType.FIXED64 | ScalarType.SFIXED64 | ScalarType.SINT64
|
||||||
? bigint
|
? bigint
|
||||||
: T extends ScalarType.BOOL
|
: T extends ScalarType.BOOL
|
||||||
? boolean
|
? boolean
|
||||||
: T extends ScalarType.STRING
|
: T extends ScalarType.STRING
|
||||||
? string
|
? string
|
||||||
: T extends ScalarType.BYTES
|
: T extends ScalarType.BYTES
|
||||||
? Uint8Array
|
? Uint8Array
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
interface BaseProtoFieldType<T, O extends boolean, R extends O extends true ? false : boolean> {
|
interface BaseProtoFieldType<T, O extends boolean, R extends O extends true ? false : boolean> {
|
||||||
kind: 'scalar' | 'message';
|
kind: 'scalar' | 'message';
|
||||||
no: number;
|
no: number;
|
||||||
type: T;
|
type: T;
|
||||||
optional: O;
|
optional: O;
|
||||||
repeat: R;
|
repeat: R;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScalarProtoFieldType<T extends ScalarType, O extends boolean, R extends O extends true ? false : boolean>
|
export interface ScalarProtoFieldType<T extends ScalarType, O extends boolean, R extends O extends true ? false : boolean>
|
||||||
extends BaseProtoFieldType<T, O, R> {
|
extends BaseProtoFieldType<T, O, R> {
|
||||||
kind: 'scalar';
|
kind: 'scalar';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageProtoFieldType<
|
export interface MessageProtoFieldType<
|
||||||
T extends () => ProtoMessageType,
|
T extends () => ProtoMessageType,
|
||||||
O extends boolean,
|
O extends boolean,
|
||||||
R extends O extends true ? false : boolean,
|
R extends O extends true ? false : boolean
|
||||||
> extends BaseProtoFieldType<T, O, R> {
|
> extends BaseProtoFieldType<T, O, R> {
|
||||||
kind: 'message';
|
kind: 'message';
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoFieldType =
|
type ProtoFieldType =
|
||||||
@ -65,62 +65,62 @@ type ProtoFieldType =
|
|||||||
| MessageProtoFieldType<() => ProtoMessageType, boolean, boolean>;
|
| MessageProtoFieldType<() => ProtoMessageType, boolean, boolean>;
|
||||||
|
|
||||||
type ProtoMessageType = {
|
type ProtoMessageType = {
|
||||||
[key: string]: ProtoFieldType;
|
[key: string]: ProtoFieldType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ProtoField<
|
export function ProtoField<
|
||||||
T extends ScalarType,
|
T extends ScalarType,
|
||||||
O extends boolean = false,
|
O extends boolean = false,
|
||||||
R extends O extends true ? false : boolean = false,
|
R extends O extends true ? false : boolean = false
|
||||||
>(no: number, type: T, optional?: O, repeat?: R): ScalarProtoFieldType<T, O, R>;
|
> (no: number, type: T, optional?: O, repeat?: R): ScalarProtoFieldType<T, O, R>;
|
||||||
export function ProtoField<
|
export function ProtoField<
|
||||||
T extends () => ProtoMessageType,
|
T extends () => ProtoMessageType,
|
||||||
O extends boolean = false,
|
O extends boolean = false,
|
||||||
R extends O extends true ? false : boolean = false,
|
R extends O extends true ? false : boolean = false
|
||||||
>(no: number, type: T, optional?: O, repeat?: R): MessageProtoFieldType<T, O, R>;
|
> (no: number, type: T, optional?: O, repeat?: R): MessageProtoFieldType<T, O, R>;
|
||||||
export function ProtoField(
|
export function ProtoField (
|
||||||
no: number,
|
no: number,
|
||||||
type: ScalarType | (() => ProtoMessageType),
|
type: ScalarType | (() => ProtoMessageType),
|
||||||
optional?: boolean,
|
optional?: boolean,
|
||||||
repeat?: boolean
|
repeat?: boolean
|
||||||
): ProtoFieldType {
|
): ProtoFieldType {
|
||||||
if (typeof type === 'function') {
|
if (typeof type === 'function') {
|
||||||
return { kind: 'message', no: no, type: type, optional: optional ?? false, repeat: repeat ?? false };
|
return { kind: 'message', no, type, optional: optional ?? false, repeat: repeat ?? false };
|
||||||
} else {
|
} else {
|
||||||
return { kind: 'scalar', no: no, type: type, optional: optional ?? false, repeat: repeat ?? false };
|
return { kind: 'scalar', no, type, optional: optional ?? false, repeat: repeat ?? false };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoFieldReturnType<T, E extends boolean> =
|
type ProtoFieldReturnType<T, E extends boolean> =
|
||||||
NonNullable<T> extends ScalarProtoFieldType<infer S, infer O, infer R>
|
NonNullable<T> extends ScalarProtoFieldType<infer S, infer _O, infer _R>
|
||||||
? ScalarTypeToTsType<S>
|
? ScalarTypeToTsType<S>
|
||||||
: T extends NonNullable<MessageProtoFieldType<infer S, infer O, infer R>>
|
: T extends NonNullable<MessageProtoFieldType<infer S, infer _O, infer _R>>
|
||||||
? NonNullable<NapProtoStructType<ReturnType<S>, E>>
|
? NonNullable<NapProtoStructType<ReturnType<S>, E>>
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
type RequiredFieldsBaseType<T, E extends boolean> = {
|
type RequiredFieldsBaseType<T, E extends boolean> = {
|
||||||
[K in keyof T as T[K] extends { optional: true } ? never : LowerCamelCase<K & string>]: T[K] extends {
|
[K in keyof T as T[K] extends { optional: true } ? never : LowerCamelCase<K & string>]: T[K] extends {
|
||||||
repeat: true;
|
repeat: true;
|
||||||
}
|
}
|
||||||
? ProtoFieldReturnType<T[K], E>[]
|
? ProtoFieldReturnType<T[K], E>[]
|
||||||
: ProtoFieldReturnType<T[K], E>;
|
: ProtoFieldReturnType<T[K], E>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OptionalFieldsBaseType<T, E extends boolean> = {
|
type OptionalFieldsBaseType<T, E extends boolean> = {
|
||||||
[K in keyof T as T[K] extends { optional: true } ? LowerCamelCase<K & string> : never]?: T[K] extends {
|
[K in keyof T as T[K] extends { optional: true } ? LowerCamelCase<K & string> : never]?: T[K] extends {
|
||||||
repeat: true;
|
repeat: true;
|
||||||
}
|
}
|
||||||
? ProtoFieldReturnType<T[K], E>[]
|
? ProtoFieldReturnType<T[K], E>[]
|
||||||
: ProtoFieldReturnType<T[K], E>;
|
: ProtoFieldReturnType<T[K], E>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RequiredFieldsType<T, E extends boolean> = E extends true
|
type RequiredFieldsType<T, E extends boolean> = E extends true
|
||||||
? Partial<RequiredFieldsBaseType<T, E>>
|
? Partial<RequiredFieldsBaseType<T, E>>
|
||||||
: RequiredFieldsBaseType<T, E>;
|
: RequiredFieldsBaseType<T, E>;
|
||||||
|
|
||||||
type OptionalFieldsType<T, E extends boolean> = E extends true
|
type OptionalFieldsType<T, E extends boolean> = E extends true
|
||||||
? Partial<OptionalFieldsBaseType<T, E>>
|
? Partial<OptionalFieldsBaseType<T, E>>
|
||||||
: OptionalFieldsBaseType<T, E>;
|
: OptionalFieldsBaseType<T, E>;
|
||||||
|
|
||||||
type NapProtoStructType<T, E extends boolean> = RequiredFieldsType<T, E> & OptionalFieldsType<T, E>;
|
type NapProtoStructType<T, E extends boolean> = RequiredFieldsType<T, E> & OptionalFieldsType<T, E>;
|
||||||
|
|
||||||
@ -129,72 +129,74 @@ export type NapProtoEncodeStructType<T> = NapProtoStructType<T, true>;
|
|||||||
export type NapProtoDecodeStructType<T> = NapProtoStructType<T, false>;
|
export type NapProtoDecodeStructType<T> = NapProtoStructType<T, false>;
|
||||||
|
|
||||||
class NapProtoRealMsg<T extends ProtoMessageType> {
|
class NapProtoRealMsg<T extends ProtoMessageType> {
|
||||||
private readonly _field: PartialFieldInfo[];
|
private readonly _field: PartialFieldInfo[];
|
||||||
private readonly _proto_msg: MessageType<NapProtoStructType<T, boolean>>;
|
private readonly _proto_msg: MessageType<NapProtoStructType<T, boolean>>;
|
||||||
private static cache = new WeakMap<ProtoMessageType, NapProtoRealMsg<any>>();
|
private static cache = new WeakMap<ProtoMessageType, NapProtoRealMsg<any>>();
|
||||||
|
|
||||||
private constructor(fields: T) {
|
private constructor (fields: T) {
|
||||||
this._field = Object.keys(fields).map((key) => {
|
this._field = Object.keys(fields).map((key) => {
|
||||||
const field = fields[key];
|
const field = fields[key];
|
||||||
if (field.kind === 'scalar') {
|
if (field.kind === 'scalar') {
|
||||||
const repeatType = field.repeat
|
const repeatType = field.repeat
|
||||||
? [ScalarType.STRING, ScalarType.BYTES].includes(field.type)
|
? [ScalarType.STRING, ScalarType.BYTES].includes(field.type)
|
||||||
? RepeatType.UNPACKED
|
? RepeatType.UNPACKED
|
||||||
: RepeatType.PACKED
|
: RepeatType.PACKED
|
||||||
: RepeatType.NO;
|
: RepeatType.NO;
|
||||||
return {
|
return {
|
||||||
no: field.no,
|
no: field.no,
|
||||||
name: key,
|
name: key,
|
||||||
kind: 'scalar',
|
kind: 'scalar',
|
||||||
T: field.type,
|
T: field.type,
|
||||||
opt: field.optional,
|
opt: field.optional,
|
||||||
repeat: repeatType,
|
repeat: repeatType,
|
||||||
};
|
};
|
||||||
} else if (field.kind === 'message') {
|
} else if (field.kind === 'message') {
|
||||||
return {
|
return {
|
||||||
no: field.no,
|
no: field.no,
|
||||||
name: key,
|
name: key,
|
||||||
kind: 'message',
|
kind: 'message',
|
||||||
repeat: field.repeat ? RepeatType.PACKED : RepeatType.NO,
|
repeat: field.repeat ? RepeatType.PACKED : RepeatType.NO,
|
||||||
T: () => NapProtoRealMsg.getInstance(field.type())._proto_msg,
|
T: () => NapProtoRealMsg.getInstance(field.type())._proto_msg,
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
}) as PartialFieldInfo[];
|
throw new Error(`Unknown field kind: ${field.kind}`);
|
||||||
this._proto_msg = new MessageType<NapProtoStructType<T, boolean>>('nya', this._field);
|
}
|
||||||
}
|
}) as PartialFieldInfo[];
|
||||||
|
this._proto_msg = new MessageType<NapProtoStructType<T, boolean>>('nya', this._field);
|
||||||
|
}
|
||||||
|
|
||||||
static getInstance<T extends ProtoMessageType>(fields: T): NapProtoRealMsg<T> {
|
static getInstance<T extends ProtoMessageType>(fields: T): NapProtoRealMsg<T> {
|
||||||
let instance = this.cache.get(fields);
|
let instance = this.cache.get(fields);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
instance = new NapProtoRealMsg(fields);
|
instance = new NapProtoRealMsg(fields);
|
||||||
this.cache.set(fields, instance);
|
this.cache.set(fields, instance);
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
encode(data: NapProtoEncodeStructType<T>): Uint8Array {
|
encode (data: NapProtoEncodeStructType<T>): Uint8Array {
|
||||||
return this._proto_msg.toBinary(this._proto_msg.create(data as PartialMessage<NapProtoEncodeStructType<T>>));
|
return this._proto_msg.toBinary(this._proto_msg.create(data as PartialMessage<NapProtoEncodeStructType<T>>));
|
||||||
}
|
}
|
||||||
|
|
||||||
decode(data: Uint8Array): NapProtoDecodeStructType<T> {
|
decode (data: Uint8Array): NapProtoDecodeStructType<T> {
|
||||||
return this._proto_msg.fromBinary(data) as NapProtoDecodeStructType<T>;
|
return this._proto_msg.fromBinary(data) as NapProtoDecodeStructType<T>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NapProtoMsg<T extends ProtoMessageType> {
|
export class NapProtoMsg<T extends ProtoMessageType> {
|
||||||
private realMsg: NapProtoRealMsg<T>;
|
private realMsg: NapProtoRealMsg<T>;
|
||||||
|
|
||||||
constructor(fields: T) {
|
constructor (fields: T) {
|
||||||
this.realMsg = NapProtoRealMsg.getInstance(fields);
|
this.realMsg = NapProtoRealMsg.getInstance(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
encode(data: NapProtoEncodeStructType<T>): Uint8Array {
|
encode (data: NapProtoEncodeStructType<T>): Uint8Array {
|
||||||
return this.realMsg.encode(data);
|
return this.realMsg.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
decode(data: Uint8Array): NapProtoDecodeStructType<T> {
|
decode (data: Uint8Array): NapProtoDecodeStructType<T> {
|
||||||
return this.realMsg.decode(data);
|
return this.realMsg.decode(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ScalarType } from '@protobuf-ts/runtime';
|
export { ScalarType } from '@protobuf-ts/runtime';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const CurrentPath = path.dirname(__filename);
|
const CurrentPath = path.dirname(__filename);
|
||||||
(async () => {
|
(async () => {
|
||||||
await import("file://" + path.join(CurrentPath, './napcat/napcat.mjs'));
|
await import('file://' + path.join(CurrentPath, './napcat/napcat.mjs'));
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -364,7 +364,7 @@ export async function NCoreInitShell () {
|
|||||||
await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname);
|
await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname);
|
||||||
handleProxy(session, logger);
|
handleProxy(session, logger);
|
||||||
|
|
||||||
let quickLoginUin: string | undefined = undefined;
|
let quickLoginUin: string | undefined;
|
||||||
try {
|
try {
|
||||||
const args = process.argv;
|
const args = process.argv;
|
||||||
const qIndex = args.findIndex(arg => arg === '-q' || arg === '--qq');
|
const qIndex = args.findIndex(arg => arg === '-q' || arg === '--qq');
|
||||||
|
|||||||
@ -3,15 +3,15 @@ import { defineConfig, PluginOption, UserConfig } from 'vite';
|
|||||||
import path, { resolve } from 'path';
|
import path, { resolve } from 'path';
|
||||||
import nodeResolve from '@rollup/plugin-node-resolve';
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
import { builtinModules } from 'module';
|
import { builtinModules } from 'module';
|
||||||
import napcatVersion from "napcat-vite/vite-plugin-version.js";
|
import napcatVersion from 'napcat-vite/vite-plugin-version.js';
|
||||||
import { autoIncludeTSPlugin } from "napcat-vite/vite-auto-include.js";
|
import { autoIncludeTSPlugin } from 'napcat-vite/vite-auto-include.js';
|
||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react-swc';
|
||||||
|
|
||||||
//依赖排除
|
// 依赖排除
|
||||||
const external = [
|
const external = [
|
||||||
'silk-wasm',
|
'silk-wasm',
|
||||||
'ws',
|
'ws',
|
||||||
'express'
|
'express',
|
||||||
];
|
];
|
||||||
|
|
||||||
const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat();
|
const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat();
|
||||||
@ -20,8 +20,8 @@ const ShellBaseConfigPlugin: PluginOption[] = [
|
|||||||
autoIncludeTSPlugin({
|
autoIncludeTSPlugin({
|
||||||
entries: [
|
entries: [
|
||||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
||||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') },
|
||||||
]
|
],
|
||||||
}),
|
}),
|
||||||
cp({
|
cp({
|
||||||
targets: [
|
targets: [
|
||||||
@ -29,7 +29,7 @@ const ShellBaseConfigPlugin: PluginOption[] = [
|
|||||||
{ src: '../napcat-webui-frontend/dist/', dest: 'dist/static/', flatten: false },
|
{ src: '../napcat-webui-frontend/dist/', dest: 'dist/static/', flatten: false },
|
||||||
{ src: '../napcat-core/external/napcat.json', dest: 'dist/config/' },
|
{ src: '../napcat-core/external/napcat.json', dest: 'dist/config/' },
|
||||||
{ src: '../../package.json', dest: 'dist' },
|
{ src: '../../package.json', dest: 'dist' },
|
||||||
{ src: '../napcat-shell-loader', dest: 'dist' }
|
{ src: '../napcat-shell-loader', dest: 'dist' },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
nodeResolve(),
|
nodeResolve(),
|
||||||
@ -62,7 +62,7 @@ const ShellBaseConfig = (source_map: boolean = false) =>
|
|||||||
fileName: (_, entryName) => `${entryName}.mjs`,
|
fileName: (_, entryName) => `${entryName}.mjs`,
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...nodeModules, ...external]
|
external: [...nodeModules, ...external],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -84,4 +84,4 @@ describe('Sha1Stream', () => {
|
|||||||
expect(hash).toEqual(expectedDigest);
|
expect(hash).toEqual(expectedDigest);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,4 +11,4 @@ export default defineConfig({
|
|||||||
'@': resolve(__dirname, '../../'),
|
'@': resolve(__dirname, '../../'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,78 +1,78 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
export function autoIncludeTSPlugin(options) {
|
export function autoIncludeTSPlugin (options) {
|
||||||
// options: { entries: [{ entry: 'napcat.ts', dir: './utils' }, ...] }
|
// options: { entries: [{ entry: 'napcat.ts', dir: './utils' }, ...] }
|
||||||
const { entries } = options;
|
const { entries } = options;
|
||||||
let tsFilesMap = {};
|
let tsFilesMap = {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'vite-auto-include',
|
name: 'vite-auto-include',
|
||||||
|
|
||||||
async buildStart() {
|
async buildStart () {
|
||||||
tsFilesMap = {};
|
tsFilesMap = {};
|
||||||
for (const { entry, dir } of entries) {
|
for (const { entry, dir } of entries) {
|
||||||
if (!tsFilesMap[entry]) {
|
if (!tsFilesMap[entry]) {
|
||||||
tsFilesMap[entry] = [];
|
tsFilesMap[entry] = [];
|
||||||
}
|
}
|
||||||
const fullDir = path.resolve(dir);
|
const fullDir = path.resolve(dir);
|
||||||
const allTsFiles = await findTSFiles(fullDir);
|
const allTsFiles = await findTSFiles(fullDir);
|
||||||
|
|
||||||
const validFiles = [];
|
const validFiles = [];
|
||||||
allTsFiles.forEach((filePath) => {
|
allTsFiles.forEach((filePath) => {
|
||||||
try {
|
try {
|
||||||
const source = fs.readFileSync(filePath, 'utf-8');
|
const source = fs.readFileSync(filePath, 'utf-8');
|
||||||
if (source && source.trim() !== '') {
|
if (source && source.trim() !== '') {
|
||||||
validFiles.push(filePath);
|
validFiles.push(filePath);
|
||||||
} else {
|
} else {
|
||||||
// Skipping empty file: ${filePath}
|
// Skipping empty file: ${filePath}
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error reading file: ${filePath}`, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
tsFilesMap[entry].push(...validFiles);
|
|
||||||
}
|
}
|
||||||
},
|
} catch (error) {
|
||||||
|
console.error(`Error reading file: ${filePath}`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
transform(code, id) {
|
tsFilesMap[entry].push(...validFiles);
|
||||||
for (const [entry, tsFiles] of Object.entries(tsFilesMap)) {
|
}
|
||||||
const isMatch = id.endsWith(entry) || id.includes(entry);
|
},
|
||||||
if (isMatch && tsFiles.length > 0) {
|
|
||||||
const imports = tsFiles.map(filePath => {
|
|
||||||
const relativePath = path.relative(path.dirname(id), filePath).replace(/\\/g, '/');
|
|
||||||
return `import './${relativePath}';`;
|
|
||||||
}).join('\n');
|
|
||||||
|
|
||||||
const transformedCode = imports + '\n' + code;
|
transform (code, id) {
|
||||||
|
for (const [entry, tsFiles] of Object.entries(tsFilesMap)) {
|
||||||
|
const isMatch = id.endsWith(entry) || id.includes(entry);
|
||||||
|
if (isMatch && tsFiles.length > 0) {
|
||||||
|
const imports = tsFiles.map(filePath => {
|
||||||
|
const relativePath = path.relative(path.dirname(id), filePath).replace(/\\/g, '/');
|
||||||
|
return `import './${relativePath}';`;
|
||||||
|
}).join('\n');
|
||||||
|
|
||||||
return {
|
const transformedCode = imports + '\n' + code;
|
||||||
code: transformedCode,
|
|
||||||
map: { mappings: '' } // 空映射即可,VSCode 可以在 TS 上断点
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return {
|
||||||
},
|
code: transformedCode,
|
||||||
|
map: { mappings: '' }, // 空映射即可,VSCode 可以在 TS 上断点
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 辅助函数:查找所有 .ts 文件
|
// 辅助函数:查找所有 .ts 文件
|
||||||
async function findTSFiles(dir) {
|
async function findTSFiles (dir) {
|
||||||
const files = [];
|
const files = [];
|
||||||
const items = await fs.promises.readdir(dir, { withFileTypes: true });
|
const items = await fs.promises.readdir(dir, { withFileTypes: true });
|
||||||
|
|
||||||
for (let item of items) {
|
for (const item of items) {
|
||||||
const fullPath = path.join(dir, item.name);
|
const fullPath = path.join(dir, item.name);
|
||||||
if (item.isDirectory()) {
|
if (item.isDirectory()) {
|
||||||
files.push(...await findTSFiles(fullPath)); // 递归查找子目录
|
files.push(...await findTSFiles(fullPath)); // 递归查找子目录
|
||||||
} else if (item.isFile() && fullPath.endsWith('.ts')) {
|
} else if (item.isFile() && fullPath.endsWith('.ts')) {
|
||||||
files.push(fullPath); // 收集 .ts 文件
|
files.push(fullPath); // 收集 .ts 文件
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import fs from "fs";
|
import fs from 'fs';
|
||||||
import path from "path";
|
import path from 'path';
|
||||||
import https from "https";
|
import https from 'https';
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@ -9,28 +9,28 @@ const __dirname = path.dirname(__filename);
|
|||||||
/**
|
/**
|
||||||
* NapCat Vite Plugin: fetches latest GitHub tag (not release) and injects into import.meta.env
|
* NapCat Vite Plugin: fetches latest GitHub tag (not release) and injects into import.meta.env
|
||||||
*/
|
*/
|
||||||
export default function vitePluginNapcatVersion() {
|
export default function vitePluginNapcatVersion () {
|
||||||
const pluginDir = path.resolve(__dirname, "dist");
|
const pluginDir = path.resolve(__dirname, 'dist');
|
||||||
const cacheFile = path.join(pluginDir, ".napcat-version.json");
|
const cacheFile = path.join(pluginDir, '.napcat-version.json');
|
||||||
const owner = "NapNeko";
|
const owner = 'NapNeko';
|
||||||
const repo = "NapCatQQ";
|
const repo = 'NapCatQQ';
|
||||||
const maxAgeMs = 24 * 60 * 60 * 1000; // cache 1 day
|
const maxAgeMs = 24 * 60 * 60 * 1000; // cache 1 day
|
||||||
const githubToken = process.env.GITHUB_TOKEN;
|
const githubToken = process.env.GITHUB_TOKEN;
|
||||||
|
|
||||||
fs.mkdirSync(pluginDir, { recursive: true });
|
fs.mkdirSync(pluginDir, { recursive: true });
|
||||||
|
|
||||||
function readCache() {
|
function readCache () {
|
||||||
try {
|
try {
|
||||||
const stat = fs.statSync(cacheFile);
|
const stat = fs.statSync(cacheFile);
|
||||||
if (Date.now() - stat.mtimeMs < maxAgeMs) {
|
if (Date.now() - stat.mtimeMs < maxAgeMs) {
|
||||||
const data = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
|
const data = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
||||||
if (data?.tag) return data.tag;
|
if (data?.tag) return data.tag;
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeCache(tag) {
|
function writeCache (tag) {
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
cacheFile,
|
cacheFile,
|
||||||
@ -39,38 +39,38 @@ export default function vitePluginNapcatVersion() {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchLatestTag() {
|
async function fetchLatestTag () {
|
||||||
const url = `https://api.github.com/repos/${owner}/${repo}/tags`;
|
const url = `https://api.github.com/repos/${owner}/${repo}/tags`;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const req = https.get(
|
const req = https.get(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": "vite-plugin-napcat-version",
|
'User-Agent': 'vite-plugin-napcat-version',
|
||||||
Accept: "application/vnd.github.v3+json",
|
Accept: 'application/vnd.github.v3+json',
|
||||||
...(githubToken ? { Authorization: `token ${githubToken}` } : {}),
|
...(githubToken ? { Authorization: `token ${githubToken}` } : {}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
(res) => {
|
(res) => {
|
||||||
let data = "";
|
let data = '';
|
||||||
res.on("data", (c) => (data += c));
|
res.on('data', (c) => (data += c));
|
||||||
res.on("end", () => {
|
res.on('end', () => {
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(data);
|
const json = JSON.parse(data);
|
||||||
if (Array.isArray(json) && json[0]?.name) {
|
if (Array.isArray(json) && json[0]?.name) {
|
||||||
resolve(json[0].name);
|
resolve(json[0].name);
|
||||||
} else reject(new Error("Invalid GitHub tag response"));
|
} else reject(new Error('Invalid GitHub tag response'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
req.on("error", reject);
|
req.on('error', reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVersion() {
|
async function getVersion () {
|
||||||
const cached = readCache();
|
const cached = readCache();
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
try {
|
try {
|
||||||
@ -78,37 +78,37 @@ export default function vitePluginNapcatVersion() {
|
|||||||
writeCache(tag);
|
writeCache(tag);
|
||||||
return tag;
|
return tag;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("[vite-plugin-napcat-version] Failed to fetch tag:", e.message);
|
console.warn('[vite-plugin-napcat-version] Failed to fetch tag:', e.message);
|
||||||
return cached ?? "v0.0.0";
|
return cached ?? 'v0.0.0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastTag = null;
|
let lastTag = null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "vite-plugin-napcat-version",
|
name: 'vite-plugin-napcat-version',
|
||||||
enforce: "pre",
|
enforce: 'pre',
|
||||||
|
|
||||||
async config(userConfig) {
|
async config (userConfig) {
|
||||||
const tag = await getVersion();
|
const tag = await getVersion();
|
||||||
console.log(`[vite-plugin-napcat-version] Using version: ${tag}`);
|
console.log(`[vite-plugin-napcat-version] Using version: ${tag}`);
|
||||||
lastTag = tag;
|
lastTag = tag;
|
||||||
return {
|
return {
|
||||||
define: {
|
define: {
|
||||||
...(userConfig.define || {}),
|
...(userConfig.define || {}),
|
||||||
"import.meta.env.VITE_NAPCAT_VERSION": JSON.stringify(tag),
|
'import.meta.env.VITE_NAPCAT_VERSION': JSON.stringify(tag),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
handleHotUpdate(ctx) {
|
handleHotUpdate (ctx) {
|
||||||
if (path.resolve(ctx.file) === cacheFile) {
|
if (path.resolve(ctx.file) === cacheFile) {
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
|
const json = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
||||||
const tag = json?.tag;
|
const tag = json?.tag;
|
||||||
if (tag && tag !== lastTag) {
|
if (tag && tag !== lastTag) {
|
||||||
lastTag = tag;
|
lastTag = tag;
|
||||||
ctx.server?.ws.send({ type: "full-reload" });
|
ctx.server?.ws.send({ type: 'full-reload' });
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { webUiPathWrapper, getInitialWebUiToken } from '@/napcat-webui-backend/index'
|
import { webUiPathWrapper, getInitialWebUiToken } from '@/napcat-webui-backend/index';
|
||||||
import { Type, Static } from '@sinclair/typebox';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
import Ajv from 'ajv';
|
import Ajv from 'ajv';
|
||||||
import fs, { constants } from 'node:fs/promises';
|
import fs, { constants } from 'node:fs/promises';
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
import eslintConfig from '../eslint.config.mjs';
|
|
||||||
export default eslintConfig;
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {}
|
autoprefixer: {},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@ -23,6 +23,6 @@ declare module 'react-color' {
|
|||||||
export const CirclePicker: any;
|
export const CirclePicker: any;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
SketchPicker: SketchPicker,
|
SketchPicker,
|
||||||
} as any;
|
} as any;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { heroui } from '@heroui/theme'
|
import { heroui } from '@heroui/theme';
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
@ -7,16 +7,16 @@ export default {
|
|||||||
'./src/layouts/**/*.{js,ts,jsx,tsx,mdx}',
|
'./src/layouts/**/*.{js,ts,jsx,tsx,mdx}',
|
||||||
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
|
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||||
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
|
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||||
'./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}'
|
'./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}',
|
||||||
],
|
],
|
||||||
safelist: [
|
safelist: [
|
||||||
{
|
{
|
||||||
pattern:
|
pattern:
|
||||||
/bg-(primary|secondary|success|danger|warning|default)-(50|100|200|300|400|500|600|700|800|900)/
|
/bg-(primary|secondary|success|danger|warning|default)-(50|100|200|300|400|500|600|700|800|900)/,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {}
|
extend: {},
|
||||||
},
|
},
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -36,7 +36,7 @@ export default {
|
|||||||
600: '#c20e4d',
|
600: '#c20e4d',
|
||||||
700: '#920b3a',
|
700: '#920b3a',
|
||||||
800: '#610726',
|
800: '#610726',
|
||||||
900: '#310413'
|
900: '#310413',
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
DEFAULT: '#DB3694',
|
DEFAULT: '#DB3694',
|
||||||
@ -50,9 +50,9 @@ export default {
|
|||||||
600: '#BC278B',
|
600: '#BC278B',
|
||||||
700: '#9D1B7F',
|
700: '#9D1B7F',
|
||||||
800: '#7F1170',
|
800: '#7F1170',
|
||||||
900: '#690A66'
|
900: '#690A66',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
colors: {
|
colors: {
|
||||||
@ -68,7 +68,7 @@ export default {
|
|||||||
600: '#f871a0',
|
600: '#f871a0',
|
||||||
700: '#faa0bf',
|
700: '#faa0bf',
|
||||||
800: '#fdd0df',
|
800: '#fdd0df',
|
||||||
900: '#fee7ef'
|
900: '#fee7ef',
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
DEFAULT: '#DB3694',
|
DEFAULT: '#DB3694',
|
||||||
@ -82,11 +82,11 @@ export default {
|
|||||||
600: '#F485AE',
|
600: '#F485AE',
|
||||||
700: '#FBAFC4',
|
700: '#FBAFC4',
|
||||||
800: '#FDD7DD',
|
800: '#FDD7DD',
|
||||||
900: '#FEEAF6'
|
900: '#FEEAF6',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
]
|
],
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react';
|
||||||
import path from 'node:path'
|
import path from 'node:path';
|
||||||
import { defineConfig, loadEnv, normalizePath } from 'vite'
|
import { defineConfig, loadEnv, normalizePath } from 'vite';
|
||||||
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
const monacoEditorPath = normalizePath(
|
const monacoEditorPath = normalizePath(
|
||||||
path.resolve(__dirname, 'node_modules/monaco-editor/min/vs')
|
path.resolve(__dirname, 'node_modules/monaco-editor/min/vs')
|
||||||
)
|
);
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
const env = loadEnv(mode, process.cwd())
|
const env = loadEnv(mode, process.cwd());
|
||||||
const backendDebugUrl = env.VITE_DEBUG_BACKEND_URL
|
const backendDebugUrl = env.VITE_DEBUG_BACKEND_URL;
|
||||||
console.log('backendDebugUrl', backendDebugUrl)
|
console.log('backendDebugUrl', backendDebugUrl);
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
@ -21,10 +21,10 @@ export default defineConfig(({ mode }) => {
|
|||||||
targets: [
|
targets: [
|
||||||
{
|
{
|
||||||
src: monacoEditorPath,
|
src: monacoEditorPath,
|
||||||
dest: 'monaco-editor/min'
|
dest: 'monaco-editor/min',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
base: '/webui/',
|
base: '/webui/',
|
||||||
server: {
|
server: {
|
||||||
@ -32,11 +32,11 @@ export default defineConfig(({ mode }) => {
|
|||||||
'/api/ws/terminal': {
|
'/api/ws/terminal': {
|
||||||
target: backendDebugUrl,
|
target: backendDebugUrl,
|
||||||
ws: true,
|
ws: true,
|
||||||
changeOrigin: true
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
'/api': backendDebugUrl,
|
'/api': backendDebugUrl,
|
||||||
'/files': backendDebugUrl
|
'/files': backendDebugUrl,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
assetsInlineLimit: 0,
|
assetsInlineLimit: 0,
|
||||||
@ -49,10 +49,10 @@ export default defineConfig(({ mode }) => {
|
|||||||
'react-hook-form': ['react-hook-form'],
|
'react-hook-form': ['react-hook-form'],
|
||||||
'react-icons': ['react-icons'],
|
'react-icons': ['react-icons'],
|
||||||
'react-hot-toast': ['react-hot-toast'],
|
'react-hot-toast': ['react-hot-toast'],
|
||||||
qface: ['qface']
|
qface: ['qface'],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|||||||
@ -12,4 +12,4 @@ export default defineConfig({
|
|||||||
'@': resolve(__dirname, 'packages'),
|
'@': resolve(__dirname, 'packages'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user