mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f429db61af | ||
![]() |
2881099602 | ||
![]() |
672ae8decf | ||
![]() |
2abc7e541d | ||
![]() |
45b1f369ac | ||
![]() |
3b5d2c8f6f | ||
![]() |
5376e16c9f |
BIN
external/LiteLoaderWrapper.zip
vendored
BIN
external/LiteLoaderWrapper.zip
vendored
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "4.2.9",
|
"version": "4.2.11",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "4.2.9",
|
"version": "4.2.11",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import winston, { format, transports } from 'winston';
|
import winston, { format, transports } from 'winston';
|
||||||
import { truncateString } from '@/common/helper';
|
import { truncateString } from '@/common/helper';
|
||||||
import path from 'node:path';
|
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 { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core';
|
||||||
import EventEmitter from 'node:events';
|
import EventEmitter from 'node:events';
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
@@ -97,26 +97,20 @@ export class LogWrapper {
|
|||||||
|
|
||||||
cleanOldLogs(logDir: string) {
|
cleanOldLogs(logDir: string) {
|
||||||
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
||||||
fs.readdir(logDir, (err, files) => {
|
fs.readdir(logDir).then((files) => {
|
||||||
if (err) {
|
|
||||||
this.logger.error('Failed to read log directory', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
const filePath = path.join(logDir, file);
|
const filePath = path.join(logDir, file);
|
||||||
this.deleteOldLogFile(filePath, oneWeekAgo);
|
this.deleteOldLogFile(filePath, oneWeekAgo);
|
||||||
});
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
this.logger.error('Failed to read log directory', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
|
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
|
||||||
fs.stat(filePath, (err, stats) => {
|
fs.stat(filePath).then((stats) => {
|
||||||
if (err) {
|
|
||||||
this.logger.error('Failed to get file stats', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (stats.mtime.getTime() < oneWeekAgo) {
|
if (stats.mtime.getTime() < oneWeekAgo) {
|
||||||
fs.unlink(filePath, (err) => {
|
fs.unlink(filePath).catch((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.code === 'ENOENT') {
|
if (err.code === 'ENOENT') {
|
||||||
this.logger.warn(`File already deleted: ${filePath}`);
|
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 {
|
function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: number): string {
|
||||||
const recordMsgOrNull = msg.records.find((record) => replyElement.sourceMsgIdInRecords === record.msgId);
|
const recordMsgOrNull = msg.records.find((record) => replyElement.sourceMsgIdInRecords === record.msgId);
|
||||||
return `[回复消息 ${
|
return `[回复消息 ${recordMsgOrNull && recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
||||||
recordMsgOrNull && recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
? rawMessageToText(recordMsgOrNull, recursiveLevel + 1)
|
||||||
? rawMessageToText(recordMsgOrNull, recursiveLevel + 1)
|
: `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
|
||||||
: `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
|
}]`;
|
||||||
}]`;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import https from 'node:https';
|
import https from 'node:https';
|
||||||
import http from 'node:http';
|
import http from 'node:http';
|
||||||
import { readFileSync } from 'node:fs';
|
|
||||||
|
|
||||||
export class RequestUtil {
|
export class RequestUtil {
|
||||||
// 适用于获取服务器下发cookies时获取,仅GET
|
// 适用于获取服务器下发cookies时获取,仅GET
|
||||||
@@ -112,24 +111,4 @@ export class RequestUtil {
|
|||||||
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
||||||
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async createFormData(boundary: string, filePath: string): Promise<Buffer> {
|
|
||||||
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'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '4.2.9';
|
export const napCatVersion = '4.2.11';
|
||||||
|
@@ -181,13 +181,13 @@ export class NTQQUserApi {
|
|||||||
//后期改成流水线处理
|
//后期改成流水线处理
|
||||||
async getUinByUidV2(Uid: string) {
|
async getUinByUidV2(Uid: string) {
|
||||||
let uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
|
let uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
|
||||||
if (uin) return uin;
|
if (uin && uin !== '0') return uin;
|
||||||
uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
|
uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
|
||||||
if (uin) return uin;
|
if (uin && uin !== '0') return uin;
|
||||||
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
|
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
|
||||||
if (uin) return uin;
|
if (uin && uin !== '0') return uin;
|
||||||
uin = (await this.core.apis.FriendApi.getBuddyIdMap(true)).getKey(Uid);
|
uin = (await this.core.apis.FriendApi.getBuddyIdMap(true)).getKey(Uid);
|
||||||
if (uin) return uin;
|
if (uin && uin !== '0') return uin;
|
||||||
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
|
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
|
||||||
return uin;
|
return uin;
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,6 @@ export class GetCollectionList extends OneBotAction<Payload, any> {
|
|||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
return await this.core.apis.CollectionApi.getAllCollection(parseInt(payload.category.toString()), +payload.count);
|
return await this.core.apis.CollectionApi.getAllCollection(+payload.category, +payload.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
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 { checkFileExist, uri2local } from '@/common/file';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
@@ -21,9 +21,7 @@ export default class SetAvatar extends OneBotAction<Payload, null> {
|
|||||||
if (path) {
|
if (path) {
|
||||||
await checkFileExist(path, 5000);// 避免崩溃
|
await checkFileExist(path, 5000);// 避免崩溃
|
||||||
const ret = await this.core.apis.UserApi.setQQAvatar(path);
|
const ret = await this.core.apis.UserApi.setQQAvatar(path);
|
||||||
fs.unlink(path, () => {
|
fs.unlink(path).catch(() => { });
|
||||||
});
|
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||||
}
|
}
|
||||||
@@ -34,7 +32,7 @@ export default class SetAvatar extends OneBotAction<Payload, null> {
|
|||||||
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path).catch(() => { });
|
||||||
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { checkFileExist, uri2local } from '@/common/file';
|
import { checkFileExist, uri2local } from '@/common/file';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { unlink } from 'node:fs';
|
import { unlink } from 'node:fs/promises';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = Type.Object({
|
const SchemaData = Type.Object({
|
||||||
@@ -41,8 +41,7 @@ export class SendGroupNotice extends OneBotAction<Payload, null> {
|
|||||||
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
|
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(path, () => {
|
unlink(path).catch(() => { });
|
||||||
});
|
|
||||||
|
|
||||||
UploadImage = ImageUploadResult.picInfo;
|
UploadImage = ImageUploadResult.picInfo;
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import * as fs from 'node:fs';
|
|
||||||
import { checkFileExistV2, uri2local } from '@/common/file';
|
import { checkFileExistV2, uri2local } from '@/common/file';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
const SchemaData = Type.Object({
|
const SchemaData = Type.Object({
|
||||||
file: Type.String(),
|
file: Type.String(),
|
||||||
group_id: Type.Union([Type.Number(), Type.String()])
|
group_id: Type.Union([Type.Number(), Type.String()])
|
||||||
@@ -14,7 +13,7 @@ type Payload = Static<typeof SchemaData>;
|
|||||||
export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SetGroupPortrait;
|
actionName = ActionName.SetGroupPortrait;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<any> {
|
async _handle(payload: Payload): Promise<any> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -23,7 +22,7 @@ export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
|||||||
if (path) {
|
if (path) {
|
||||||
await checkFileExistV2(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileExistV2(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path).catch(() => { });
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||||
}
|
}
|
||||||
@@ -34,7 +33,7 @@ export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path).catch(() => { });
|
||||||
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ export default class SetGroupBan extends OneBotAction<Payload, null> {
|
|||||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
if (!uid) throw new Error('uid error');
|
if (!uid) throw new Error('uid error');
|
||||||
await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
|
await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
|
||||||
[{ uid: uid, timeStamp: parseInt(payload.duration.toString()) }]);
|
[{ uid: uid, timeStamp: +payload.duration}]);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ class ForwardSingleMsg extends OneBotAction<Payload, null> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
throw new Error(`无法找到消息${payload.message_id}`);
|
throw new Error(`无法找到消息${payload.message_id}`);
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@ export class SetMsgEmojiLike extends OneBotAction<Payload, any> {
|
|||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
throw new Error('msg not found');
|
throw new Error('msg not found');
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,6 @@ import {
|
|||||||
RawMessage,
|
RawMessage,
|
||||||
SendMessageElement,
|
SendMessageElement,
|
||||||
SendTextElement,
|
SendTextElement,
|
||||||
BaseEmojiType,
|
|
||||||
FaceType,
|
FaceType,
|
||||||
GrayTipElement,
|
GrayTipElement,
|
||||||
} from '@/core';
|
} from '@/core';
|
||||||
@@ -26,12 +25,9 @@ import { EventType } from '@/onebot/event/OneBotEvent';
|
|||||||
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
||||||
import { uri2local } from '@/common/file';
|
import { uri2local } from '@/common/file';
|
||||||
import { RequestUtil } from '@/common/request';
|
import { RequestUtil } from '@/common/request';
|
||||||
import fs from 'node:fs';
|
import fsPromise, { constants } from 'node:fs/promises';
|
||||||
import fsPromise from 'node:fs/promises';
|
|
||||||
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
|
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
|
||||||
// import { decodeSysMessage } from '@/core/packet/proto/old/ProfileLike';
|
|
||||||
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
|
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
|
||||||
import { decodeSysMessage } from "@/core/helper/adaptDecoder";
|
|
||||||
import { GroupChange, PushMsgBody } from "@/core/packet/transformer/proto";
|
import { GroupChange, PushMsgBody } from "@/core/packet/transformer/proto";
|
||||||
import { NapProtoMsg } from '@napneko/nap-proto-core';
|
import { NapProtoMsg } from '@napneko/nap-proto-core';
|
||||||
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
|
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
|
||||||
@@ -452,7 +448,7 @@ export class OneBotMsgApi {
|
|||||||
},
|
},
|
||||||
|
|
||||||
[OB11MessageDataType.face]: async ({ data: { id } }) => {
|
[OB11MessageDataType.face]: async ({ data: { id } }) => {
|
||||||
let parsedFaceId = parseInt(id);
|
let parsedFaceId = +id;
|
||||||
// 从face_config.json中获取表情名称
|
// 从face_config.json中获取表情名称
|
||||||
const sysFaces = faceConfig.sysface;
|
const sysFaces = faceConfig.sysface;
|
||||||
const face: any = sysFaces.find((systemFace) => systemFace.QSid === parsedFaceId.toString());
|
const face: any = sysFaces.find((systemFace) => systemFace.QSid === parsedFaceId.toString());
|
||||||
@@ -460,7 +456,6 @@ export class OneBotMsgApi {
|
|||||||
this.core.context.logger.logError('不支持的ID', id);
|
this.core.context.logger.logError('不支持的ID', id);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
parsedFaceId = parseInt(parsedFaceId.toString());
|
|
||||||
let faceType = 1;
|
let faceType = 1;
|
||||||
if (parsedFaceId >= 222) {
|
if (parsedFaceId >= 222) {
|
||||||
faceType = 2;
|
faceType = 2;
|
||||||
@@ -888,16 +883,16 @@ export class OneBotMsgApi {
|
|||||||
try {
|
try {
|
||||||
for (const fileElement of sendElements) {
|
for (const fileElement of sendElements) {
|
||||||
if (fileElement.elementType === ElementType.PTT) {
|
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) {
|
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) {
|
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) {
|
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
|
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan
|
||||||
@@ -917,9 +912,9 @@ export class OneBotMsgApi {
|
|||||||
}, returnMsg.msgId);
|
}, returnMsg.msgId);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
deleteAfterSentFiles.forEach(file => {
|
deleteAfterSentFiles.forEach(async file => {
|
||||||
try {
|
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));
|
fsPromise.unlink(file).then().catch(e => this.core.context.logger.logError('发送消息删除文件失败', e));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -958,14 +953,14 @@ export class OneBotMsgApi {
|
|||||||
}
|
}
|
||||||
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 130:
|
case 130:
|
||||||
return 'leave';
|
return 'leave';
|
||||||
case 131:
|
case 131:
|
||||||
return 'kick';
|
return 'kick';
|
||||||
case 3:
|
case 3:
|
||||||
return 'kick_me';
|
return 'kick_me';
|
||||||
default:
|
default:
|
||||||
return 'kick';
|
return 'kick';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,13 +9,13 @@ export const LogHandler: RequestHandler = async (req, res) => {
|
|||||||
if (filename.includes('..')) {
|
if (filename.includes('..')) {
|
||||||
return sendError(res, 'ID不合法');
|
return sendError(res, 'ID不合法');
|
||||||
}
|
}
|
||||||
const logContent = WebUiConfigWrapper.GetLogContent(filename);
|
const logContent = await WebUiConfigWrapper.GetLogContent(filename);
|
||||||
return sendSuccess(res, logContent);
|
return sendSuccess(res, logContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 日志列表
|
// 日志列表
|
||||||
export const LogListHandler: RequestHandler = async (_, res) => {
|
export const LogListHandler: RequestHandler = async (_, res) => {
|
||||||
const logList = WebUiConfigWrapper.GetLogsList();
|
const logList = await WebUiConfigWrapper.GetLogsList();
|
||||||
return sendSuccess(res, logList);
|
return sendSuccess(res, logList);
|
||||||
};
|
};
|
||||||
// 实时日志(SSE)
|
// 实时日志(SSE)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { webUiPathWrapper } from '@/webui';
|
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 * as net from 'node:net';
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
@@ -90,18 +90,18 @@ export class WebUiConfigWrapper {
|
|||||||
try {
|
try {
|
||||||
const configPath = resolve(webUiPathWrapper.configPath, './webui.json');
|
const configPath = resolve(webUiPathWrapper.configPath, './webui.json');
|
||||||
|
|
||||||
if (!existsSync(configPath)) {
|
if (!await fs.access(configPath, constants.R_OK | constants.W_OK).then(() => true).catch(() => false)) {
|
||||||
writeFileSync(configPath, JSON.stringify(defaultconfig, null, 4));
|
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<WebUiConfigType>, defaultconfig);
|
const parsedConfig = this.applyDefaults(JSON.parse(fileContent) as Partial<WebUiConfigType>, defaultconfig);
|
||||||
|
|
||||||
if (!parsedConfig.prefix.startsWith('/')) parsedConfig.prefix = '/' + parsedConfig.prefix;
|
if (!parsedConfig.prefix.startsWith('/')) parsedConfig.prefix = '/' + parsedConfig.prefix;
|
||||||
if (parsedConfig.prefix.endsWith('/')) parsedConfig.prefix = parsedConfig.prefix.slice(0, -1);
|
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);
|
return resolve(webUiPathWrapper.logsPath);
|
||||||
}
|
}
|
||||||
// 获取日志列表
|
// 获取日志列表
|
||||||
public static GetLogsList(): string[] {
|
public static async GetLogsList(): Promise<string[]> {
|
||||||
if (existsSync(webUiPathWrapper.logsPath)) {
|
if (await fs.access(webUiPathWrapper.logsPath, constants.F_OK).then(() => true).catch(() => false)) {
|
||||||
return readdirSync(webUiPathWrapper.logsPath)
|
return (await fs.readdir(webUiPathWrapper.logsPath))
|
||||||
.filter((file) => file.endsWith('.log'))
|
.filter((file) => file.endsWith('.log'))
|
||||||
.map((file) => file.replace('.log', ''));
|
.map((file) => file.replace('.log', ''));
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
// 获取指定日志文件内容
|
// 获取指定日志文件内容
|
||||||
public static GetLogContent(filename: string): string {
|
public static async GetLogContent(filename: string): Promise<string> {
|
||||||
const logPath = resolve(webUiPathWrapper.logsPath, `${filename}.log`);
|
const logPath = resolve(webUiPathWrapper.logsPath, `${filename}.log`);
|
||||||
if (existsSync(logPath)) {
|
if (await fs.access(logPath, constants.R_OK).then(() => true).catch(() => false)) {
|
||||||
return readFileSync(logPath, 'utf-8');
|
return await fs.readFile(logPath, 'utf-8');
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user