diff --git a/src/common/framwork/napcat.ts b/src/common/framwork/napcat.ts new file mode 100644 index 00000000..4a55ab60 --- /dev/null +++ b/src/common/framwork/napcat.ts @@ -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; \ No newline at end of file diff --git a/src/common/utils/QQBasicInfo.ts b/src/common/utils/QQBasicInfo.ts index e69c3827..214c7117 100644 --- a/src/common/utils/QQBasicInfo.ts +++ b/src/common/utils/QQBasicInfo.ts @@ -3,55 +3,65 @@ import fs from 'node:fs'; import { systemPlatform } from '@/common/utils/system'; import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper'; import AppidTable from '@/core/external/appid.json'; -import { log } from './log'; +import { LogWrapper } from './log'; -//基础目录获取 -export const QQMainPath = process.execPath; -export const QQPackageInfoPath: string = path.join(path.dirname(QQMainPath), 'resources', 'app', 'package.json'); -export const QQVersionConfigPath: string | undefined = getQQVersionConfigPath(QQMainPath); +export class QQBasicInfoWrapper { + QQMainPath: string | undefined; + QQPackageInfoPath: string | undefined; + QQVersionConfigPath: string | undefined; + isQuickUpdate: boolean | undefined; + QQVersionConfig: QQVersionConfigType | undefined; + QQPackageInfo: QQPackageInfoType | undefined; + QQVersionAppid: string | undefined; + QQVersionQua: string | undefined; + context: { logger: LogWrapper; }; + constructor(context: { logger: LogWrapper }) { + //基础目录获取 + this.context = context; + this.QQMainPath = process.execPath; + this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json'); + this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath); -//基础信息获取 无快更则启用默认模板填充 -export const isQuickUpdate: boolean = !!QQVersionConfigPath; -export const QQVersionConfig: QQVersionConfigType = isQuickUpdate ? JSON.parse(fs.readFileSync(QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo(); -export const QQPackageInfo: QQPackageInfoType = JSON.parse(fs.readFileSync(QQPackageInfoPath).toString()); -export const { appid: QQVersionAppid, qua: QQVersionQua } = getAppidV2(); + //基础信息获取 无快更则启用默认模板填充 + this.isQuickUpdate = !!this.QQVersionConfigPath; + this.QQVersionConfig = this.isQuickUpdate ? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo(); + this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString()); + let { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2(); + this.QQVersionAppid = IQQVersionAppid; + this.QQVersionQua = IQQVersionQua; + } -//基础函数 -export function getQQBuildStr() { - return isQuickUpdate ? QQVersionConfig.buildId : QQPackageInfo.buildVersion; -} -export function getFullQQVesion() { - return isQuickUpdate ? QQVersionConfig.curVersion : QQPackageInfo.version; -} -export function requireMinNTQQBuild(buildStr: string) { - return parseInt(getQQBuildStr()) >= parseInt(buildStr); -} -//此方法不要直接使用 -export function getQUAInternal() { - return systemPlatform === 'linux' ? `V1_LNX_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B`; -} -export function getAppidV2(): { appid: string, qua: string } { - const appidTbale = AppidTable as unknown as QQAppidTableType; - try { - const data = appidTbale[getFullQQVesion()]; - if (data) { - return data; + //基础函数 + getQQBuildStr() { + return this.isQuickUpdate ? this.QQVersionConfig?.buildId : this.QQPackageInfo?.buildVersion; + } + getFullQQVesion() { return this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version; } + + requireMinNTQQBuild(buildStr: string) { + let currentBuild = parseInt(this.getQQBuildStr() || '0') + if (currentBuild == 0) throw new Error('QQBuildStr获取失败') + return currentBuild >= parseInt(buildStr); + } + //此方法不要直接使用 + getQUAInternal() { + return systemPlatform === 'linux' ? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`; + } + getAppidV2(): { appid: string, qua: string } { + const appidTbale = AppidTable as unknown as QQAppidTableType; + try { + let fullVersion = this.getFullQQVesion(); + 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, -// 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', +export let QQBasicInfo: QQBasicInfoWrapper | undefined; \ No newline at end of file diff --git a/src/common/utils/helper.ts b/src/common/utils/helper.ts index f311d7a2..bc3dc1ce 100644 --- a/src/common/utils/helper.ts +++ b/src/common/utils/helper.ts @@ -1,7 +1,6 @@ import crypto from 'node:crypto'; import path from 'node:path'; import fs from 'fs'; -import { log, logDebug } from './log'; import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import * as fsPromise from 'node:fs/promises'; @@ -303,20 +302,6 @@ export function migrateConfig(oldConfig: any) { }; 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) { if (obj1 === obj2) return true; if (obj1 == null || obj2 == null) return false; diff --git a/src/common/utils/log.ts b/src/common/utils/log.ts index b21ddfb6..56f998e8 100644 --- a/src/common/utils/log.ts +++ b/src/common/utils/log.ts @@ -1,13 +1,7 @@ import log4js, { Configuration } from 'log4js'; import { truncateString } from '@/common/utils/helper'; import path from 'node:path'; -import { dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; import chalk from 'chalk'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - export enum LogLevel { DEBUG = 'debug', INFO = 'info', @@ -15,9 +9,6 @@ export enum LogLevel { ERROR = 'error', FATAL = 'fatal', } - -const logDir = path.join(path.resolve(__dirname), 'logs'); - function getFormattedTimestamp() { const now = new Date(); const year = now.getFullYear(); @@ -29,109 +20,116 @@ function getFormattedTimestamp() { const milliseconds = now.getMilliseconds().toString().padStart(3, '0'); return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`; } - -const filename = `${getFormattedTimestamp()}.log`; -const logPath = path.join(logDir, filename); - -const logConfig: Configuration = { - 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' +export class LogWrapper { + fileLogEnabled = true; + consoleLogEnabled = true; + logConfig: Configuration; + loggerConsole: log4js.Logger; + loggerFile: log4js.Logger; + loggerDefault: log4js.Logger; + // eslint-disable-next-line no-control-regex + colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g; + constructor(logDir: string) { + // logDir = path.join(path.resolve(__dirname), 'logs'); + const filename = `${getFormattedTimestamp()}.log`; + 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 - type: 'console', - layout: { - type: 'pattern', - pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m` + }; + log4js.configure(this.logConfig); + this.loggerConsole = log4js.getLogger('console'); + this.loggerFile = log4js.getLogger('file'); + this.loggerDefault = log4js.getLogger('default'); + this.setLogSelfInfo({ nick: '', uin: '', uid: '' }); + } + setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) { + this.logConfig.categories.file.level = fileLogLevel; + this.logConfig.categories.console.level = consoleLogLevel; + 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 + ' '; } - }, - categories: { - default: { appenders: ['FileAppender', 'ConsoleAppender'], level: 'debug' }, // 默认情况下同时输出到文件和控制台 - file: { appenders: ['FileAppender'], level: 'debug' }, - console: { appenders: ['ConsoleAppender'], level: 'debug' } + return logMsg; } -}; -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 }) { - const userInfo = `${selfInfo.nick}(${selfInfo.uin})`; - loggerConsole.addContext('userInfo', userInfo); - loggerFile.addContext('userInfo', userInfo); - loggerDefault.addContext('userInfo', userInfo); -} -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; + _log(level: LogLevel, ...args: any[]) { + if (this.consoleLogEnabled) { + this.loggerConsole[level](this.formatMsg(args)); + } + if (this.fileLogEnabled) { + this.loggerFile[level](this.formatMsg(args).replace(this.colorEscape, '')); } - logMsg += msgItem + ' '; } - return logMsg; -} -// eslint-disable-next-line no-control-regex -const colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g; - -function _log(level: LogLevel, ...args: any[]) { - if (consoleLogEnabled) { - loggerConsole[level](formatMsg(args)); + log(...args: any[]) { + // info 等级 + this._log(LogLevel.INFO, ...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); -} \ No newline at end of file diff --git a/src/onebot/index.ts b/src/onebot/index.ts new file mode 100644 index 00000000..7f3b456c --- /dev/null +++ b/src/onebot/index.ts @@ -0,0 +1 @@ +//OneBot实现类 \ No newline at end of file