diff --git a/manifest.json b/manifest.json index a6db5f2..d03b050 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "LLOneBot", "slug": "LLOneBot", "description": "实现 OneBot 11 协议,用于 QQ 机器人开发", - "version": "3.31.9", + "version": "3.31.10", "icon": "./icon.webp", "authors": [ { diff --git a/src/common/utils/eventTask.ts b/src/common/utils/eventTask.ts deleted file mode 100644 index 2c84e03..0000000 --- a/src/common/utils/eventTask.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { NodeIQQNTWrapperSession } from '@/ntqqapi/wrapper' -import { randomUUID } from 'node:crypto' - -interface Internal_MapKey { - timeout: number - createtime: number - func: (...arg: any[]) => unknown - checker?: (...args: any[]) => boolean -} - -export class ListenerClassBase { - [key: string]: string -} - -export interface ListenerIBase { - new(listener: unknown): ListenerClassBase -} - -// forked from https://github.com/NapNeko/NapCatQQ/blob/6f6b258f22d7563f15d84e7172c4d4cbb547f47e/src/common/utils/EventTask.ts#L20 -export class NTEventWrapper { - private ListenerMap: { [key: string]: ListenerIBase } | undefined//ListenerName-Unique -> Listener构造函数 - private WrapperSession: NodeIQQNTWrapperSession | undefined//WrapperSession - private ListenerManger: Map = new Map() //ListenerName-Unique -> Listener实例 - private EventTask = new Map>>()//tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func} - public initialised = false - - constructor() { - } - - createProxyDispatch(ListenerMainName: string) { - const current = this - return new Proxy({}, { - get(target: any, prop: string, receiver: unknown) { - // console.log('get', prop, typeof target[prop]) - if (typeof target[prop] === 'undefined') { - // 如果方法不存在,返回一个函数,这个函数调用existentMethod - return (...args: unknown[]) => { - current.dispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then() - } - } - // 如果方法存在,正常返回 - return Reflect.get(target, prop, receiver) - } - }) - } - - init({ ListenerMap, WrapperSession }: { ListenerMap: { [key: string]: typeof ListenerClassBase }, WrapperSession: NodeIQQNTWrapperSession }) { - this.ListenerMap = ListenerMap - this.WrapperSession = WrapperSession - this.initialised = true - } - - createEventFunction unknown>(eventName: string): T | undefined { - const eventNameArr = eventName.split('/') - type eventType = { - [key: string]: () => { [key: string]: (...params: Parameters) => Promise> } - } - if (eventNameArr.length > 1) { - const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '') - const eventName = eventNameArr[1] - //getNodeIKernelGroupListener,GroupService - //console.log('2', eventName) - const services = (this.WrapperSession as unknown as eventType)[serviceName]() - let event = services[eventName] - //重新绑定this - event = event.bind(services) - if (event) { - return event as T - } - return undefined - } - } - - 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.createEventFunction<(listener: T) => number>(Service) - addfunc!(Listener as T) - //console.log(addfunc!(Listener as T)) - this.ListenerManger.set(listenerMainName + uniqueCode, Listener) - } - return Listener as T - } - - //统一回调清理事件 - async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: unknown[]) { - //console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args) - this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.forEach((task, uuid) => { - //console.log(task.func, uuid, task.createtime, task.timeout) - if (task.createtime + task.timeout < Date.now()) { - this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid) - return - } - if (task.checker && task.checker(...args)) { - task.func(...args) - } - }) - } - - async CallNoListenerEvent Promise>(EventName = '', timeout: number = 3000, ...args: Parameters) { - return new Promise>>(async (resolve, reject) => { - const EventFunc = this.createEventFunction(EventName) - let complete = false - const Timeouter = setTimeout(() => { - if (!complete) { - reject(new Error('NTEvent EventName:' + EventName + ' timeout')) - } - }, timeout) - const retData = await EventFunc!(...args) - complete = true - resolve(retData) - }) - } - - async RegisterListen void>(ListenerName = '', waitTimes = 1, timeout = 5000, checker: (...args: Parameters) => boolean) { - return new Promise>((resolve, reject) => { - const ListenerNameList = ListenerName.split('/') - const ListenerMainName = ListenerNameList[0] - const ListenerSubName = ListenerNameList[1] - const id = randomUUID() - let complete = 0 - let retData: Parameters | undefined = undefined - const databack = () => { - if (complete == 0) { - reject(new Error(' ListenerName:' + ListenerName + ' timeout')) - } else { - resolve(retData!) - } - } - const Timeouter = setTimeout(databack, timeout) - const eventCallbak = { - timeout: timeout, - createtime: Date.now(), - checker: checker, - func: (...args: Parameters) => { - complete++ - retData = args - if (complete >= waitTimes) { - clearTimeout(Timeouter) - databack() - } - } - } - if (!this.EventTask.get(ListenerMainName)) { - this.EventTask.set(ListenerMainName, new Map()) - } - if (!(this.EventTask.get(ListenerMainName)?.get(ListenerSubName))) { - this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map()) - } - this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak) - this.createListenerFunction(ListenerMainName) - }) - } - - async CallNormalEvent Promise, ListenerType extends (...args: any[]) => void> - (EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters) => boolean, ...args: Parameters) { - return new Promise<[EventRet: Awaited>, ...Parameters]>(async (resolve, reject) => { - const id = randomUUID() - let complete = 0 - let retData: Parameters | undefined = undefined - let retEvent = {} - const databack = () => { - if (complete == 0) { - reject(new Error('Timeout: NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n')) - } else { - resolve([retEvent as Awaited>, ...retData!]) - } - } - - const ListenerNameList = ListenerName.split('/') - const ListenerMainName = ListenerNameList[0] - const ListenerSubName = ListenerNameList[1] - - const Timeouter = setTimeout(databack, timeout) - - const eventCallbak = { - timeout: timeout, - createtime: Date.now(), - checker: checker, - func: (...args: unknown[]) => { - complete++ - //console.log('func', ...args) - retData = args as Parameters - if (complete >= waitTimes) { - clearTimeout(Timeouter) - databack() - } - } - } - if (!this.EventTask.get(ListenerMainName)) { - this.EventTask.set(ListenerMainName, new Map()) - } - if (!(this.EventTask.get(ListenerMainName)?.get(ListenerSubName))) { - this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map()) - } - this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak) - this.createListenerFunction(ListenerMainName) - const EventFunc = this.createEventFunction(EventName) - retEvent = await EventFunc!(...args) - }) - } -} - -export const NTEventDispatch = new NTEventWrapper() - -// 示例代码 快速创建事件 -// let NTEvent = new NTEventWrapper() -// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise>('NodeIKernelProfileLikeService/GetTest') -// if (TestEvent) { -// TestEvent(true) -// } - -// 示例代码 快速创建监听Listener类 -// let NTEvent = new NTEventWrapper() -// NTEvent.CreatListenerFunction('NodeIKernelMsgListener', 'core') - - -// 调用接口 -//let NTEvent = new NTEventWrapper() -//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise, (data1: string, data2: number) => void>('NodeIKernelProfileLikeService/GetTest', 'NodeIKernelMsgListener/onAddSendMsg', 1, 3000, true) - -// 注册监听 解除监听 -// NTEventDispatch.RigisterListener('NodeIKernelMsgListener/onAddSendMsg','core',cb) -// NTEventDispatch.UnRigisterListener('NodeIKernelMsgListener/onAddSendMsg','core') - -// let GetTest = NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode) -// GetTest('test') - -// always模式 -// NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode,(...args:any[])=>{ console.log(args) }) \ No newline at end of file diff --git a/src/common/utils/messageUnique.ts b/src/common/utils/messageUnique.ts index 3df7330..2d9ea0b 100644 --- a/src/common/utils/messageUnique.ts +++ b/src/common/utils/messageUnique.ts @@ -10,154 +10,154 @@ import { DATA_DIR } from '../globalVars' import { FileCacheV2 } from '../types' interface SQLiteTables extends Tables { - message: { - shortId: number - msgId: string - chatType: number - peerUid: string - } - file_v2: FileCacheV2 + message: { + shortId: number + msgId: string + chatType: number + peerUid: string + } + file_v2: FileCacheV2 } interface MsgIdAndPeerByShortId { - MsgId: string - Peer: Peer + MsgId: string + Peer: Peer } // forked from https://github.com/NapNeko/NapCatQQ/blob/6f6b258f22d7563f15d84e7172c4d4cbb547f47e/src/common/utils/MessageUnique.ts#L84 class MessageUniqueWrapper { - private msgDataMap: LimitedHashTable - private msgIdMap: LimitedHashTable - private db: Database | undefined + private msgDataMap: LimitedHashTable + private msgIdMap: LimitedHashTable + private db: Database | undefined - constructor(maxMap: number = 1000) { - this.msgIdMap = new LimitedHashTable(maxMap) - this.msgDataMap = new LimitedHashTable(maxMap) + constructor(maxMap: number = 1000) { + this.msgIdMap = new LimitedHashTable(maxMap) + this.msgDataMap = new LimitedHashTable(maxMap) + } + + async init(uin: string) { + const dbDir = path.join(DATA_DIR, 'database') + if (!fs.existsSync(dbDir)) { + await fsPromise.mkdir(dbDir) } + const database = new Database() + await database.connect(SQLite, { + path: path.join(dbDir, `${uin}.db`) + }) + database.extend('message', { + shortId: 'integer(10)', + chatType: 'unsigned', + msgId: 'string(24)', + peerUid: 'string(24)' + }, { + primary: 'shortId' + }) + database.extend('file_v2', { + fileName: 'string', + fileSize: 'string', + fileUuid: 'string(128)', + msgId: 'string(24)', + msgTime: 'unsigned(10)', + peerUid: 'string(24)', + chatType: 'unsigned', + elementId: 'string(24)', + elementType: 'unsigned', + }, { + primary: 'fileUuid', + indexes: ['fileName'] + }) + this.db = database + } - async init(uin: string) { - const dbDir = path.join(DATA_DIR, 'database') - if (!fs.existsSync(dbDir)) { - await fsPromise.mkdir(dbDir) + async getRecentMsgIds(Peer: Peer, size: number): Promise { + const heads = this.msgIdMap.getHeads(size) + if (!heads) { + return [] + } + const data: (MsgIdAndPeerByShortId | undefined)[] = [] + for (const t of heads) { + data.push(await MessageUnique.getMsgIdAndPeerByShortId(t.value)) + } + const ret = data.filter((t) => t?.Peer.chatType === Peer.chatType && t?.Peer.peerUid === Peer.peerUid) + return ret.map((t) => t?.MsgId).filter((t) => t !== undefined) + } + + createMsg(peer: Peer, msgId: string): number { + const key = `${msgId}|${peer.chatType}|${peer.peerUid}` + const hash = createHash('md5').update(key).digest() + //设置第一个bit为0 保证shortId为正数 + hash[0] &= 0x7f + const shortId = hash.readInt32BE(0) + //减少性能损耗 + // const isExist = this.msgIdMap.getKey(shortId) + // if (isExist && isExist === msgId) { + // return shortId + // } + this.msgIdMap.set(msgId, shortId) + this.msgDataMap.set(key, shortId) + this.db?.upsert('message', [{ + msgId, + shortId, + chatType: peer.chatType, + peerUid: peer.peerUid + }], 'shortId').then() + return shortId + } + + async getMsgIdAndPeerByShortId(shortId: number): Promise { + const data = this.msgDataMap.getKey(shortId) + if (data) { + const [msgId, chatTypeStr, peerUid] = data.split('|') + const peer: Peer = { + chatType: parseInt(chatTypeStr), + peerUid, + guildId: '', + } + return { MsgId: msgId, Peer: peer } + } + const items = await this.db?.get('message', { shortId }) + if (items?.length) { + const { msgId, chatType, peerUid } = items[0] + return { + MsgId: msgId, + Peer: { + chatType, + peerUid, + guildId: '', } - const database = new Database() - await database.connect(SQLite, { - path: path.join(dbDir, `${uin}.db`) - }) - database.extend('message', { - shortId: 'integer(10)', - chatType: 'unsigned', - msgId: 'string(24)', - peerUid: 'string(24)' - }, { - primary: 'shortId' - }) - database.extend('file_v2', { - fileName: 'string', - fileSize: 'string', - fileUuid: 'string(128)', - msgId: 'string(24)', - msgTime: 'unsigned(10)', - peerUid: 'string(24)', - chatType: 'unsigned', - elementId: 'string(24)', - elementType: 'unsigned', - }, { - primary: 'fileUuid', - indexes: ['fileName'] - }) - this.db = database + } } + return undefined + } - async getRecentMsgIds(Peer: Peer, size: number): Promise { - const heads = this.msgIdMap.getHeads(size) - if (!heads) { - return [] - } - const data: (MsgIdAndPeerByShortId | undefined)[] = [] - for (const t of heads) { - data.push(await MessageUnique.getMsgIdAndPeerByShortId(t.value)) - } - const ret = data.filter((t) => t?.Peer.chatType === Peer.chatType && t?.Peer.peerUid === Peer.peerUid) - return ret.map((t) => t?.MsgId).filter((t) => t !== undefined) - } + getShortIdByMsgId(msgId: string): number | undefined { + return this.msgIdMap.getValue(msgId) + } - createMsg(peer: Peer, msgId: string): number { - const key = `${msgId}|${peer.chatType}|${peer.peerUid}` - const hash = createHash('md5').update(key).digest() - //设置第一个bit为0 保证shortId为正数 - hash[0] &= 0x7f - const shortId = hash.readInt32BE(0) - //减少性能损耗 - // const isExist = this.msgIdMap.getKey(shortId) - // if (isExist && isExist === msgId) { - // return shortId - // } - this.msgIdMap.set(msgId, shortId) - this.msgDataMap.set(key, shortId) - this.db?.upsert('message', [{ - msgId, - shortId, - chatType: peer.chatType, - peerUid: peer.peerUid - }], 'shortId').then() - return shortId - } + async getPeerByMsgId(msgId: string) { + const shortId = this.msgIdMap.getValue(msgId) + if (!shortId) return undefined + return await this.getMsgIdAndPeerByShortId(shortId) + } - async getMsgIdAndPeerByShortId(shortId: number): Promise { - const data = this.msgDataMap.getKey(shortId) - if (data) { - const [msgId, chatTypeStr, peerUid] = data.split('|') - const peer: Peer = { - chatType: parseInt(chatTypeStr), - peerUid, - guildId: '', - } - return { MsgId: msgId, Peer: peer } - } - const items = await this.db?.get('message', { shortId }) - if (items?.length) { - const { msgId, chatType, peerUid } = items[0] - return { - MsgId: msgId, - Peer: { - chatType, - peerUid, - guildId: '', - } - } - } - return undefined - } + resize(maxSize: number): void { + this.msgIdMap.resize(maxSize) + this.msgDataMap.resize(maxSize) + } - getShortIdByMsgId(msgId: string): number | undefined { - return this.msgIdMap.getValue(msgId) - } + addFileCache(data: FileCacheV2) { + return this.db?.upsert('file_v2', [data], 'fileUuid') + } - async getPeerByMsgId(msgId: string) { - const shortId = this.msgIdMap.getValue(msgId) - if (!shortId) return undefined - return await this.getMsgIdAndPeerByShortId(shortId) - } + getFileCacheByName(fileName: string) { + return this.db?.get('file_v2', { fileName }, { + sort: { msgTime: 'desc' } + }) + } - resize(maxSize: number): void { - this.msgIdMap.resize(maxSize) - this.msgDataMap.resize(maxSize) - } - - addFileCache(data: FileCacheV2) { - return this.db?.upsert('file_v2', [data], 'fileUuid') - } - - getFileCacheByName(fileName: string) { - return this.db?.get('file_v2', { fileName }, { - sort: { msgTime: 'desc' } - }) - } - - getFileCacheById(fileUuid: string) { - return this.db?.get('file_v2', { fileUuid }) - } + getFileCacheById(fileUuid: string) { + return this.db?.get('file_v2', { fileUuid }) + } } export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper() \ No newline at end of file diff --git a/src/common/utils/table.ts b/src/common/utils/table.ts index bd2a6e0..29738af 100644 --- a/src/common/utils/table.ts +++ b/src/common/utils/table.ts @@ -1,72 +1,72 @@ // forked from https://github.com/NapNeko/NapCatQQ/blob/6f6b258f22d7563f15d84e7172c4d4cbb547f47e/src/common/utils/MessageUnique.ts#L5 export class LimitedHashTable { - private keyToValue: Map = new Map() - private valueToKey: Map = new Map() - private maxSize: number + private keyToValue: Map = new Map() + private valueToKey: Map = new Map() + private maxSize: number - constructor(maxSize: number) { - this.maxSize = maxSize - } + constructor(maxSize: number) { + this.maxSize = maxSize + } - resize(count: number) { - this.maxSize = count - } + resize(count: number) { + this.maxSize = count + } - set(key: K, value: V): void { - this.keyToValue.set(key, value) - this.valueToKey.set(value, key) - while (this.keyToValue.size !== this.valueToKey.size) { - console.log('keyToValue.size !== valueToKey.size Error Atom') - this.keyToValue.clear() - this.valueToKey.clear() - } - while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) { - const oldestKey = this.keyToValue.keys().next().value - this.valueToKey.delete(this.keyToValue.get(oldestKey)!) - this.keyToValue.delete(oldestKey) - } + set(key: K, value: V): void { + this.keyToValue.set(key, value) + this.valueToKey.set(value, key) + while (this.keyToValue.size !== this.valueToKey.size) { + console.log('keyToValue.size !== valueToKey.size Error Atom') + this.keyToValue.clear() + this.valueToKey.clear() } + while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) { + const oldestKey = this.keyToValue.keys().next().value + this.valueToKey.delete(this.keyToValue.get(oldestKey)!) + this.keyToValue.delete(oldestKey) + } + } - getValue(key: K): V | undefined { - return this.keyToValue.get(key) - } + getValue(key: K): V | undefined { + return this.keyToValue.get(key) + } - getKey(value: V): K | undefined { - return this.valueToKey.get(value) - } + getKey(value: V): K | undefined { + return this.valueToKey.get(value) + } - deleteByValue(value: V): void { - const key = this.valueToKey.get(value) - if (key !== undefined) { - this.keyToValue.delete(key) - this.valueToKey.delete(value) - } + deleteByValue(value: V): void { + const key = this.valueToKey.get(value) + if (key !== undefined) { + this.keyToValue.delete(key) + this.valueToKey.delete(value) } + } - deleteByKey(key: K): void { - const value = this.keyToValue.get(key) - if (value !== undefined) { - this.keyToValue.delete(key) - this.valueToKey.delete(value) - } + deleteByKey(key: K): void { + const value = this.keyToValue.get(key) + if (value !== undefined) { + this.keyToValue.delete(key) + this.valueToKey.delete(value) } + } - getKeyList(): K[] { - return Array.from(this.keyToValue.keys()) - } + getKeyList(): K[] { + return Array.from(this.keyToValue.keys()) + } - //获取最近刚写入的几个值 - getHeads(size: number): { key: K; value: V }[] | undefined { - const keyList = this.getKeyList() - if (keyList.length === 0) { - return undefined - } - const result: { key: K; value: V }[] = [] - const listSize = Math.min(size, keyList.length) - for (let i = 0; i < listSize; i++) { - const key = keyList[listSize - i] - result.push({ key, value: this.keyToValue.get(key)! }) - } - return result + //获取最近刚写入的几个值 + getHeads(size: number): { key: K; value: V }[] | undefined { + const keyList = this.getKeyList() + if (keyList.length === 0) { + return undefined } + const result: { key: K; value: V }[] = [] + const listSize = Math.min(size, keyList.length) + for (let i = 0; i < listSize; i++) { + const key = keyList[listSize - i] + result.push({ key, value: this.keyToValue.get(key)! }) + } + return result + } } \ No newline at end of file diff --git a/src/ntqqapi/api/file.ts b/src/ntqqapi/api/file.ts index e17bd57..6599064 100644 --- a/src/ntqqapi/api/file.ts +++ b/src/ntqqapi/api/file.ts @@ -21,7 +21,6 @@ import { Peer } from '@/ntqqapi/types/msg' import { calculateFileMD5 } from '@/common/utils/file' import { fileTypeFromFile } from 'file-type' import fsPromise from 'node:fs/promises' -import { NTEventDispatch } from '@/common/utils/eventTask' import { OnRichMediaDownloadCompleteParams } from '@/ntqqapi/listeners' import { Time } from 'cosmokit' import { Service, Context } from 'cordis' @@ -143,76 +142,32 @@ export class NTQQFileApi extends Service { return sourcePath } } - let filePath: string - if (NTEventDispatch.initialised) { - const data = await NTEventDispatch.CallNormalEvent< - ( - params: { - fileModelId: string, - downloadSourceType: number, - triggerType: number, - msgId: string, - chatType: ChatType, - peerUid: string, - elementId: string, - thumbSize: number, - downloadType: number, - filePath: string - }) => Promise, - (fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) => void - >( - 'NodeIKernelMsgService/downloadRichMedia', - 'NodeIKernelMsgListener/onRichMediaDownloadComplete', - 1, - timeout, - (arg: OnRichMediaDownloadCompleteParams) => { - if (arg.msgId === msgId) { - return true - } - return false - }, + const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>( + 'nodeIKernelMsgService/downloadRichMedia', + [ { - fileModelId: '0', - downloadSourceType: 0, - triggerType: 1, - msgId: msgId, - chatType: chatType, - peerUid: peerUid, - elementId: elementId, - thumbSize: 0, - downloadType: 1, - filePath: thumbPath - } - ) - filePath = data[1].filePath - } else { - const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>( - 'nodeIKernelMsgService/downloadRichMedia', - [ - { - getReq: { - fileModelId: '0', - downloadSourceType: 0, - triggerType: 1, - msgId: msgId, - chatType: chatType, - peerUid: peerUid, - elementId: elementId, - thumbSize: 0, - downloadType: 1, - filePath: thumbPath, - }, + getReq: { + fileModelId: '0', + downloadSourceType: 0, + triggerType: 1, + msgId: msgId, + chatType: chatType, + peerUid: peerUid, + elementId: elementId, + thumbSize: 0, + downloadType: 1, + filePath: thumbPath, }, - null, - ], - { - cbCmd: ReceiveCmdS.MEDIA_DOWNLOAD_COMPLETE, - cmdCB: payload => payload.notifyInfo.msgId === msgId, - timeout - } - ) - filePath = data.notifyInfo.filePath - } + }, + null, + ], + { + cbCmd: ReceiveCmdS.MEDIA_DOWNLOAD_COMPLETE, + cmdCB: payload => payload.notifyInfo.msgId === msgId, + timeout + } + ) + let filePath = data.notifyInfo.filePath if (filePath.startsWith('\\')) { const downloadPath = TEMP_DIR filePath = path.join(downloadPath, filePath) @@ -238,7 +193,7 @@ export class NTQQFileApi extends Service { const url: string = element.originImageUrl! // 没有域名 const md5HexStr = element.md5HexStr const fileMd5 = element.md5HexStr - + if (url) { const parsedUrl = new URL(IMAGE_HTTP_HOST + url) //临时解析拼接 const imageAppid = parsedUrl.searchParams.get('appid') diff --git a/src/ntqqapi/api/friend.ts b/src/ntqqapi/api/friend.ts index d447f3e..8eb3004 100644 --- a/src/ntqqapi/api/friend.ts +++ b/src/ntqqapi/api/friend.ts @@ -2,8 +2,7 @@ import { Friend, FriendV2, SimpleInfo, CategoryFriend } from '../types' import { ReceiveCmdS } from '../hook' import { invoke, NTMethod, NTClass } from '../ntcall' import { getSession } from '@/ntqqapi/wrapper' -import { BuddyListReqType, NodeIKernelProfileService } from '../services' -import { NTEventDispatch } from '@/common/utils/eventTask' +import { BuddyListReqType } from '../services' import { Dict, pick } from 'cosmokit' import { Service, Context } from 'cordis' @@ -19,7 +18,7 @@ export class NTQQFriendApi extends Service { } /** 大于或等于 26702 应使用 getBuddyV2 */ - async getFriends(_forced = false) { + async getFriends() { const data = await invoke<{ data: { categoryId: number @@ -75,9 +74,7 @@ export class NTQQFriendApi extends Service { const buddyService = session.getBuddyService() const buddyListV2 = await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) uids.push(...buddyListV2.data.flatMap(item => item.buddyUids)) - const data = await NTEventDispatch.CallNoListenerEvent( - 'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids - ) + const data = await session.getProfileService().getCoreAndBaseInfo('nodeStore', uids) return Array.from(data.values()) } else { const data = await invoke<{ @@ -92,11 +89,8 @@ export class NTQQFriendApi extends Service { afterFirstCmd: false, } ) - const categoryUids: Map = new Map() - for (const item of data.buddyCategory) { - categoryUids.set(item.categoryId, item.buddyUids) - } - return Object.values(data.userSimpleInfos).filter(v => v.baseInfo && categoryUids.get(v.baseInfo.categoryId)?.includes(v.uid!)) + const uids = data.buddyCategory.flatMap(item => item.buddyUids) + return Object.values(data.userSimpleInfos).filter(v => uids.includes(v.uid!)) } } @@ -106,12 +100,10 @@ export class NTQQFriendApi extends Service { const session = getSession() if (session) { const uids: string[] = [] - const buddyService = session?.getBuddyService() + const buddyService = session.getBuddyService() const buddyListV2 = await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) uids.push(...buddyListV2.data.flatMap(item => item.buddyUids)) - const data = await NTEventDispatch.CallNoListenerEvent( - 'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids - ) + const data = await session.getProfileService().getCoreAndBaseInfo('nodeStore', uids) for (const [, item] of data) { if (retMap.size > 5000) { break @@ -155,9 +147,7 @@ export class NTQQFriendApi extends Service { }) return item.buddyUids })) - const data = await NTEventDispatch.CallNoListenerEvent( - 'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids - ) + const data = await session.getProfileService().getCoreAndBaseInfo('nodeStore', uids) return Array.from(data).map(([key, value]) => { const category = categoryMap.get(key) return category ? { ...value, categoryId: category.categoryId, categroyName: category.categroyName } : value diff --git a/src/ntqqapi/api/group.ts b/src/ntqqapi/api/group.ts index 949e171..0e7a8de 100644 --- a/src/ntqqapi/api/group.ts +++ b/src/ntqqapi/api/group.ts @@ -1,5 +1,5 @@ import { ReceiveCmdS } from '../hook' -import { Group, GroupMember, GroupMemberRole, GroupNotifies, GroupRequestOperateTypes, GroupNotify, GetFileListParam } from '../types' +import { Group, GroupMember, GroupMemberRole, GroupNotifies, GroupRequestOperateTypes, GetFileListParam } from '../types' import { invoke, NTClass, NTMethod } from '../ntcall' import { GeneralCallResult } from '../services' import { NTQQWindows } from './window' @@ -24,7 +24,7 @@ export class NTQQGroupApi extends Service { super(ctx, 'ntGroupApi', true) } - async getGroups(forced = false): Promise { + async getGroups(): Promise { const result = await invoke<{ updateType: number groupList: Group[] diff --git a/src/ntqqapi/api/user.ts b/src/ntqqapi/api/user.ts index 52cb1f5..cb4791d 100644 --- a/src/ntqqapi/api/user.ts +++ b/src/ntqqapi/api/user.ts @@ -65,7 +65,7 @@ export class NTQQUserApi extends Service { return ret } - async getUserDetailInfo(uid: string, _getLevel = false) { + async getUserDetailInfo(uid: string) { if (getBuildVersion() >= 26702) { return this.fetchUserDetailInfo(uid) } diff --git a/src/ntqqapi/core.ts b/src/ntqqapi/core.ts index e1524f2..4f38fce 100644 --- a/src/ntqqapi/core.ts +++ b/src/ntqqapi/core.ts @@ -2,8 +2,6 @@ import fs from 'node:fs' import { Service, Context } from 'cordis' import { registerCallHook, registerReceiveHook, ReceiveCmdS } from './hook' import { MessageUnique } from '../common/utils/messageUnique' -import { NTEventDispatch } from '../common/utils/eventTask' -import { wrapperConstructor, getSession } from './wrapper' import { Config as LLOBConfig } from '../common/types' import { llonebotError } from '../common/globalVars' import { isNumeric } from '../common/utils/misc' @@ -45,10 +43,6 @@ class Core extends Service { public start() { llonebotError.otherError = '' - const WrapperSession = getSession() - if (WrapperSession) { - NTEventDispatch.init({ ListenerMap: wrapperConstructor, WrapperSession }) - } MessageUnique.init(selfInfo.uin) this.registerListener() this.ctx.logger.info(`LLOneBot/${version}`) diff --git a/src/ntqqapi/entities.ts b/src/ntqqapi/entities.ts index 5f02e5c..451a6f3 100644 --- a/src/ntqqapi/entities.ts +++ b/src/ntqqapi/entities.ts @@ -201,7 +201,7 @@ export namespace SendElementEntities { // log("生成缩略图", _thumbPath) thumbPath.set(0, _thumbPath) const thumbMd5 = await calculateFileMD5(_thumbPath) - let element: SendVideoElement = { + const element: SendVideoElement = { elementType: ElementType.VIDEO, elementId: '', videoElement: { diff --git a/src/ntqqapi/wrapper.ts b/src/ntqqapi/wrapper.ts index 9250c9b..6530797 100644 --- a/src/ntqqapi/wrapper.ts +++ b/src/ntqqapi/wrapper.ts @@ -34,7 +34,7 @@ export interface WrapperApi { } export interface WrapperConstructor { - [key: string]: any + [key: string]: unknown } const wrapperApi: WrapperApi = {} diff --git a/src/onebot11/action/go-cqhttp/UploadFile.ts b/src/onebot11/action/go-cqhttp/UploadFile.ts index 24428b9..3502d2f 100644 --- a/src/onebot11/action/go-cqhttp/UploadFile.ts +++ b/src/onebot11/action/go-cqhttp/UploadFile.ts @@ -28,7 +28,7 @@ export class UploadGroupFile extends BaseAction { } const sendFileEle = await SendElementEntities.file(this.ctx, downloadResult.path, payload.name, payload.folder_id) const peer = await createPeer(this.ctx, payload, CreatePeerMode.Group) - await sendMsg(this.ctx, peer, [sendFileEle], [], true) + await sendMsg(this.ctx, peer, [sendFileEle], []) return null } } @@ -53,7 +53,7 @@ export class UploadPrivateFile extends BaseAction { actionName = ActionName.GetGroupList - protected async _handle(payload: Payload) { - const groupList = await this.ctx.ntGroupApi.getGroups(payload?.no_cache === true || payload?.no_cache === 'true') + protected async _handle() { + const groupList = await this.ctx.ntGroupApi.getGroups() return OB11Entities.groups(groupList) } } diff --git a/src/onebot11/action/group/GetGroupMemberInfo.ts b/src/onebot11/action/group/GetGroupMemberInfo.ts index e05ea91..b4d153d 100644 --- a/src/onebot11/action/group/GetGroupMemberInfo.ts +++ b/src/onebot11/action/group/GetGroupMemberInfo.ts @@ -18,7 +18,7 @@ class GetGroupMemberInfo extends BaseAction { if (member) { if (isNullable(member.sex)) { //log('获取群成员详细信息') - const info = await this.ctx.ntUserApi.getUserDetailInfo(member.uid, true) + const info = await this.ctx.ntUserApi.getUserDetailInfo(member.uid) //log('群成员详细信息结果', info) Object.assign(member, info) } diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 35ced15..cf73588 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -214,7 +214,7 @@ export class SendMsg extends BaseAction { } // log("分割后的转发节点", sendElementsSplit) for (const eles of sendElementsSplit) { - const nodeMsg = await sendMsg(this.ctx, selfPeer, eles, [], true) + const nodeMsg = await sendMsg(this.ctx, selfPeer, eles, []) if (!nodeMsg) { this.ctx.logger.warn('转发节点生成失败', eles) continue diff --git a/src/onebot11/action/system/CanSendRecord.ts b/src/onebot11/action/system/CanSendRecord.ts index d75f35f..665d5fb 100644 --- a/src/onebot11/action/system/CanSendRecord.ts +++ b/src/onebot11/action/system/CanSendRecord.ts @@ -5,7 +5,7 @@ interface ReturnType { yes: boolean } -export default class CanSendRecord extends BaseAction { +export default class CanSendRecord extends BaseAction { actionName = ActionName.CanSendRecord protected async _handle() { diff --git a/src/onebot11/action/user/GetFriendList.ts b/src/onebot11/action/user/GetFriendList.ts index 7c6e632..7bbead3 100644 --- a/src/onebot11/action/user/GetFriendList.ts +++ b/src/onebot11/action/user/GetFriendList.ts @@ -16,7 +16,7 @@ export class GetFriendList extends BaseAction { if (getBuildVersion() >= 26702) { return OB11Entities.friendsV2(await this.ctx.ntFriendApi.getBuddyV2(refresh)) } - return OB11Entities.friends(await this.ctx.ntFriendApi.getFriends(refresh)) + return OB11Entities.friends(await this.ctx.ntFriendApi.getFriends()) } } diff --git a/src/onebot11/adapter.ts b/src/onebot11/adapter.ts index 0f16a32..b3a2bf3 100644 --- a/src/onebot11/adapter.ts +++ b/src/onebot11/adapter.ts @@ -399,7 +399,7 @@ class OneBot11Adapter extends Service { this.handleRecallMsg(input) }) this.ctx.on('nt/message-sent', input => { - this.handleRecallMsg(input) + this.handleMsg(input) }) this.ctx.on('nt/group-notify', input => { this.handleGroupNotify(input) diff --git a/src/onebot11/entities.ts b/src/onebot11/entities.ts index b319998..68b04a1 100644 --- a/src/onebot11/entities.ts +++ b/src/onebot11/entities.ts @@ -173,8 +173,8 @@ export namespace OB11Entities { id: MessageUnique.createMsg(peer, replyMsg ? replyMsg.msgId : records.msgId).toString() } } - } catch (e: any) { - ctx.logger.error('获取不到引用的消息', replyElement, e.stack) + } catch (e) { + ctx.logger.error('获取不到引用的消息', replyElement, (e as Error).stack) continue } } @@ -378,7 +378,7 @@ export namespace OB11Entities { if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) { //判断业务类型 //Poke事件 - const pokedetail: any[] = json.items + const pokedetail: Dict[] = json.items //筛选item带有uid的元素 const poke_uid = pokedetail.filter(item => item.uid) if (poke_uid.length == 2) { diff --git a/src/onebot11/helper/createMessage.ts b/src/onebot11/helper/createMessage.ts index 18ebd90..6ec850f 100644 --- a/src/onebot11/helper/createMessage.ts +++ b/src/onebot11/helper/createMessage.ts @@ -236,8 +236,7 @@ export async function sendMsg( ctx: Context, peer: Peer, sendElements: SendMessageElement[], - deleteAfterSentFiles: string[], - waitComplete = true, + deleteAfterSentFiles: string[] ) { if (!sendElements.length) { throw '消息体无法解析,请检查是否发送了不支持的消息类型' diff --git a/src/onebot11/helper/quickOperation.ts b/src/onebot11/helper/quickOperation.ts index c67d8f7..8127015 100644 --- a/src/onebot11/helper/quickOperation.ts +++ b/src/onebot11/helper/quickOperation.ts @@ -88,7 +88,7 @@ async function handleMsg(ctx: Context, msg: OB11Message, quickAction: QuickOpera } replyMessage = replyMessage.concat(convertMessage2List(reply, quickAction.auto_escape)) const { sendElements, deleteAfterSentFiles } = await createSendElements(ctx, replyMessage, peer) - sendMsg(ctx, peer, sendElements, deleteAfterSentFiles, false).catch(e => ctx.logger.error(e)) + sendMsg(ctx, peer, sendElements, deleteAfterSentFiles).catch(e => ctx.logger.error(e)) } if (msg.message_type === 'group') { const groupMsgQuickAction = quickAction as QuickOperationGroupMessage diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 685b606..17d16ac 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -1,7 +1,7 @@ import { CheckVersion, Config } from '../common/types' import { SettingButton, SettingItem, SettingList, SettingSwitch, SettingSelect } from './components' import { version } from '../version' -// @ts-expect-error +// @ts-expect-error: Unreachable code error import StyleRaw from './style.css?raw' type HostsType = 'httpHosts' | 'wsHosts' diff --git a/src/version.ts b/src/version.ts index b0be24c..79bfc7b 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '3.31.9' +export const version = '3.31.10'