mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
chore: 改造为后初始化
This commit is contained in:
24
src/common/framwork/napcat.ts
Normal file
24
src/common/framwork/napcat.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import path, { dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
class NapCatPathWrapper {
|
||||||
|
NapCat_Main_Path: string | undefined;
|
||||||
|
NapCat_Logs_Path: string | undefined;
|
||||||
|
NapCat_Config_Path: string | undefined;
|
||||||
|
constructor() { }
|
||||||
|
Init(MainPath: string = dirname(fileURLToPath(import.meta.url))) {
|
||||||
|
this.NapCat_Main_Path = MainPath;
|
||||||
|
this.NapCat_Logs_Path = path.join(this.NapCat_Main_Path, "logs");
|
||||||
|
this.NapCat_Config_Path = path.join(this.NapCat_Main_Path, "config");
|
||||||
|
}
|
||||||
|
getScriptPath() {
|
||||||
|
return this.NapCat_Main_Path;
|
||||||
|
}
|
||||||
|
getLogsPath() {
|
||||||
|
return this.NapCat_Logs_Path;
|
||||||
|
}
|
||||||
|
getConfigPath() {
|
||||||
|
return this.NapCat_Config_Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export let NapCatPath: NapCatPathWrapper | undefined;
|
@@ -3,55 +3,65 @@ import fs from 'node:fs';
|
|||||||
import { systemPlatform } from '@/common/utils/system';
|
import { systemPlatform } from '@/common/utils/system';
|
||||||
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
|
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
|
||||||
import AppidTable from '@/core/external/appid.json';
|
import AppidTable from '@/core/external/appid.json';
|
||||||
import { log } from './log';
|
import { LogWrapper } from './log';
|
||||||
|
|
||||||
//基础目录获取
|
export class QQBasicInfoWrapper {
|
||||||
export const QQMainPath = process.execPath;
|
QQMainPath: string | undefined;
|
||||||
export const QQPackageInfoPath: string = path.join(path.dirname(QQMainPath), 'resources', 'app', 'package.json');
|
QQPackageInfoPath: string | undefined;
|
||||||
export const QQVersionConfigPath: string | undefined = getQQVersionConfigPath(QQMainPath);
|
QQVersionConfigPath: string | undefined;
|
||||||
|
isQuickUpdate: boolean | undefined;
|
||||||
|
QQVersionConfig: QQVersionConfigType | undefined;
|
||||||
|
QQPackageInfo: QQPackageInfoType | undefined;
|
||||||
|
QQVersionAppid: string | undefined;
|
||||||
|
QQVersionQua: string | undefined;
|
||||||
|
context: { logger: LogWrapper; };
|
||||||
|
constructor(context: { logger: LogWrapper }) {
|
||||||
|
//基础目录获取
|
||||||
|
this.context = context;
|
||||||
|
this.QQMainPath = process.execPath;
|
||||||
|
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json');
|
||||||
|
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
|
||||||
|
|
||||||
//基础信息获取 无快更则启用默认模板填充
|
//基础信息获取 无快更则启用默认模板填充
|
||||||
export const isQuickUpdate: boolean = !!QQVersionConfigPath;
|
this.isQuickUpdate = !!this.QQVersionConfigPath;
|
||||||
export const QQVersionConfig: QQVersionConfigType = isQuickUpdate ? JSON.parse(fs.readFileSync(QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
this.QQVersionConfig = this.isQuickUpdate ? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
||||||
export const QQPackageInfo: QQPackageInfoType = JSON.parse(fs.readFileSync(QQPackageInfoPath).toString());
|
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
|
||||||
export const { appid: QQVersionAppid, qua: QQVersionQua } = getAppidV2();
|
let { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
|
||||||
|
this.QQVersionAppid = IQQVersionAppid;
|
||||||
|
this.QQVersionQua = IQQVersionQua;
|
||||||
|
}
|
||||||
|
|
||||||
//基础函数
|
//基础函数
|
||||||
export function getQQBuildStr() {
|
getQQBuildStr() {
|
||||||
return isQuickUpdate ? QQVersionConfig.buildId : QQPackageInfo.buildVersion;
|
return this.isQuickUpdate ? this.QQVersionConfig?.buildId : this.QQPackageInfo?.buildVersion;
|
||||||
}
|
}
|
||||||
export function getFullQQVesion() {
|
getFullQQVesion() { return this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version; }
|
||||||
return isQuickUpdate ? QQVersionConfig.curVersion : QQPackageInfo.version;
|
|
||||||
}
|
requireMinNTQQBuild(buildStr: string) {
|
||||||
export function requireMinNTQQBuild(buildStr: string) {
|
let currentBuild = parseInt(this.getQQBuildStr() || '0')
|
||||||
return parseInt(getQQBuildStr()) >= parseInt(buildStr);
|
if (currentBuild == 0) throw new Error('QQBuildStr获取失败')
|
||||||
}
|
return currentBuild >= parseInt(buildStr);
|
||||||
//此方法不要直接使用
|
}
|
||||||
export function getQUAInternal() {
|
//此方法不要直接使用
|
||||||
return systemPlatform === 'linux' ? `V1_LNX_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B`;
|
getQUAInternal() {
|
||||||
}
|
return systemPlatform === 'linux' ? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||||
export function getAppidV2(): { appid: string, qua: string } {
|
}
|
||||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
getAppidV2(): { appid: string, qua: string } {
|
||||||
try {
|
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||||
const data = appidTbale[getFullQQVesion()];
|
try {
|
||||||
if (data) {
|
let fullVersion = this.getFullQQVesion();
|
||||||
return data;
|
if (!fullVersion) throw new Error('QQ版本获取失败');
|
||||||
|
const data = appidTbale[fullVersion];
|
||||||
|
if (data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||||
|
}
|
||||||
|
// 以下是兜底措施
|
||||||
|
this.context.logger.log(`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`);
|
||||||
|
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: this.getQUAInternal() };
|
||||||
}
|
}
|
||||||
catch (e) {
|
|
||||||
log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
|
||||||
}
|
|
||||||
// 以下是兜底措施
|
|
||||||
log(`[QQ版本兼容性检测] ${getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`);
|
|
||||||
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: getQUAInternal() };
|
|
||||||
}
|
}
|
||||||
// platform_type: 3,
|
export let QQBasicInfo: QQBasicInfoWrapper | undefined;
|
||||||
// app_type: 4,
|
|
||||||
// app_version: '9.9.12-25765',
|
|
||||||
// qua: 'V1_WIN_NQ_9.9.12_25765_GW_B',
|
|
||||||
// appid: '537234702',
|
|
||||||
// platVer: '10.0.26100',
|
|
||||||
// clientVer: '9.9.9-25765',
|
|
||||||
// Linux
|
|
||||||
// app_version: '3.2.9-25765',
|
|
||||||
// qua: 'V1_LNX_NQ_3.2.10_25765_GW_B',
|
|
@@ -1,7 +1,6 @@
|
|||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { log, logDebug } from './log';
|
|
||||||
import { dirname } from 'node:path';
|
import { dirname } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import * as fsPromise from 'node:fs/promises';
|
import * as fsPromise from 'node:fs/promises';
|
||||||
@@ -303,20 +302,6 @@ export function migrateConfig(oldConfig: any) {
|
|||||||
};
|
};
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
// 升级旧的配置到新的
|
|
||||||
export async function UpdateConfig() {
|
|
||||||
const configFiles = await fsPromise.readdir(path.join(__dirname, 'config'));
|
|
||||||
for (const file of configFiles) {
|
|
||||||
if (file.match(/^onebot11_\d+.json$/)) {
|
|
||||||
const CurrentConfig = JSON.parse(await fsPromise.readFile(path.join(__dirname, 'config', file), 'utf8'));
|
|
||||||
if (isValidOldConfig(CurrentConfig)) {
|
|
||||||
log('正在迁移旧配置到新配置 File:', file);
|
|
||||||
const NewConfig = migrateConfig(CurrentConfig);
|
|
||||||
await fsPromise.writeFile(path.join(__dirname, 'config', file), JSON.stringify(NewConfig, null, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function isEqual(obj1: any, obj2: any) {
|
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;
|
||||||
|
@@ -1,13 +1,7 @@
|
|||||||
import log4js, { Configuration } from 'log4js';
|
import log4js, { Configuration } from 'log4js';
|
||||||
import { truncateString } from '@/common/utils/helper';
|
import { truncateString } from '@/common/utils/helper';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { dirname } from 'node:path';
|
|
||||||
import { fileURLToPath } from 'node:url';
|
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = dirname(__filename);
|
|
||||||
|
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
DEBUG = 'debug',
|
DEBUG = 'debug',
|
||||||
INFO = 'info',
|
INFO = 'info',
|
||||||
@@ -15,9 +9,6 @@ export enum LogLevel {
|
|||||||
ERROR = 'error',
|
ERROR = 'error',
|
||||||
FATAL = 'fatal',
|
FATAL = 'fatal',
|
||||||
}
|
}
|
||||||
|
|
||||||
const logDir = path.join(path.resolve(__dirname), 'logs');
|
|
||||||
|
|
||||||
function getFormattedTimestamp() {
|
function getFormattedTimestamp() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const year = now.getFullYear();
|
const year = now.getFullYear();
|
||||||
@@ -29,109 +20,116 @@ function getFormattedTimestamp() {
|
|||||||
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
|
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
|
||||||
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
|
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
|
||||||
}
|
}
|
||||||
|
export class LogWrapper {
|
||||||
const filename = `${getFormattedTimestamp()}.log`;
|
fileLogEnabled = true;
|
||||||
const logPath = path.join(logDir, filename);
|
consoleLogEnabled = true;
|
||||||
|
logConfig: Configuration;
|
||||||
const logConfig: Configuration = {
|
loggerConsole: log4js.Logger;
|
||||||
appenders: {
|
loggerFile: log4js.Logger;
|
||||||
FileAppender: { // 输出到文件的appender
|
loggerDefault: log4js.Logger;
|
||||||
type: 'file',
|
// eslint-disable-next-line no-control-regex
|
||||||
filename: logPath, // 指定日志文件的位置和文件名
|
colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
|
||||||
maxLogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
constructor(logDir: string) {
|
||||||
layout: {
|
// logDir = path.join(path.resolve(__dirname), 'logs');
|
||||||
type: 'pattern',
|
const filename = `${getFormattedTimestamp()}.log`;
|
||||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] %X{userInfo} | %m'
|
const logPath = path.join(logDir, filename);
|
||||||
|
this.logConfig = {
|
||||||
|
appenders: {
|
||||||
|
FileAppender: { // 输出到文件的appender
|
||||||
|
type: 'file',
|
||||||
|
filename: logPath, // 指定日志文件的位置和文件名
|
||||||
|
maxLogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
||||||
|
layout: {
|
||||||
|
type: 'pattern',
|
||||||
|
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] %X{userInfo} | %m'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ConsoleAppender: { // 输出到控制台的appender
|
||||||
|
type: 'console',
|
||||||
|
layout: {
|
||||||
|
type: 'pattern',
|
||||||
|
pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
categories: {
|
||||||
|
default: { appenders: ['FileAppender', 'ConsoleAppender'], level: 'debug' }, // 默认情况下同时输出到文件和控制台
|
||||||
|
file: { appenders: ['FileAppender'], level: 'debug' },
|
||||||
|
console: { appenders: ['ConsoleAppender'], level: 'debug' }
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
ConsoleAppender: { // 输出到控制台的appender
|
log4js.configure(this.logConfig);
|
||||||
type: 'console',
|
this.loggerConsole = log4js.getLogger('console');
|
||||||
layout: {
|
this.loggerFile = log4js.getLogger('file');
|
||||||
type: 'pattern',
|
this.loggerDefault = log4js.getLogger('default');
|
||||||
pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m`
|
this.setLogSelfInfo({ nick: '', uin: '', uid: '' });
|
||||||
|
}
|
||||||
|
setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||||
|
this.logConfig.categories.file.level = fileLogLevel;
|
||||||
|
this.logConfig.categories.console.level = consoleLogLevel;
|
||||||
|
log4js.configure(this.logConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLogSelfInfo(selfInfo: { nick: string, uin: string, uid: string }) {
|
||||||
|
const userInfo = `${selfInfo.nick}(${selfInfo.uin})`;
|
||||||
|
this.loggerConsole.addContext('userInfo', userInfo);
|
||||||
|
this.loggerFile.addContext('userInfo', userInfo);
|
||||||
|
this.loggerDefault.addContext('userInfo', userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enableFileLog(enable: boolean) {
|
||||||
|
this.fileLogEnabled = enable;
|
||||||
|
}
|
||||||
|
enableConsoleLog(enable: boolean) {
|
||||||
|
this.consoleLogEnabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatMsg(msg: any[]) {
|
||||||
|
let logMsg = '';
|
||||||
|
for (const msgItem of msg) {
|
||||||
|
if (msgItem instanceof Error) { // 判断是否是错误
|
||||||
|
logMsg += msgItem.stack + ' ';
|
||||||
|
continue;
|
||||||
|
} else if (typeof msgItem === 'object') { // 判断是否是对象
|
||||||
|
const obj = JSON.parse(JSON.stringify(msgItem, null, 2));
|
||||||
|
logMsg += JSON.stringify(truncateString(obj)) + ' ';
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
logMsg += msgItem + ' ';
|
||||||
}
|
}
|
||||||
},
|
return logMsg;
|
||||||
categories: {
|
|
||||||
default: { appenders: ['FileAppender', 'ConsoleAppender'], level: 'debug' }, // 默认情况下同时输出到文件和控制台
|
|
||||||
file: { appenders: ['FileAppender'], level: 'debug' },
|
|
||||||
console: { appenders: ['ConsoleAppender'], level: 'debug' }
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
log4js.configure(logConfig);
|
|
||||||
const loggerConsole = log4js.getLogger('console');
|
|
||||||
const loggerFile = log4js.getLogger('file');
|
|
||||||
const loggerDefault = log4js.getLogger('default');
|
|
||||||
|
|
||||||
export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
|
||||||
logConfig.categories.file.level = fileLogLevel;
|
|
||||||
logConfig.categories.console.level = consoleLogLevel;
|
|
||||||
log4js.configure(logConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setLogSelfInfo(selfInfo: { nick: string, uin: string, uid: string }) {
|
_log(level: LogLevel, ...args: any[]) {
|
||||||
const userInfo = `${selfInfo.nick}(${selfInfo.uin})`;
|
if (this.consoleLogEnabled) {
|
||||||
loggerConsole.addContext('userInfo', userInfo);
|
this.loggerConsole[level](this.formatMsg(args));
|
||||||
loggerFile.addContext('userInfo', userInfo);
|
}
|
||||||
loggerDefault.addContext('userInfo', userInfo);
|
if (this.fileLogEnabled) {
|
||||||
}
|
this.loggerFile[level](this.formatMsg(args).replace(this.colorEscape, ''));
|
||||||
setLogSelfInfo({ nick: '', uin: '', uid: '' });
|
|
||||||
|
|
||||||
let fileLogEnabled = true;
|
|
||||||
let consoleLogEnabled = true;
|
|
||||||
export function enableFileLog(enable: boolean) {
|
|
||||||
fileLogEnabled = enable;
|
|
||||||
}
|
|
||||||
export function enableConsoleLog(enable: boolean) {
|
|
||||||
consoleLogEnabled = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatMsg(msg: any[]) {
|
|
||||||
let logMsg = '';
|
|
||||||
for (const msgItem of msg) {
|
|
||||||
if (msgItem instanceof Error) { // 判断是否是错误
|
|
||||||
logMsg += msgItem.stack + ' ';
|
|
||||||
continue;
|
|
||||||
} else if (typeof msgItem === 'object') { // 判断是否是对象
|
|
||||||
const obj = JSON.parse(JSON.stringify(msgItem, null, 2));
|
|
||||||
logMsg += JSON.stringify(truncateString(obj)) + ' ';
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
logMsg += msgItem + ' ';
|
|
||||||
}
|
}
|
||||||
return logMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-control-regex
|
log(...args: any[]) {
|
||||||
const colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
|
// info 等级
|
||||||
|
this._log(LogLevel.INFO, ...args);
|
||||||
function _log(level: LogLevel, ...args: any[]) {
|
|
||||||
if (consoleLogEnabled) {
|
|
||||||
loggerConsole[level](formatMsg(args));
|
|
||||||
}
|
}
|
||||||
if (fileLogEnabled) {
|
|
||||||
loggerFile[level](formatMsg(args).replace(colorEscape, ''));
|
logDebug(...args: any[]) {
|
||||||
|
this._log(LogLevel.DEBUG, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
logError(...args: any[]) {
|
||||||
|
this._log(LogLevel.ERROR, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
logWarn(...args: any[]) {
|
||||||
|
this._log(LogLevel.WARN, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
logFatal(...args: any[]) {
|
||||||
|
this._log(LogLevel.FATAL, ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function log(...args: any[]) {
|
|
||||||
// info 等级
|
|
||||||
_log(LogLevel.INFO, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logDebug(...args: any[]) {
|
|
||||||
_log(LogLevel.DEBUG, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logError(...args: any[]) {
|
|
||||||
_log(LogLevel.ERROR, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logWarn(...args: any[]) {
|
|
||||||
_log(LogLevel.WARN, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logFatal(...args: any[]) {
|
|
||||||
_log(LogLevel.FATAL, ...args);
|
|
||||||
}
|
|
1
src/onebot/index.ts
Normal file
1
src/onebot/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
//OneBot实现类
|
Reference in New Issue
Block a user