This commit is contained in:
手瓜一十雪 2024-06-04 12:39:08 +08:00
commit 4dd7363dd3
15 changed files with 94 additions and 68 deletions

View File

@ -19,6 +19,7 @@
},
"devDependencies": {
"@log4js-node/log4js-api": "^1.0.2",
"@protobuf-ts/plugin": "^2.9.4",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6",
"@types/cors": "^2.8.17",
@ -43,11 +44,11 @@
"vite": "^5.2.6",
"vite-plugin-cp": "^4.0.8",
"vite-plugin-dts": "^3.8.2",
"vite-tsconfig-paths": "^4.3.2",
"@protobuf-ts/plugin": "^2.9.4"
"vite-tsconfig-paths": "^4.3.2"
},
"dependencies": {
"ajv": "^8.13.0",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"cors": "^2.8.5",
"express": "^5.0.0-beta.2",

View File

@ -1,5 +1,5 @@
import { sleep } from '@/common/utils/helper';
import { logError } from './log';
type AsyncQueueTask = (() => void) | (()=>Promise<void>);
@ -26,7 +26,8 @@ export class AsyncQueue {
await taskRet;
}
} catch (e) {
console.error(e);
// console.error(e);
logError(e);
}
this.tasks.shift();
await sleep(100);

View File

@ -2,6 +2,7 @@ import path from 'node:path';
import fs from 'node:fs';
import os from 'node:os';
import { systemPlatform } from '@/common/utils/system';
import { logError } from '@/common/utils/log';
export const exePath = process.execPath;
@ -49,7 +50,7 @@ if (fs.existsSync(configVersionInfoPath)) {
const _ =JSON.parse(fs.readFileSync(configVersionInfoPath).toString());
_qqVersionConfigInfo = Object.assign(_qqVersionConfigInfo, _);
} catch (e) {
console.error('Load QQ version config info failed, Use default version', e);
logError('Load QQ version config info failed, Use default version', e);
}
}

View File

@ -24,7 +24,7 @@ export async function encodeSilk(filePath: string) {
const fileHeader = buffer.toString('hex', 0, bytesToRead);
return fileHeader;
} catch (err) {
console.error('读取文件错误:', err);
logError('读取文件错误:', err);
return;
}
}

View File

@ -4,7 +4,6 @@ import fs from 'fs';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export function getModuleWithArchName(moduleName: string) {

View File

@ -498,7 +498,7 @@ class DBUtil extends DBUtilBase {
if (err)
logError(err),
Promise.reject(),
console.log('插入入群时间失败', userId, groupId);
logError('插入入群时间失败', userId, groupId);
}
);

View File

@ -3,7 +3,7 @@ import fsPromise from 'fs/promises';
import crypto from 'crypto';
import util from 'util';
import path from 'node:path';
import { log } from './log';
import { log, logError } from './log';
import { dbUtil } from '@/common/utils/db';
import * as fileType from 'file-type';
import { v4 as uuidv4 } from 'uuid';
@ -262,12 +262,12 @@ export async function copyFolder(sourcePath: string, destPath: string) {
try {
await fsPromise.copyFile(srcPath, dstPath);
} catch (error) {
console.error(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
logError(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
// 这里可以决定是否要继续复制其他文件
}
}
}
} catch (error) {
console.error('复制文件夹时出错:', error);
logError('复制文件夹时出错:', error);
}
}

View File

@ -4,7 +4,7 @@ import path from 'node:path';
import { SelfInfo } from '@/core';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import chalk from 'chalk';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
@ -42,14 +42,14 @@ const logConfig: Configuration = {
maxLoogSize: 10485760, // 日志文件的最大大小单位字节这里设置为10MB
layout: {
type: 'pattern',
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] - %m'
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] - %m'
pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m`
}
}
},
@ -61,7 +61,9 @@ const logConfig: Configuration = {
};
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;
@ -70,12 +72,12 @@ export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
}
export function setLogSelfInfo(selfInfo: SelfInfo) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
logConfig.appenders.FileAppender.layout.pattern = logConfig.appenders.ConsoleAppender.layout.pattern =
`%d{yyyy-MM-dd hh:mm:ss} [%p] ${selfInfo.nick}(${selfInfo.uin}) %m`;
log4js.configure(logConfig);
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;
@ -86,7 +88,7 @@ export function enableConsoleLog(enable: boolean) {
consoleLogEnabled = enable;
}
function formatMsg(msg: any[]){
function formatMsg(msg: any[]) {
let logMsg = '';
for (const msgItem of msg) {
// 判断是否是对象
@ -97,15 +99,18 @@ function formatMsg(msg: any[]){
}
logMsg += msgItem + ' ';
}
return '\n' + logMsg + '\n';
return logMsg;
}
function _log(level: LogLevel, ...args: any[]){
if (consoleLogEnabled){
log4js.getLogger('console')[level](formatMsg(args));
// eslint-disable-next-line no-control-regex
const colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
function _log(level: LogLevel, ...args: any[]) {
if (consoleLogEnabled) {
loggerConsole[level](formatMsg(args));
}
if (fileLogEnabled){
log4js.getLogger('file')[level](formatMsg(args));
if (fileLogEnabled) {
loggerFile[level](formatMsg(args).replace(colorEscape, ''));
}
}
@ -121,3 +126,11 @@ export function logDebug(...args: any[]) {
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);
}

View File

@ -24,7 +24,7 @@ export async function getVideoInfo(filePath: string) {
} else {
const videoStream = metadata.streams.find((s: { codec_type: string; }) => s.codec_type === 'video');
if (videoStream) {
console.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
} else {
return reject('未找到视频流信息。');
}

View File

@ -5,18 +5,19 @@ import fs from 'fs/promises';
import fsSync from 'fs';
import path from 'node:path';
import { checkVersion } from '@/common/utils/version';
import { log, logDebug, logError, LogLevel, setLogLevel } from '@/common/utils/log';
import { log, logDebug, logError, LogLevel, logWarn, setLogLevel } from '@/common/utils/log';
import { NapCatOnebot11 } from '@/onebot11/main';
import { InitWebUi } from './webui/index';
import { WebUiDataRuntime } from './webui/src/helper/Data';
import { UpdateConfig } from './common/utils/helper';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import chalk from 'chalk';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const tagColor = chalk.cyan;
program
.option('-q, --qq <type>', 'QQ号')
.parse(process.argv);
@ -31,19 +32,19 @@ checkVersion().then(async (remoteVersion: string) => {
const localVersion = JSON.parse(fsSync.readFileSync(path.join(__dirname, 'package.json')).toString()).version;
const localVersionList = localVersion.split('.');
const remoteVersionList = remoteVersion.split('.');
log('[NapCat] 当前版本:', localVersion);
log(tagColor('[NapCat]'), '当前版本:', localVersion);
for (const k of [0, 1, 2]) {
if (parseInt(remoteVersionList[k]) > parseInt(localVersionList[k])) {
console.log(`[NapCat] 检测到更新,请前往 https://github.com/NapNeko/NapCatQQ 下载 NapCatQQ V ${remoteVersion}`);
logWarn(tagColor('[NapCat]'), `检测到更新,请前往 https://github.com/NapNeko/NapCatQQ 下载 NapCatQQ V ${remoteVersion}`);
return;
} else if (parseInt(remoteVersionList[k]) < parseInt(localVersionList[k])) {
break;
}
}
logDebug('[NapCat] 当前已是最新版本');
logDebug(tagColor('[NapCat]'),'当前已是最新版本');
return;
}).catch((e) => {
logError('[NapCat] 检测更新失败', e);
logError(tagColor('[NapCat]'),'检测更新失败', e);
});
// 不是很好待优化
const NapCat_OneBot11 = new NapCatOnebot11();
@ -51,18 +52,18 @@ const NapCat_OneBot11 = new NapCatOnebot11();
WebUiDataRuntime.setOB11ConfigCall(NapCat_OneBot11.SetConfig);
napCatCore.onLoginSuccess((uin, uid) => {
console.log('登录成功!');
log('登录成功!');
WebUiDataRuntime.setQQLoginStatus(true);
WebUiDataRuntime.setQQLoginUin(uin.toString());
});
const showQRCode = async (url: string, base64: string, buffer: Buffer) => {
await WebUiDataRuntime.setQQLoginQrcodeURL(url);
console.log('请扫描下面的二维码然后在手Q上授权登录');
logWarn('请扫描下面的二维码然后在手Q上授权登录');
const qrcodePath = path.join(__dirname, 'qrcode.png');
qrcode.generate(url, { small: true }, (res) => {
console.log(`${res}\n二维码解码URL: ${url}\n如果控制台二维码无法扫码可以复制解码url到二维码生成网站生成二维码再扫码也可以打开下方的二维码路径图片进行扫码`);
logWarn(`\n${res}\n二维码解码URL: ${url}\n如果控制台二维码无法扫码可以复制解码url到二维码生成网站生成二维码再扫码也可以打开下方的二维码路径图片进行扫码`);
fs.writeFile(qrcodePath, buffer).then(() => {
console.log('二维码已保存到', qrcodePath);
logWarn('二维码已保存到', qrcodePath);
});
});
};
@ -86,7 +87,7 @@ WebUiDataRuntime.setQQQuickLoginCall(async (uin: string) => {
}
resolve({ result: true, message: '' });
}).catch((e) => {
console.error(e);
logError(e);
resolve({ result: false, message: '快速登录发生错误' });
});
} else {
@ -104,7 +105,7 @@ if (quickLoginQQ) {
logError('快速登录错误:', res.loginErrorInfo.errMsg);
}
}).catch((e) => {
console.error(e);
logError(e);
napCatCore.qrLogin(showQRCode);
});
} else {

View File

@ -9,6 +9,7 @@ import {
} from '@/core/entities';
import { dbUtil } from '@/common/utils/db';
import { NTQQFileApi, NTQQFileCacheApi } from '@/core/apis/file';
import { logError } from '@/common/utils/log';
export default class CleanCache extends BaseAction<void, void> {
actionName = ActionName.CleanCache;
@ -62,7 +63,7 @@ export default class CleanCache extends BaseAction<void, void> {
await NTQQFileCacheApi.clearChatCache(chatCacheList, cacheFileList);
res();
} catch(e) {
console.error('清理缓存时发生了错误');
logError('清理缓存时发生了错误');
rej(e);
}
});

View File

@ -3,19 +3,23 @@ import { log } from '@/common/utils/log';
import { getGroup, getGroupMember, selfInfo } from '@/core/data';
import exp from 'constants';
import { Group } from '@/core';
import chalk from 'chalk';
const spSegColor = chalk.blue;// for special segment
const spColor = chalk.cyan;// for special
// todo: 应该放到core去用RawMessage解析打印
export async function logMessage(ob11Message: OB11Message){
export async function logMessage(ob11Message: OB11Message) {
const isSelfSent = ob11Message.sender.user_id.toString() === selfInfo.uin;
let prefix = '';
let group: Group | undefined;
if (isSelfSent){
if (isSelfSent) {
prefix = '发送消息 ';
if (ob11Message.message_type === 'private'){
if (ob11Message.message_type === 'private') {
prefix += '给私聊 ';
prefix += `${ob11Message.target_id}`;
}
else{
else {
prefix += '给群聊 ';
}
}
@ -25,57 +29,60 @@ export async function logMessage(ob11Message: OB11Message){
}
let msgChain = '';
if (Array.isArray(ob11Message.message)) {
const msgParts = [];
for (const segment of ob11Message.message) {
if (segment.type === 'text') {
msgChain += segment.data.text + '\n';
msgParts.push(segment.data.text);
}
else if (segment.type === 'at') {
const groupMember = await getGroupMember(ob11Message.group_id!, segment.data.qq!);
msgChain += `@${groupMember?.cardName || groupMember?.nick}(${segment.data.qq}) `;
msgParts.push(spSegColor(`[@${groupMember?.cardName || groupMember?.nick}(${segment.data.qq})]`));
}
else if (segment.type === 'reply') {
msgChain += `回复消息(id:${segment.data.id}) `;
msgParts.push(spSegColor(`[回复消息|id:${segment.data.id}]`));
}
else if (segment.type === 'image') {
msgChain += `\n[图片]${segment.data.url}\n`;
msgParts.push(spSegColor(`[图片|${segment.data.url}]`));
}
else if (segment.type === 'face'){
msgChain += `[表情](id:${segment.data.id}) `;
else if (segment.type === 'face') {
msgParts.push(spSegColor(`[表情|id:${segment.data.id}]`));
}
else if (segment.type === 'mface'){
msgChain += `\n[商城表情]${segment.data.url}\n`;
else if (segment.type === 'mface') {
// @ts-expect-error 商城表情 url
msgParts.push(spSegColor(`[商城表情|${segment.data.url}]`));
}
else if (segment.type === 'record') {
msgChain += `[语音]${segment.data.file} `;
msgParts.push(spSegColor(`[语音|${segment.data.file}]`));
}
else if (segment.type === 'file') {
msgChain += `[文件]${segment.data.file} `;
msgParts.push(spSegColor(`[文件|${segment.data.file}]`));
}
else if (segment.type === 'json') {
msgChain += `\n[json]${JSON.stringify(segment.data)}\n`;
msgParts.push(spSegColor(`[json|${JSON.stringify(segment.data)}]`));
}
else if (segment.type === 'markdown') {
msgChain += `\n[json]${segment.data.content}\n`;
msgParts.push(spSegColor(`[markdown|${segment.data.content}]`));
}
else {
msgChain += `${JSON.stringify(segment)}`;
msgParts.push(spSegColor(`[未实现|${JSON.stringify(segment)}]`));
}
}
msgChain = msgParts.join(' ');
}
else {
msgChain = ob11Message.message;
}
let msgString = `${prefix}${ob11Message.sender.nickname}(${ob11Message.sender.user_id}): ${msgChain}`;
if (isSelfSent){
if (isSelfSent) {
msgString = `${prefix}: ${msgChain}`;
}
log(msgString);
}
export async function logNotice(ob11Notice: any){
log('[notice]', ob11Notice);
export async function logNotice(ob11Notice: any) {
log(spColor('[Notice]'), ob11Notice);
}
export async function logRequest(ob11Request: any){
log('[request]', ob11Request);
export async function logRequest(ob11Request: any) {
log(spColor('[Request]'), ob11Request);
}

View File

@ -112,7 +112,7 @@ export class NapCatOnebot11 {
try {
// 生产环境会自己去掉
if (import.meta.env.MODE == 'development') {
console.log(buf2hex(Buffer.from(protobufData)));
logDebug(buf2hex(Buffer.from(protobufData)));
}
const sysMsg = SysData.fromBinary(Buffer.from(protobufData));
const peeruin = sysMsg.header[0].peerNumber;
@ -258,7 +258,7 @@ export class NapCatOnebot11 {
for (const member of members.values()) {
//console.log(member?.isDelete, role, isPrivilege);
if (member?.isDelete && !isPrivilege /*&& selfInfo.uin !== member.uin*/) {
console.log('[群聊] 群组 ', groupCode, ' 成员' + member.uin + '退出');
log('[群聊] 群组 ', groupCode, ' 成员' + member.uin + '退出');
const groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(groupCode), parseInt(member.uin), 0, 'leave');// 不知道怎么出去的
postOB11Event(groupDecreaseEvent, true);
}

View File

@ -7,6 +7,7 @@ import { WebUiConfig } from './src/helper/config';
const app = express();
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { log } from '@/common/utils/log';
const __filename = fileURLToPath(import.meta.url);
@ -32,8 +33,8 @@ export async function InitWebUi() {
//挂载API接口
app.use('/api', ALLRouter);
app.listen(config.port, async () => {
console.log(`[NapCat] [WebUi] Current WebUi is running at IP:${config.port}`);
console.log(`[NapCat] [WebUi] Login Token is ${config.token}`);
log(`[NapCat] [WebUi] Current WebUi is running at IP:${config.port}`);
log(`[NapCat] [WebUi] Login Token is ${config.token}`);
});
}

View File

@ -3,6 +3,7 @@ import { resolve } from 'node:path';
import * as net from 'node:net';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { logError } from '@/common/utils/log';
const __filename = fileURLToPath(import.meta.url);
@ -78,7 +79,7 @@ class WebUiConfigWrapper {
this.WebUiConfigData = parsedConfig;
return this.WebUiConfigData;
} catch (e) {
console.error('读取配置文件失败', e);
logError('读取配置文件失败', e);
}
return {} as WebUiConfigType; // 理论上这行代码到不了,为了保持函数完整性而保留
}