mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
refactor
This commit is contained in:
@@ -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<string, ListenerClassBase> = new Map<string, ListenerClassBase>() //ListenerName-Unique -> Listener实例
|
||||
private EventTask = new Map<string, Map<string, Map<string, Internal_MapKey>>>()//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<T extends (...args: any) => unknown>(eventName: string): T | undefined {
|
||||
const eventNameArr = eventName.split('/')
|
||||
type eventType = {
|
||||
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }
|
||||
}
|
||||
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<T>(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<EventType extends (...args: any[]) => Promise<any>>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||
const EventFunc = this.createEventFunction<EventType>(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<ListenerType extends (...args: any[]) => void>(ListenerName = '', waitTimes = 1, timeout = 5000, checker: (...args: Parameters<ListenerType>) => boolean) {
|
||||
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||
const ListenerNameList = ListenerName.split('/')
|
||||
const ListenerMainName = ListenerNameList[0]
|
||||
const ListenerSubName = ListenerNameList[1]
|
||||
const id = randomUUID()
|
||||
let complete = 0
|
||||
let retData: Parameters<ListenerType> | 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<ListenerType>) => {
|
||||
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<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>
|
||||
(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters<ListenerType>) => boolean, ...args: Parameters<EventType>) {
|
||||
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
||||
const id = randomUUID()
|
||||
let complete = 0
|
||||
let retData: Parameters<ListenerType> | 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<ReturnType<EventType>>, ...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<ListenerType>
|
||||
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<EventType>(EventName)
|
||||
retEvent = await EventFunc!(...args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const NTEventDispatch = new NTEventWrapper()
|
||||
|
||||
// 示例代码 快速创建事件
|
||||
// let NTEvent = new NTEventWrapper()
|
||||
// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise<Number>>('NodeIKernelProfileLikeService/GetTest')
|
||||
// if (TestEvent) {
|
||||
// TestEvent(true)
|
||||
// }
|
||||
|
||||
// 示例代码 快速创建监听Listener类
|
||||
// let NTEvent = new NTEventWrapper()
|
||||
// NTEvent.CreatListenerFunction<NodeIKernelMsgListener>('NodeIKernelMsgListener', 'core')
|
||||
|
||||
|
||||
// 调用接口
|
||||
//let NTEvent = new NTEventWrapper()
|
||||
//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise<Number>, (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) })
|
@@ -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<unknown>,
|
||||
(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')
|
||||
|
@@ -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'
|
||||
|
||||
@@ -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']>(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||
)
|
||||
const data = await session.getProfileService().getCoreAndBaseInfo('nodeStore', uids)
|
||||
return Array.from(data.values())
|
||||
} else {
|
||||
const data = await invoke<{
|
||||
@@ -106,12 +103,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']>(
|
||||
'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 +150,7 @@ export class NTQQFriendApi extends Service {
|
||||
})
|
||||
return item.buddyUids
|
||||
}))
|
||||
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||
'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
|
||||
|
@@ -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'
|
||||
|
@@ -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}`)
|
||||
|
Reference in New Issue
Block a user