Compare commits

...

7 Commits

Author SHA1 Message Date
linyuchen
5ff6ceec6d chore: ver 3.13.8 2024-03-09 02:38:05 +08:00
linyuchen
17af156451 fix: update msg seqId 2024-03-09 02:34:21 +08:00
linyuchen
c3c9e74832 fix: image cache url 2024-03-08 23:52:35 +08:00
linyuchen
0480208738 feat: file cache db 2024-03-08 23:27:20 +08:00
linyuchen
62eefbdb69 fix: sent pic message url 2024-03-08 22:16:05 +08:00
linyuchen
566537cbe3 fix: 构建转发消息的文件没有自动删除 2024-03-07 20:19:00 +08:00
linyuchen
ed831ae4cd fix: 网络下载文件大小异常提示 2024-03-07 19:07:00 +08:00
11 changed files with 88 additions and 42 deletions

View File

@@ -1,10 +1,10 @@
{
"manifest_version": 4,
"type": "extension",
"name": "LLOneBot v3.13.7",
"name": "LLOneBot v3.13.8",
"slug": "LLOneBot",
"description": "LiteLoaderQQNT的OneBotApi",
"version": "3.13.7",
"version": "3.13.8",
"thumbnail": "./icon.png",
"authors": [
{

View File

@@ -28,8 +28,6 @@ export const llonebotError: LLOneBotError = {
otherError: ''
}
export const fileCache = new Map<string, FileCache>()
export async function getFriend(qq: string, uid: string = ""): Promise<Friend | undefined> {
let filterKey = uid ? "uid" : "uin"

View File

@@ -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<string, RawMessage> = {} // <msg_id_ | msg_short_id_ | msg_seq_id_><id>: RawMessage
private cache: Record<string, RawMessage | string | FileCache> = {} // <msg_id_ | msg_short_id_ | msg_seq_id_><id>: 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<RawMessage> {
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<RawMessage> {
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<RawMessage> {
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)
@@ -117,11 +118,10 @@ class DBUtil {
this.db.put(shortIdKey, msg.msgId).then();
this.db.put(longIdKey, JSON.stringify(msg)).then();
try {
if (!(await this.db.get(seqIdKey))) {
this.db.put(seqIdKey, msg.msgId).then();
}
await this.db.get(seqIdKey)
} catch (e) {
// log("新的seqId", seqIdKey)
this.db.put(seqIdKey, msg.msgId).then();
}
this.cache[shortIdKey] = this.cache[longIdKey] = msg;
if (!this.cache[seqIdKey]) {
@@ -136,12 +136,12 @@ 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)
} catch (e) {
return
existMsg = msg
}
}
@@ -154,11 +154,10 @@ class DBUtil {
}
this.db.put(shortIdKey, msg.msgId).then();
try {
if (!(await this.db.get(seqIdKey))) {
this.db.put(seqIdKey, msg.msgId).then();
}
await this.db.get(seqIdKey)
} catch (e) {
this.db.put(seqIdKey, msg.msgId).then();
// log("更新seqId error", e.stack, seqIdKey);
}
// log("更新消息", existMsg.msgSeq, existMsg.msgShortId, existMsg.msgId);
}
@@ -179,6 +178,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<FileCache | undefined> {
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();

View File

@@ -89,6 +89,9 @@ export class SendMsgElementConstructor {
picWidth = 768;
}
const {md5, fileName: _fileName, path, fileSize} = await NTQQApi.uploadFile(filePath, ElementType.FILE);
if (fileSize === 0){
throw "文件异常大小为0";
}
let element: SendFileElement = {
elementType: ElementType.FILE,
elementId: "",

View File

@@ -268,7 +268,7 @@ registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, ({msgRe
const message = msgRecord
const peerUid = message.peerUid
// log("收到自己发送成功的消息", Object.keys(sendMessagePool), message);
// log("收到自己发送成功的消息", message.msgSeq);
// log("收到自己发送成功的消息", message);
dbUtil.addMsg(message).then()
const sendCallback = sendMessagePool[peerUid]
if (sendCallback) {

View File

@@ -233,6 +233,7 @@ export interface PicElement {
fileSize: number;
fileName: string;
fileUuid: string;
md5HexStr?: string;
}
export interface GrayTipElement {

View File

@@ -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<GetFilePayload, GetFileResponse> {
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
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')

View File

@@ -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 {
@@ -158,6 +159,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
const {sendElements, deleteAfterSentFiles} = await this.createSendElements(messages, group)
try {
const returnMsg = await this.send(peer, sendElements, deleteAfterSentFiles)
deleteAfterSentFiles.map(f => fs.unlink(f, () => {}));
return {message_id: returnMsg.msgShortId}
} catch (e) {
log("发送消息失败", e.stack.toString())
@@ -213,7 +215,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
deleteAfterSentFiles
} = await this.createSendElements(this.convertMessage2List(messageNode.data.content), group);
log("开始生成转发节点", sendElements);
const nodeMsg = await this.send(selfPeer, sendElements, deleteAfterSentFiles, true);
const nodeMsg = await this.send(selfPeer, sendElements, deleteAfterSentFiles, false);
selfNodeMsgList.push(nodeMsg);
log("转发节点生成成功", nodeMsg.msgId);
} catch (e) {
@@ -327,9 +329,20 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
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
@@ -367,7 +380,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
}
}
private async send(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = false) {
private async send(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) {
if (!sendElements.length) {
throw ("消息体无法解析")
}

View File

@@ -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";
@@ -106,7 +106,7 @@ export class OB11Constructor {
continue
}
}catch (e) {
log("获取不到引用的消息", e.stack)
log("获取不到引用的消息", e.stack, element.replyElement.replayMsgSeq)
}
} else if (element.picElement) {
@@ -114,19 +114,26 @@ export class OB11Constructor {
// message_data["data"]["file"] = element.picElement.sourcePath
message_data["data"]["file"] = element.picElement.fileName
// message_data["data"]["path"] = element.picElement.sourcePath
message_data["data"]["url"] = IMAGE_HTTP_HOST + element.picElement.originImageUrl
const url = element.picElement.originImageUrl
const fileMd5 = element.picElement.md5HexStr
if (url){
message_data["data"]["url"] = IMAGE_HTTP_HOST + url
}
else if (fileMd5 && element.picElement.fileUuid.indexOf("_") === -1){ // fileuuid有下划线的是Linux发送的这个url是另外的格式目前尚未得知如何组装
message_data["data"]["url"] = `${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(),
url: IMAGE_HTTP_HOST + element.picElement.originImageUrl,
url: message_data["data"]["url"],
downloadFunc: async () => {
await NTQQApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid,
element.elementId, element.picElement.thumbPath?.get(0) || "", element.picElement.sourcePath)
}
})
}).then()
// 不在自动下载图片
} else if (element.videoElement) {
@@ -135,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,
@@ -143,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;
@@ -151,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,
@@ -159,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;
@@ -167,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 => {

View File

@@ -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 {

View File

@@ -1 +1 @@
export const version = "3.13.7"
export const version = "3.13.8"