chore: 改造为后初始化

This commit is contained in:
手瓜一十雪
2024-08-08 15:13:58 +08:00
parent 5ae9be0291
commit c417a95e1f
5 changed files with 181 additions and 163 deletions

View 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;

View File

@@ -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',

View File

@@ -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;

View File

@@ -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
View File

@@ -0,0 +1 @@
//OneBot实现类