From 6aa44bdd79db42dca88278436ffa673e2974555c Mon Sep 17 00:00:00 2001 From: idranme Date: Wed, 14 Aug 2024 18:20:39 +0800 Subject: [PATCH 1/2] fix: `/get_image` --- src/common/types.ts | 9 ++-- src/common/utils/EventTask.ts | 20 ++++---- src/common/utils/MessageUnique.ts | 21 ++++++++ src/ntqqapi/api/file.ts | 1 - src/onebot11/action/file/GetFile.ts | 64 ++++++++++++++---------- src/onebot11/action/file/GetImage.ts | 7 +++ src/onebot11/constructor.ts | 75 ++++++++++++++-------------- 7 files changed, 116 insertions(+), 81 deletions(-) diff --git a/src/common/types.ts b/src/common/types.ts index b4d722d..d4c6986 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -41,11 +41,10 @@ export interface LLOneBotError { export interface FileCache { fileName: string - filePath: string fileSize: string - fileUuid?: string - url?: string - msgId?: string + msgId: string + peerUid: string + chatType: number elementId: string - downloadFunc?: () => Promise + elementType: number } diff --git a/src/common/utils/EventTask.ts b/src/common/utils/EventTask.ts index 1099752..bc32199 100644 --- a/src/common/utils/EventTask.ts +++ b/src/common/utils/EventTask.ts @@ -34,7 +34,7 @@ export class NTEventWrapper { if (typeof target[prop] === 'undefined') { // 如果方法不存在,返回一个函数,这个函数调用existentMethod return (...args: any[]) => { - current.DispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then() + current.dispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then() } } // 如果方法存在,正常返回 @@ -48,7 +48,7 @@ export class NTEventWrapper { this.WrapperSession = WrapperSession } - CreatEventFunction any>(eventName: string): T | undefined { + createEventFunction any>(eventName: string): T | undefined { const eventNameArr = eventName.split('/') type eventType = { [key: string]: () => { [key: string]: (...params: Parameters) => Promise> } @@ -69,16 +69,14 @@ export class NTEventWrapper { } } - createEventFunction = this.CreatEventFunction - - CreatListenerFunction(listenerMainName: string, uniqueCode: string = ''): T { + createListenerFunction(listenerMainName: string, uniqueCode: string = ''): T { const ListenerType = this.ListenerMap![listenerMainName] let Listener = this.ListenerManger.get(listenerMainName + uniqueCode) if (!Listener && ListenerType) { Listener = new ListenerType(this.createProxyDispatch(listenerMainName)) const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1] const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener' - const addfunc = this.CreatEventFunction<(listener: T) => number>(Service) + const addfunc = this.createEventFunction<(listener: T) => number>(Service) addfunc!(Listener as T) //console.log(addfunc!(Listener as T)) this.ListenerManger.set(listenerMainName + uniqueCode, Listener) @@ -87,7 +85,7 @@ export class NTEventWrapper { } //统一回调清理事件 - async DispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) { + async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) { //console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args) this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.forEach((task, uuid) => { //console.log(task.func, uuid, task.createtime, task.timeout) @@ -103,7 +101,7 @@ export class NTEventWrapper { async CallNoListenerEvent Promise | any>(EventName = '', timeout: number = 3000, ...args: Parameters) { return new Promise>>(async (resolve, reject) => { - const EventFunc = this.CreatEventFunction(EventName) + const EventFunc = this.createEventFunction(EventName) let complete = false const Timeouter = setTimeout(() => { if (!complete) { @@ -152,7 +150,7 @@ export class NTEventWrapper { this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map()) } this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak) - this.CreatListenerFunction(ListenerMainName) + this.createListenerFunction(ListenerMainName) }) } @@ -198,8 +196,8 @@ export class NTEventWrapper { this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map()) } this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak) - this.CreatListenerFunction(ListenerMainName) - const EventFunc = this.CreatEventFunction(EventName) + this.createListenerFunction(ListenerMainName) + const EventFunc = this.createEventFunction(EventName) retEvent = await EventFunc!(...(args as any[])) }) } diff --git a/src/common/utils/MessageUnique.ts b/src/common/utils/MessageUnique.ts index f300f14..9fd3873 100644 --- a/src/common/utils/MessageUnique.ts +++ b/src/common/utils/MessageUnique.ts @@ -7,6 +7,7 @@ import SQLite from '@minatojs/driver-sqlite' import fsPromise from 'node:fs/promises' import fs from 'node:fs' import path from 'node:path' +import { FileCache } from '../types' interface SQLiteTables extends Tables { message: { @@ -15,6 +16,7 @@ interface SQLiteTables extends Tables { chatType: number peerUid: string } + file: FileCache } interface MsgIdAndPeerByShortId { @@ -50,6 +52,17 @@ class MessageUniqueWrapper { }, { primary: 'shortId' }) + database.extend('file', { + fileName: 'string', + fileSize: 'string', + msgId: 'string(24)', + peerUid: 'string(24)', + chatType: 'unsigned', + elementId: 'string(24)', + elementType: 'unsigned', + }, { + primary: 'fileName' + }) this.db = database } @@ -128,6 +141,14 @@ class MessageUniqueWrapper { this.msgIdMap.resize(maxSize) this.msgDataMap.resize(maxSize) } + + addFileCache(data: FileCache) { + return this.db?.upsert('file', [data], 'fileName') + } + + getFileCache(fileName: string) { + return this.db?.get('file', { fileName }) + } } export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper() \ No newline at end of file diff --git a/src/ntqqapi/api/file.ts b/src/ntqqapi/api/file.ts index 80bf555..e4d51c6 100644 --- a/src/ntqqapi/api/file.ts +++ b/src/ntqqapi/api/file.ts @@ -179,7 +179,6 @@ export class NTQQFileApi { const url: string = element.originImageUrl! // 没有域名 const md5HexStr = element.md5HexStr const fileMd5 = element.md5HexStr - const fileUuid = element.fileUuid if (url) { const UrlParse = new URL(IMAGE_HTTP_HOST + url) //临时解析拼接 diff --git a/src/onebot11/action/file/GetFile.ts b/src/onebot11/action/file/GetFile.ts index d741bfc..7e53e4f 100644 --- a/src/onebot11/action/file/GetFile.ts +++ b/src/onebot11/action/file/GetFile.ts @@ -3,9 +3,10 @@ import fsPromise from 'node:fs/promises' import { getConfigUtil } from '@/common/config' import { NTQQFileApi, NTQQGroupApi, NTQQUserApi, NTQQFriendApi, NTQQMsgApi } from '@/ntqqapi/api' import { ActionName } from '../types' -import { RawMessage } from '@/ntqqapi/types' +import { PicElement } from '@/ntqqapi/types' import { UUIDConverter } from '@/common/utils/helper' import { Peer, ChatType, ElementType } from '@/ntqqapi/types' +import { MessageUnique } from '@/common/utils/MessageUnique' export interface GetFilePayload { file: string // 文件名或者fileUuid @@ -51,10 +52,10 @@ export abstract class GetFileBase extends BaseAction e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT) if (!findEle) { throw new Error('element not found') @@ -68,7 +69,7 @@ export abstract class GetFileBase extends BaseAction e.elementType == NTSearchNameResult[0].elemType) - if (file.length == 0) { - throw new Error('file not found') - } - const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file[0].elementId, '', '') + const fileCache = await MessageUnique.getFileCache(String(payload.file)) + if (fileCache?.length) { + const downloadPath = await NTQQFileApi.downloadMedia( + fileCache[0].msgId, + fileCache[0].chatType, + fileCache[0].peerUid, + fileCache[0].elementId, + '', + '' + ) const res: GetFileResponse = { file: downloadPath, url: downloadPath, - file_size: NTSearchNameResult[0].fileSize.toString(), - file_name: NTSearchNameResult[0].fileName, + file_size: fileCache[0].fileSize, + file_name: fileCache[0].fileName, } - if (enableLocalFile2Url) { + const peer: Peer = { + chatType: fileCache[0].chatType, + peerUid: fileCache[0].peerUid, + guildId: '' + } + if (fileCache[0].elementType === ElementType.PIC) { + const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [fileCache[0].msgId]) + if (msgList.msgList.length === 0) { + throw new Error('msg not found') + } + const msg = msgList.msgList[0] + const findEle = msg.elements.find(e => e.elementId === fileCache[0].elementId) + if (!findEle) { + throw new Error('element not found') + } + res.url = await NTQQFileApi.getImageUrl(findEle.picElement) + } else if (fileCache[0].elementType === ElementType.VIDEO) { + res.url = await NTQQFileApi.getVideoUrl(peer, fileCache[0].msgId, fileCache[0].elementId) + } + if (enableLocalFile2Url && downloadPath && res.file === res.url) { try { res.base64 = await fsPromise.readFile(downloadPath, 'base64') } catch (e) { diff --git a/src/onebot11/action/file/GetImage.ts b/src/onebot11/action/file/GetImage.ts index d51ba67..56f0288 100644 --- a/src/onebot11/action/file/GetImage.ts +++ b/src/onebot11/action/file/GetImage.ts @@ -3,4 +3,11 @@ import { ActionName } from '../types' export default class GetImage extends GetFileBase { actionName = ActionName.GetImage + + protected async _handle(payload: { file: string }) { + if (!payload.file) { + throw new Error('参数 file 不能为空') + } + return super._handle(payload) + } } diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts index a9440b8..2bc85a8 100644 --- a/src/onebot11/constructor.ts +++ b/src/onebot11/constructor.ts @@ -184,21 +184,30 @@ export class OB11Constructor { } else if (element.picElement) { message_data['type'] = OB11MessageDataType.image - let fileName = element.picElement.fileName - const isGif = element.picElement.picType === PicType.gif + const { picElement } = element + /*let fileName = picElement.fileName + const isGif = picElement.picType === PicType.gif if (isGif && !fileName.endsWith('.gif')) { fileName += '.gif' - } - message_data['data']['file'] = fileName - message_data['data']['subType'] = element.picElement.picSubType + }*/ + message_data['data']['file'] = picElement.fileName + message_data['data']['subType'] = picElement.picSubType message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId) - message_data['data']['url'] = await NTQQFileApi.getImageUrl(element.picElement) - message_data['data']['file_size'] = element.picElement.fileSize + message_data['data']['url'] = await NTQQFileApi.getImageUrl(picElement) + message_data['data']['file_size'] = picElement.fileSize + MessageUnique.addFileCache({ + peerUid: msg.peerUid, + msgId: msg.msgId, + chatType: msg.chatType, + elementId: element.elementId, + elementType: element.elementType, + fileName: picElement.fileName, + fileSize: String(picElement.fileSize || '0'), + }) } else if (element.videoElement || element.fileElement) { const videoOrFileElement = element.videoElement || element.fileElement - const ob11MessageDataType = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file - message_data['type'] = ob11MessageDataType + message_data['type'] = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file message_data['data']['file'] = videoOrFileElement.fileName message_data['data']['path'] = videoOrFileElement.filePath message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId) @@ -210,40 +219,32 @@ export class OB11Constructor { }, msg.msgId, element.elementId, ) } - NTQQFileApi.addFileCache( - { - peerUid: msg.peerUid, - chatType: msg.chatType, - guildId: '', - }, - msg.msgId, - msg.msgSeq, - msg.senderUid, - element.elementId, - element.elementType.toString(), - videoOrFileElement.fileSize || '0', - videoOrFileElement.fileName, - ) + MessageUnique.addFileCache({ + peerUid: msg.peerUid, + msgId: msg.msgId, + chatType: msg.chatType, + elementId: element.elementId, + elementType: element.elementType, + fileName: videoOrFileElement.fileName, + fileSize: String(videoOrFileElement.fileSize || '0') + }) } else if (element.pttElement) { message_data['type'] = OB11MessageDataType.voice - message_data['data']['file'] = element.pttElement.fileName - message_data['data']['path'] = element.pttElement.filePath + const { pttElement } = element + message_data['data']['file'] = pttElement.fileName + message_data['data']['path'] = pttElement.filePath message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId) - message_data['data']['file_size'] = element.pttElement.fileSize - NTQQFileApi.addFileCache({ + message_data['data']['file_size'] = pttElement.fileSize + MessageUnique.addFileCache({ peerUid: msg.peerUid, + msgId: msg.msgId, chatType: msg.chatType, - guildId: '', - }, - msg.msgId, - msg.msgSeq, - msg.senderUid, - element.elementId, - element.elementType.toString(), - element.pttElement.fileSize || '0', - element.pttElement.fileUuid || '', - ) + elementId: element.elementId, + elementType: element.elementType, + fileName: pttElement.fileName, + fileSize: String(pttElement.fileSize || '0') + }) } else if (element.arkElement) { message_data['type'] = OB11MessageDataType.json From c1d7aa7aedba765eb0b598e9879116b9ee73418e Mon Sep 17 00:00:00 2001 From: idranme Date: Wed, 14 Aug 2024 18:59:27 +0800 Subject: [PATCH 2/2] chore: v3.29.1 --- manifest.json | 2 +- src/onebot11/action/file/GetFile.ts | 1 - src/version.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 8b31b6b..749de07 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "LLOneBot", "slug": "LLOneBot", "description": "实现 OneBot 11 协议,用以 QQ 机器人开发", - "version": "3.29.0", + "version": "3.29.1", "icon": "./icon.webp", "authors": [ { diff --git a/src/onebot11/action/file/GetFile.ts b/src/onebot11/action/file/GetFile.ts index 7e53e4f..11fff91 100644 --- a/src/onebot11/action/file/GetFile.ts +++ b/src/onebot11/action/file/GetFile.ts @@ -3,7 +3,6 @@ import fsPromise from 'node:fs/promises' import { getConfigUtil } from '@/common/config' import { NTQQFileApi, NTQQGroupApi, NTQQUserApi, NTQQFriendApi, NTQQMsgApi } from '@/ntqqapi/api' import { ActionName } from '../types' -import { PicElement } from '@/ntqqapi/types' import { UUIDConverter } from '@/common/utils/helper' import { Peer, ChatType, ElementType } from '@/ntqqapi/types' import { MessageUnique } from '@/common/utils/MessageUnique' diff --git a/src/version.ts b/src/version.ts index f1fc764..b7db38f 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '3.29.0' +export const version = '3.29.1'