diff --git a/src/common/file-uuid.ts b/src/common/file-uuid.ts new file mode 100644 index 000000000..717cae719 --- /dev/null +++ b/src/common/file-uuid.ts @@ -0,0 +1,56 @@ +import { Peer } from '@/core'; +import { LRUCache } from './lru-cache'; +import { randomUUID } from 'crypto'; + +interface FileUUIDData { + peer: Peer; + modelId?: string; + fileId?: string; + msgId?: string; + elementId?: string; + fileUUID?: string; +} + +class FileUUIDManager { + private cache: LRUCache; + + constructor(capacity: number) { + this.cache = new LRUCache(capacity); + } + + public encode(data: FileUUIDData, endString: string = "", customUUID?: string): string { + const uuid = customUUID ? customUUID : randomUUID().replace(/-/g, '') + endString; + this.cache.put(uuid, data); + return uuid; + } + + public decode(uuid: string): FileUUIDData | undefined { + return this.cache.get(uuid); + } +} + +export class FileNapCatOneBotUUIDWrap { + private manager: FileUUIDManager; + + constructor(capacity: number = 100) { + this.manager = new FileUUIDManager(capacity); + } + + public encodeModelId(peer: Peer, modelId: string, fileId: string, fileUUID: string = "", endString: string = "", customUUID?: string): string { + return this.manager.encode({ peer, modelId, fileId, fileUUID }, endString, customUUID); + } + + public decodeModelId(uuid: string): FileUUIDData | undefined { + return this.manager.decode(uuid); + } + + public encode(peer: Peer, msgId: string, elementId: string, fileUUID: string = "", customUUID?: string): string { + return this.manager.encode({ peer, msgId, elementId, fileUUID }, "", customUUID); + } + + public decode(uuid: string): FileUUIDData | undefined { + return this.manager.decode(uuid); + } +} + +export const FileNapCatOneBotUUID = new FileNapCatOneBotUUIDWrap(); \ No newline at end of file diff --git a/src/common/helper.ts b/src/common/helper.ts index b39aa3958..f426cf6c5 100644 --- a/src/common/helper.ts +++ b/src/common/helper.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import fs from 'fs'; import os from 'node:os'; -import { Peer, QQLevel } from '@/core'; +import { QQLevel } from '@/core'; export async function solveProblem any>(func: T, ...args: Parameters): Promise | undefined> { return new Promise | undefined>((resolve) => { @@ -24,81 +24,6 @@ export async function solveAsyncProblem Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } diff --git a/src/core/external/appid.json b/src/core/external/appid.json index a8556c7c7..9e649d9d6 100644 --- a/src/core/external/appid.json +++ b/src/core/external/appid.json @@ -174,5 +174,9 @@ "6.9.63-31245": { "appid": 537266474, "qua": "V1_MAC_NQ_6.9.63_31245_GW_B" + }, + "9.9.17-31363": { + "appid": 537266500, + "qua": "V1_WIN_NQ_9.9.17_31363_GW_B" } -} +} \ No newline at end of file diff --git a/src/core/external/offset.json b/src/core/external/offset.json index 56b6a4bda..76ef2fad7 100644 --- a/src/core/external/offset.json +++ b/src/core/external/offset.json @@ -226,5 +226,9 @@ "3.2.15-31245-arm64": { "send": "71BEBB8", "recv": "71C23F0" + }, + "9.9.17-31363-x64": { + "send": "39C1910", + "recv": "39C5d44" } -} +} \ No newline at end of file diff --git a/src/onebot/action/file/GetFile.ts b/src/onebot/action/file/GetFile.ts index 040836052..e971f3e0d 100644 --- a/src/onebot/action/file/GetFile.ts +++ b/src/onebot/action/file/GetFile.ts @@ -1,6 +1,6 @@ import { OneBotAction } from '@/onebot/action/OneBotAction'; import fs from 'fs/promises'; -import { FileNapCatOneBotUUID } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/file-uuid'; import { ActionName } from '@/onebot/action/router'; import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types'; import { Static, Type } from '@sinclair/typebox'; @@ -28,7 +28,7 @@ export class GetFileBase extends OneBotAction { payload.file ||= payload.file_id || ''; //接收消息标记模式 const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file); - if (contextMsgFile) { + if (contextMsgFile && contextMsgFile.msgId && contextMsgFile.elementId) { const { peer, msgId, elementId } = contextMsgFile; const downloadPath = await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', ''); const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList @@ -68,7 +68,7 @@ export class GetFileBase extends OneBotAction { //群文件模式 const contextModelIdFile = FileNapCatOneBotUUID.decodeModelId(payload.file); - if (contextModelIdFile) { + if (contextModelIdFile && contextModelIdFile.modelId) { const { peer, modelId } = contextModelIdFile; const downloadPath = await this.core.apis.FileApi.downloadFileForModelId(peer, modelId, ''); const res: GetFileResponse = { diff --git a/src/onebot/action/file/GetGroupFileUrl.ts b/src/onebot/action/file/GetGroupFileUrl.ts index ae3f5687e..d12095885 100644 --- a/src/onebot/action/file/GetGroupFileUrl.ts +++ b/src/onebot/action/file/GetGroupFileUrl.ts @@ -1,5 +1,5 @@ import { ActionName } from '@/onebot/action/router'; -import { FileNapCatOneBotUUID } from "@/common/helper"; +import { FileNapCatOneBotUUID } from '@/common/file-uuid'; import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus"; import { Static, Type } from '@sinclair/typebox'; diff --git a/src/onebot/action/go-cqhttp/DeleteGroupFile.ts b/src/onebot/action/go-cqhttp/DeleteGroupFile.ts index 85b43ccee..c0b9a6007 100644 --- a/src/onebot/action/go-cqhttp/DeleteGroupFile.ts +++ b/src/onebot/action/go-cqhttp/DeleteGroupFile.ts @@ -1,7 +1,7 @@ import { OneBotAction } from '@/onebot/action/OneBotAction'; import { ActionName } from '@/onebot/action/router'; -import { FileNapCatOneBotUUID } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/file-uuid'; import { Static, Type } from '@sinclair/typebox'; const SchemaData = Type.Object({ @@ -16,7 +16,7 @@ export class DeleteGroupFile extends OneBotAction { payloadSchema = SchemaData; async _handle(payload: Payload) { const data = FileNapCatOneBotUUID.decodeModelId(payload.file_id); - if (!data) throw new Error('Invalid file_id'); + if (!data || !data.fileId) throw new Error('Invalid file_id'); return await this.core.apis.GroupApi.delGroupFile(payload.group_id.toString(), [data.fileId]); } } diff --git a/src/onebot/api/group.ts b/src/onebot/api/group.ts index af57ed7d7..5a57f68e7 100644 --- a/src/onebot/api/group.ts +++ b/src/onebot/api/group.ts @@ -23,7 +23,7 @@ import { OB11GroupTitleEvent } from '@/onebot/event/notice/OB11GroupTitleEvent'; import { OB11GroupUploadNoticeEvent } from '../event/notice/OB11GroupUploadNoticeEvent'; import { OB11GroupNameEvent } from '../event/notice/OB11GroupNameEvent'; import { pathToFileURL } from 'node:url'; -import { FileNapCatOneBotUUID } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/file-uuid'; import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent'; export class OneBotGroupApi { @@ -199,7 +199,7 @@ export class OneBotGroupApi { id: FileNapCatOneBotUUID.encode({ chatType: ChatType.KCHATTYPEGROUP, peerUid: msg.peerUid, - }, msg.msgId, elementWrapper.elementId, elementWrapper?.fileElement?.fileUuid, "." + element.fileName), + }, msg.msgId, elementWrapper.elementId, elementWrapper?.fileElement?.fileUuid, element.fileName), url: pathToFileURL(element.filePath).href, name: element.fileName, size: parseInt(element.fileSize), diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index 6f0fa300e..18df4d558 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -1,4 +1,4 @@ -import { FileNapCatOneBotUUID } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/file-uuid'; import { MessageUnique } from '@/common/message-unique'; import { pathToFileURL } from 'node:url'; import { @@ -116,18 +116,22 @@ export class OneBotMsgApi { peerUid: msg.peerUid, guildId: '', }; - const encodedFileId = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, "." + element.fileName); + FileNapCatOneBotUUID.encode( + peer, + msg.msgId, + elementWrapper.elementId, + element.fileUuid, + element.fileName + ); return { type: OB11MessageDataType.image, data: { summary: element.summary, - file: encodedFileId, + file: element.fileName, sub_type: element.picSubType, - file_id: encodedFileId, url: await this.core.apis.FileApi.getImageUrl(element), path: element.filePath, file_size: element.fileSize, - file_unique: element.md5HexStr ?? element.fileName, }, }; } catch (e: any) { @@ -142,15 +146,15 @@ export class OneBotMsgApi { peerUid: msg.peerUid, guildId: '', }; + const file = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, element.fileName); return { type: OB11MessageDataType.file, data: { - file: element.fileName, + file: file, path: element.filePath, url: pathToFileURL(element.filePath).href, - file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, "." + element.fileName), + file_id: file, file_size: element.fileSize, - file_unique: element.fileMd5 ?? element.fileSha ?? element.fileName, }, }; }, @@ -201,18 +205,18 @@ export class OneBotMsgApi { const { emojiId } = _; const dir = emojiId.substring(0, 2); const url = `https://gxh.vip.qq.com/club/item/parcel/item/${dir}/${emojiId}/raw300.gif`; + const filename = `${dir}-${emojiId}.gif`; + FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, "", filename) return { type: OB11MessageDataType.image, data: { summary: _.faceName, // 商城表情名称 - file: 'marketface', - file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, "", "." + _.key + ".jpg"), + file: filename, path: url, url: url, key: _.key, emoji_id: _.emojiId, emoji_package_id: _.emojiPackageId, - file_unique: _.key }, }; }, @@ -327,16 +331,14 @@ export class OneBotMsgApi { if (!videoDownUrl) { videoDownUrl = element.filePath; } - const fileCode = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, "", "." + element.fileName); + const fileCode = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, element.fileName); return { type: OB11MessageDataType.video, data: { file: fileCode, path: videoDownUrl, url: videoDownUrl ?? pathToFileURL(element.filePath).href, - file_id: fileCode, file_size: element.fileSize, - file_unique: element.videoMd5 ?? element.thumbMd5 ?? element.fileName, }, }; }, @@ -347,16 +349,14 @@ export class OneBotMsgApi { peerUid: msg.peerUid, guildId: '', }; - const fileCode = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, "", "." + element.fileName); + const fileCode = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, "", element.fileName); return { type: OB11MessageDataType.voice, data: { file: fileCode, path: element.filePath, url: pathToFileURL(element.filePath).href, - file_id: fileCode, file_size: element.fileSize, - file_unique: element.fileUuid }, }; }, diff --git a/src/onebot/helper/data.ts b/src/onebot/helper/data.ts index 29409c4d3..867149ec9 100644 --- a/src/onebot/helper/data.ts +++ b/src/onebot/helper/data.ts @@ -1,4 +1,5 @@ -import { calcQQLevel, FileNapCatOneBotUUID } from '@/common/helper'; +import { calcQQLevel } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/file-uuid'; import { FriendV2, Group, GroupFileInfoUpdateParamType, GroupMember, SelfInfo, NTSex } from '@/core'; import { OB11Group, diff --git a/src/onebot/index.ts b/src/onebot/index.ts index 0eaa74eae..f569de3a2 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -180,8 +180,11 @@ export class NapCatOneBot11Adapter { WebUiDataRuntime.setQQLoginStatus(true); WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => { const prev = this.configLoader.configData; + // 保证默认配置 + newConfig = mergeOneBotConfigs(newConfig); + this.configLoader.save(newConfig); - this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); + //this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); await this.reloadNetwork(prev, newConfig); }); } diff --git a/src/onebot/types/message.ts b/src/onebot/types/message.ts index 645f0b5f3..ada739b7d 100644 --- a/src/onebot/types/message.ts +++ b/src/onebot/types/message.ts @@ -110,7 +110,6 @@ export interface OB11MessageContext { // 文件消息基础接口定义 export interface OB11MessageFileBase { data: { - file_unique?: string; path?: string; thumb?: string; name?: string;