From 04802087385290f6330e214ed4b4971c7d388783 Mon Sep 17 00:00:00 2001 From: linyuchen Date: Fri, 8 Mar 2024 23:27:20 +0800 Subject: [PATCH] feat: file cache db --- src/common/data.ts | 2 -- src/common/db.ts | 42 +++++++++++++++++++++++++++------- src/onebot11/action/GetFile.ts | 4 ++-- src/onebot11/action/SendMsg.ts | 14 +++++++++++- src/onebot11/constructor.ts | 20 ++++++++-------- src/onebot11/utils.ts | 4 ++-- 6 files changed, 61 insertions(+), 25 deletions(-) diff --git a/src/common/data.ts b/src/common/data.ts index 43d1835..a766e5c 100644 --- a/src/common/data.ts +++ b/src/common/data.ts @@ -28,8 +28,6 @@ export const llonebotError: LLOneBotError = { otherError: '' } -export const fileCache = new Map() - export async function getFriend(qq: string, uid: string = ""): Promise { let filterKey = uid ? "uid" : "uin" diff --git a/src/common/db.ts b/src/common/db.ts index 16af692..cba3ac4 100644 --- a/src/common/db.ts +++ b/src/common/db.ts @@ -1,17 +1,17 @@ -// import {DATA_DIR} from "./utils"; import {Level} from "level"; import {RawMessage} from "../ntqqapi/types"; import {DATA_DIR, log} from "./utils"; import {selfInfo} from "./data"; -import * as wasi from "wasi"; +import {FileCache} from "./types"; class DBUtil { private readonly DB_KEY_PREFIX_MSG_ID = "msg_id_"; private readonly DB_KEY_PREFIX_MSG_SHORT_ID = "msg_short_id_"; private readonly DB_KEY_PREFIX_MSG_SEQ_ID = "msg_seq_id_"; + private readonly DB_KEY_PREFIX_FILE = "file_"; private db: Level; - private cache: Record = {} // : RawMessage + private cache: Record = {} // : RawMessage private currentShortId: number; /* @@ -19,6 +19,7 @@ class DBUtil { * msg_id_101231230999: {} // 长id: RawMessage * msg_short_id_1: 101231230999 // 短id: 长id * msg_seq_id_1: 101231230999 // 序列id: 长id + * file_7827DBAFJFW2323.png: {} // 文件名: FileCache * */ constructor() { @@ -61,7 +62,7 @@ class DBUtil { async getMsgByShortId(shortMsgId: number): Promise { const shortMsgIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + shortMsgId; if (this.cache[shortMsgIdKey]) { - return this.cache[shortMsgIdKey] + return this.cache[shortMsgIdKey] as RawMessage } const longId = await this.db.get(shortMsgIdKey); const msg = await this.getMsgByLongId(longId) @@ -72,7 +73,7 @@ class DBUtil { async getMsgByLongId(longId: string): Promise { const longIdKey = this.DB_KEY_PREFIX_MSG_ID + longId; if (this.cache[longIdKey]) { - return this.cache[longIdKey] + return this.cache[longIdKey] as RawMessage } const data = await this.db.get(longIdKey) const msg = JSON.parse(data) @@ -83,7 +84,7 @@ class DBUtil { async getMsgBySeqId(seqId: string): Promise { const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + seqId; if (this.cache[seqIdKey]) { - return this.cache[seqIdKey] + return this.cache[seqIdKey] as RawMessage } const longId = await this.db.get(seqIdKey); const msg = await this.getMsgByLongId(longId) @@ -95,7 +96,7 @@ class DBUtil { // 有则更新,无则添加 // log("addMsg", msg.msgId, msg.msgSeq, msg.msgShortId); const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId - let existMsg = this.cache[longIdKey] + let existMsg = this.cache[longIdKey] as RawMessage if (!existMsg) { try { existMsg = await this.getMsgByLongId(msg.msgId) @@ -136,7 +137,7 @@ class DBUtil { async updateMsg(msg: RawMessage) { const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId - let existMsg = this.cache[longIdKey] + let existMsg = this.cache[longIdKey] as RawMessage if (!existMsg) { try { existMsg = await this.getMsgByLongId(msg.msgId) @@ -179,6 +180,31 @@ class DBUtil { await this.db.put(key, this.currentShortId.toString()); return this.currentShortId; } + + async addFileCache(fileName: string, data: FileCache) { + const key = this.DB_KEY_PREFIX_FILE + fileName; + if (this.cache[key]) { + return + } + let cacheDBData = {...data} + delete cacheDBData['downloadFunc'] + this.cache[fileName] = data; + await this.db.put(key, JSON.stringify(cacheDBData)); + } + + async getFileCache(fileName: string): Promise { + const key = this.DB_KEY_PREFIX_FILE + fileName; + if (this.cache[key]) { + return this.cache[key] as FileCache + } + try{ + + let data = await this.db.get(key); + return JSON.parse(data); + }catch (e) { + + } + } } export const dbUtil = new DBUtil(); \ No newline at end of file diff --git a/src/onebot11/action/GetFile.ts b/src/onebot11/action/GetFile.ts index 12bf9ad..e0a5410 100644 --- a/src/onebot11/action/GetFile.ts +++ b/src/onebot11/action/GetFile.ts @@ -1,7 +1,7 @@ import BaseAction from "./BaseAction"; -import {fileCache} from "../../common/data"; import {getConfigUtil} from "../../common/utils"; import fs from "fs/promises"; +import {dbUtil} from "../../common/db"; export interface GetFilePayload { file: string // 文件名 @@ -18,7 +18,7 @@ export interface GetFileResponse { export class GetFileBase extends BaseAction { protected async _handle(payload: GetFilePayload): Promise { - const cache = fileCache.get(payload.file) + const cache = await dbUtil.getFileCache(payload.file) const {autoDeleteFile, enableLocalFile2Url, autoDeleteFileSecond} = getConfigUtil().getConfig() if (!cache) { throw new Error('file not found') diff --git a/src/onebot11/action/SendMsg.ts b/src/onebot11/action/SendMsg.ts index 985aeee..7ba805a 100644 --- a/src/onebot11/action/SendMsg.ts +++ b/src/onebot11/action/SendMsg.ts @@ -18,6 +18,7 @@ import {log} from "../../common/utils"; import {decodeCQCode} from "../cqcode"; import {dbUtil} from "../../common/db"; import {ALLOW_SEND_TEMP_MSG} from "../../common/config"; +import {FileCache} from "../../common/types"; function checkSendMessage(sendMsgList: OB11MessageData[]) { function checkUri(uri: string): boolean { @@ -328,9 +329,20 @@ export class SendMsg extends BaseAction { case OB11MessageDataType.file: case OB11MessageDataType.video: case OB11MessageDataType.voice: { - const file = sendMsg.data?.file + let file = sendMsg.data?.file const payloadFileName = sendMsg.data?.name if (file) { + const cache = await dbUtil.getFileCache(file) + if (cache){ + if (fs.existsSync(cache.filePath)){ + file = "file://" + cache.filePath + } + else if (cache.downloadFunc){ + await cache.downloadFunc() + file = cache.filePath; + log("找到文件缓存", file); + } + } const {path, isLocal, fileName, errMsg} = (await uri2local(file)) if (errMsg){ throw errMsg diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts index 36acf49..c4ec0c2 100644 --- a/src/onebot11/constructor.ts +++ b/src/onebot11/constructor.ts @@ -9,7 +9,7 @@ import { OB11UserSex } from "./types"; import {AtType, ChatType, Group, GroupMember, IMAGE_HTTP_HOST, RawMessage, SelfInfo, User} from '../ntqqapi/types'; -import {fileCache, getFriend, getGroupMember, selfInfo, tempGroupCodeMap} from '../common/data'; +import {getFriend, getGroupMember, selfInfo, tempGroupCodeMap} from '../common/data'; import {getConfigUtil, log} from "../common/utils"; import {NTQQApi} from "../ntqqapi/ntcall"; import {EventType} from "./event/OB11BaseEvent"; @@ -120,11 +120,11 @@ export class OB11Constructor { message_data["data"]["url"] = IMAGE_HTTP_HOST + url } else if (fileMd5){ - message_data["data"]["file_id"] = `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${fileMd5}/0` + message_data["data"]["file_id"] = `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${fileMd5.toUpperCase()}/0` } // message_data["data"]["file_id"] = element.picElement.fileUuid message_data["data"]["file_size"] = element.picElement.fileSize - fileCache.set(element.picElement.fileName, { + dbUtil.addFileCache(element.picElement.fileName, { fileName: element.picElement.fileName, filePath: element.picElement.sourcePath, fileSize: element.picElement.fileSize.toString(), @@ -133,7 +133,7 @@ export class OB11Constructor { await NTQQApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, element.elementId, element.picElement.thumbPath?.get(0) || "", element.picElement.sourcePath) } - }) + }).then() // 不在自动下载图片 } else if (element.videoElement) { @@ -142,7 +142,7 @@ export class OB11Constructor { message_data["data"]["path"] = element.videoElement.filePath // message_data["data"]["file_id"] = element.videoElement.fileUuid message_data["data"]["file_size"] = element.videoElement.fileSize - fileCache.set(element.videoElement.fileName, { + dbUtil.addFileCache(element.videoElement.fileName, { fileName: element.videoElement.fileName, filePath: element.videoElement.filePath, fileSize: element.videoElement.fileSize, @@ -150,7 +150,7 @@ export class OB11Constructor { await NTQQApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, element.elementId, element.videoElement.thumbPath.get(0), element.videoElement.filePath) } - }) + }).then() // 怎么拿到url呢 } else if (element.fileElement) { message_data["type"] = OB11MessageDataType.file; @@ -158,7 +158,7 @@ export class OB11Constructor { // message_data["data"]["path"] = element.fileElement.filePath // message_data["data"]["file_id"] = element.fileElement.fileUuid message_data["data"]["file_size"] = element.fileElement.fileSize - fileCache.set(element.fileElement.fileName, { + dbUtil.addFileCache(element.fileElement.fileName, { fileName: element.fileElement.fileName, filePath: element.fileElement.filePath, fileSize: element.fileElement.fileSize, @@ -166,7 +166,7 @@ export class OB11Constructor { await NTQQApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, element.elementId, null, element.fileElement.filePath) } - }) + }).then() // 怎么拿到url呢 } else if (element.pttElement) { message_data["type"] = OB11MessageDataType.voice; @@ -174,11 +174,11 @@ export class OB11Constructor { message_data["data"]["path"] = element.pttElement.filePath // message_data["data"]["file_id"] = element.pttElement.fileUuid message_data["data"]["file_size"] = element.pttElement.fileSize - fileCache.set(element.pttElement.fileName, { + dbUtil.addFileCache(element.pttElement.fileName, { fileName: element.pttElement.fileName, filePath: element.pttElement.filePath, fileSize: element.pttElement.fileSize, - }) + }).then() // log("收到语音消息", msg) // window.LLAPI.Ptt2Text(message.raw.msgId, message.peer, messages).then(text => { diff --git a/src/onebot11/utils.ts b/src/onebot11/utils.ts index 812e891..7b0fcca 100644 --- a/src/onebot11/utils.ts +++ b/src/onebot11/utils.ts @@ -1,8 +1,8 @@ import {DATA_DIR, isGIF, log} from "../common/utils"; import {v4 as uuidv4} from "uuid"; import * as path from 'node:path'; -import {fileCache} from "../common/data"; import * as fileType from 'file-type'; +import {dbUtil} from "../common/db"; const fs = require("fs").promises; @@ -73,7 +73,7 @@ export async function uri2local(uri: string, fileName: string = null) { filePath = pathname } } else { - const cache = fileCache.get(uri) + const cache = await dbUtil.getFileCache(uri); if (cache) { filePath = cache.filePath } else {