From 45b1f369ac6e96eb5f9af4c2e38edba39fb2013c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Mon, 2 Dec 2024 11:44:37 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E5=BC=82=E6=AD=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/log.ts | 29 ++++++++----------- src/common/request.ts | 21 -------------- src/onebot/action/extends/SetQQAvatar.ts | 8 ++--- .../action/go-cqhttp/SendGroupNotice.ts | 5 ++-- .../action/go-cqhttp/SetGroupPortrait.ts | 11 ++++--- src/onebot/api/msg.ts | 18 +++++------- src/webui/src/api/Log.ts | 4 +-- src/webui/src/helper/config.ts | 22 +++++++------- 8 files changed, 42 insertions(+), 76 deletions(-) diff --git a/src/common/log.ts b/src/common/log.ts index 0965f4ea..870f0c66 100644 --- a/src/common/log.ts +++ b/src/common/log.ts @@ -1,7 +1,7 @@ import winston, { format, transports } from 'winston'; import { truncateString } from '@/common/helper'; import path from 'node:path'; -import fs from 'node:fs'; +import fs from 'node:fs/promises'; import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core'; import EventEmitter from 'node:events'; export enum LogLevel { @@ -97,26 +97,20 @@ export class LogWrapper { cleanOldLogs(logDir: string) { const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000; - fs.readdir(logDir, (err, files) => { - if (err) { - this.logger.error('Failed to read log directory', err); - return; - } + fs.readdir(logDir).then((files) => { files.forEach((file) => { const filePath = path.join(logDir, file); this.deleteOldLogFile(filePath, oneWeekAgo); }); + }).catch((err) => { + this.logger.error('Failed to read log directory', err); }); } private deleteOldLogFile(filePath: string, oneWeekAgo: number) { - fs.stat(filePath, (err, stats) => { - if (err) { - this.logger.error('Failed to get file stats', err); - return; - } + fs.stat(filePath).then((stats) => { if (stats.mtime.getTime() < oneWeekAgo) { - fs.unlink(filePath, (err) => { + fs.unlink(filePath).catch((err) => { if (err) { if (err.code === 'ENOENT') { this.logger.warn(`File already deleted: ${filePath}`); @@ -128,6 +122,8 @@ export class LogWrapper { } }); } + }).catch((err) => { + this.logger.error('Failed to get file stats', err); }); } @@ -316,9 +312,8 @@ function textElementToText(textElement: any): string { function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: number): string { const recordMsgOrNull = msg.records.find((record) => replyElement.sourceMsgIdInRecords === record.msgId); - return `[回复消息 ${ - recordMsgOrNull && recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020' - ? rawMessageToText(recordMsgOrNull, recursiveLevel + 1) - : `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})` - }]`; + return `[回复消息 ${recordMsgOrNull && recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020' + ? rawMessageToText(recordMsgOrNull, recursiveLevel + 1) + : `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})` + }]`; } diff --git a/src/common/request.ts b/src/common/request.ts index aecc5b1b..11523842 100644 --- a/src/common/request.ts +++ b/src/common/request.ts @@ -1,6 +1,5 @@ import https from 'node:https'; import http from 'node:http'; -import { readFileSync } from 'node:fs'; export class RequestUtil { // 适用于获取服务器下发cookies时获取,仅GET @@ -112,24 +111,4 @@ export class RequestUtil { static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) { return this.HttpGetJson(url, method, data, headers, false, false); } - - static async createFormData(boundary: string, filePath: string): Promise { - let type = 'image/png'; - if (filePath.endsWith('.jpg')) { - type = 'image/jpeg'; - } - const formDataParts = [ - `------${boundary}\r\n`, - `Content-Disposition: form-data; name="share_image"; filename="${filePath}"\r\n`, - 'Content-Type: ' + type + '\r\n\r\n', - ]; - - const fileContent = readFileSync(filePath); - const footer = `\r\n------${boundary}--`; - return Buffer.concat([ - Buffer.from(formDataParts.join(''), 'utf8'), - fileContent, - Buffer.from(footer, 'utf8'), - ]); - } } diff --git a/src/onebot/action/extends/SetQQAvatar.ts b/src/onebot/action/extends/SetQQAvatar.ts index 3f96a91c..f8003fec 100644 --- a/src/onebot/action/extends/SetQQAvatar.ts +++ b/src/onebot/action/extends/SetQQAvatar.ts @@ -1,6 +1,6 @@ import { OneBotAction } from '@/onebot/action/OneBotAction'; import { ActionName } from '@/onebot/action/router'; -import * as fs from 'node:fs'; +import fs from 'node:fs/promises'; import { checkFileExist, uri2local } from '@/common/file'; import { Static, Type } from '@sinclair/typebox'; @@ -21,9 +21,7 @@ export default class SetAvatar extends OneBotAction { if (path) { await checkFileExist(path, 5000);// 避免崩溃 const ret = await this.core.apis.UserApi.setQQAvatar(path); - fs.unlink(path, () => { - }); - + fs.unlink(path).catch(() => { }); if (!ret) { throw new Error(`头像${payload.file}设置失败,api无返回`); } @@ -34,7 +32,7 @@ export default class SetAvatar extends OneBotAction { throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`); } } else { - fs.unlink(path, () => { }); + fs.unlink(path).catch(() => { }); throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`); } return null; diff --git a/src/onebot/action/go-cqhttp/SendGroupNotice.ts b/src/onebot/action/go-cqhttp/SendGroupNotice.ts index b36146a8..998d711f 100644 --- a/src/onebot/action/go-cqhttp/SendGroupNotice.ts +++ b/src/onebot/action/go-cqhttp/SendGroupNotice.ts @@ -1,7 +1,7 @@ import { checkFileExist, uri2local } from '@/common/file'; import { OneBotAction } from '@/onebot/action/OneBotAction'; import { ActionName } from '@/onebot/action/router'; -import { unlink } from 'node:fs'; +import { unlink } from 'node:fs/promises'; import { Static, Type } from '@sinclair/typebox'; const SchemaData = Type.Object({ @@ -41,8 +41,7 @@ export class SendGroupNotice extends OneBotAction { throw new Error(`群公告${payload.image}设置失败,图片上传失败`); } - unlink(path, () => { - }); + unlink(path).catch(() => { }); UploadImage = ImageUploadResult.picInfo; } diff --git a/src/onebot/action/go-cqhttp/SetGroupPortrait.ts b/src/onebot/action/go-cqhttp/SetGroupPortrait.ts index 9845aad7..b9354dd5 100644 --- a/src/onebot/action/go-cqhttp/SetGroupPortrait.ts +++ b/src/onebot/action/go-cqhttp/SetGroupPortrait.ts @@ -1,9 +1,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction'; -import { ActionName, BaseCheckResult } from '@/onebot/action/router'; -import * as fs from 'node:fs'; +import { ActionName } from '@/onebot/action/router'; import { checkFileExistV2, uri2local } from '@/common/file'; import { Static, Type } from '@sinclair/typebox'; - +import fs from 'node:fs/promises'; const SchemaData = Type.Object({ file: Type.String(), group_id: Type.Union([Type.Number(), Type.String()]) @@ -14,7 +13,7 @@ type Payload = Static; export default class SetGroupPortrait extends OneBotAction { actionName = ActionName.SetGroupPortrait; payloadSchema = SchemaData; - + async _handle(payload: Payload): Promise { const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file)); if (!success) { @@ -23,7 +22,7 @@ export default class SetGroupPortrait extends OneBotAction { if (path) { await checkFileExistV2(path, 5000); // 文件不存在QQ会崩溃,需要提前判断 const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path); - fs.unlink(path, () => { }); + fs.unlink(path).catch(() => { }); if (!ret) { throw new Error(`头像${payload.file}设置失败,api无返回`); } @@ -34,7 +33,7 @@ export default class SetGroupPortrait extends OneBotAction { } return ret; } else { - fs.unlink(path, () => { }); + fs.unlink(path).catch(() => { }); throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`); } } diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index cac41fdc..bf8f790c 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -15,7 +15,6 @@ import { RawMessage, SendMessageElement, SendTextElement, - BaseEmojiType, FaceType, GrayTipElement, } from '@/core'; @@ -26,12 +25,9 @@ import { EventType } from '@/onebot/event/OneBotEvent'; import { encodeCQCode } from '@/onebot/helper/cqcode'; import { uri2local } from '@/common/file'; import { RequestUtil } from '@/common/request'; -import fs from 'node:fs'; -import fsPromise from 'node:fs/promises'; +import fsPromise, { constants } from 'node:fs/promises'; import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent'; -// import { decodeSysMessage } from '@/core/packet/proto/old/ProfileLike'; import { ForwardMsgBuilder } from "@/common/forward-msg-builder"; -import { decodeSysMessage } from "@/core/helper/adaptDecoder"; import { GroupChange, PushMsgBody } from "@/core/packet/transformer/proto"; import { NapProtoMsg } from '@napneko/nap-proto-core'; import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent'; @@ -887,16 +883,16 @@ export class OneBotMsgApi { try { for (const fileElement of sendElements) { if (fileElement.elementType === ElementType.PTT) { - totalSize += fs.statSync(fileElement.pttElement.filePath).size; + totalSize += (await fsPromise.stat(fileElement.pttElement.filePath)).size; } if (fileElement.elementType === ElementType.FILE) { - totalSize += fs.statSync(fileElement.fileElement.filePath).size; + totalSize += (await fsPromise.stat(fileElement.fileElement.filePath)).size; } if (fileElement.elementType === ElementType.VIDEO) { - totalSize += fs.statSync(fileElement.videoElement.filePath).size; + totalSize += (await fsPromise.stat(fileElement.videoElement.filePath)).size; } if (fileElement.elementType === ElementType.PIC) { - totalSize += fs.statSync(fileElement.picElement.sourcePath).size; + totalSize += (await fsPromise.stat(fileElement.picElement.sourcePath)).size; } } //且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan @@ -916,9 +912,9 @@ export class OneBotMsgApi { }, returnMsg.msgId); setTimeout(() => { - deleteAfterSentFiles.forEach(file => { + deleteAfterSentFiles.forEach(async file => { try { - if (fs.existsSync(file)) { + if (await fsPromise.access(file, constants.W_OK).then(() => true).catch(() => false)) { fsPromise.unlink(file).then().catch(e => this.core.context.logger.logError('发送消息删除文件失败', e)); } } catch (error) { diff --git a/src/webui/src/api/Log.ts b/src/webui/src/api/Log.ts index 1684183d..5429e0b6 100644 --- a/src/webui/src/api/Log.ts +++ b/src/webui/src/api/Log.ts @@ -9,13 +9,13 @@ export const LogHandler: RequestHandler = async (req, res) => { if (filename.includes('..')) { return sendError(res, 'ID不合法'); } - const logContent = WebUiConfigWrapper.GetLogContent(filename); + const logContent = await WebUiConfigWrapper.GetLogContent(filename); return sendSuccess(res, logContent); }; // 日志列表 export const LogListHandler: RequestHandler = async (_, res) => { - const logList = WebUiConfigWrapper.GetLogsList(); + const logList = await WebUiConfigWrapper.GetLogsList(); return sendSuccess(res, logList); }; // 实时日志(SSE) diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index 9c1d7413..6f74e93e 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -1,5 +1,5 @@ import { webUiPathWrapper } from '@/webui'; -import { existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs'; +import fs, { constants } from 'node:fs/promises'; import * as net from 'node:net'; import { resolve } from 'node:path'; @@ -90,18 +90,18 @@ export class WebUiConfigWrapper { try { const configPath = resolve(webUiPathWrapper.configPath, './webui.json'); - if (!existsSync(configPath)) { - writeFileSync(configPath, JSON.stringify(defaultconfig, null, 4)); + if (!await fs.access(configPath, constants.R_OK | constants.W_OK).then(() => true).catch(() => false)) { + await fs.writeFile(configPath, JSON.stringify(defaultconfig, null, 4)); } - const fileContent = readFileSync(configPath, 'utf-8'); + const fileContent = await fs.readFile(configPath, 'utf-8'); // 更新配置字段后新增字段可能会缺失,同步一下 const parsedConfig = this.applyDefaults(JSON.parse(fileContent) as Partial, defaultconfig); if (!parsedConfig.prefix.startsWith('/')) parsedConfig.prefix = '/' + parsedConfig.prefix; if (parsedConfig.prefix.endsWith('/')) parsedConfig.prefix = parsedConfig.prefix.slice(0, -1); // 配置已经被操作过了,还是回写一下吧,不然新配置不会出现在配置文件里 - writeFileSync(configPath, JSON.stringify(parsedConfig, null, 4)); + await fs.writeFile(configPath, JSON.stringify(parsedConfig, null, 4)); // 不希望回写的配置放后面 // 查询主机地址是否可用 @@ -137,19 +137,19 @@ export class WebUiConfigWrapper { return resolve(webUiPathWrapper.logsPath); } // 获取日志列表 - public static GetLogsList(): string[] { - if (existsSync(webUiPathWrapper.logsPath)) { - return readdirSync(webUiPathWrapper.logsPath) + public static async GetLogsList(): Promise { + if (await fs.access(webUiPathWrapper.logsPath, constants.F_OK).then(() => true).catch(() => false)) { + return (await fs.readdir(webUiPathWrapper.logsPath)) .filter((file) => file.endsWith('.log')) .map((file) => file.replace('.log', '')); } return []; } // 获取指定日志文件内容 - public static GetLogContent(filename: string): string { + public static async GetLogContent(filename: string): Promise { const logPath = resolve(webUiPathWrapper.logsPath, `${filename}.log`); - if (existsSync(logPath)) { - return readFileSync(logPath, 'utf-8'); + if (await fs.access(logPath, constants.R_OK).then(() => true).catch(() => false)) { + return await fs.readFile(logPath, 'utf-8'); } return ''; }