From e21c779d06171767dd996ce0ad4f823afa45f065 Mon Sep 17 00:00:00 2001 From: "Wesley F. Young" Date: Mon, 26 Aug 2024 12:02:41 +0800 Subject: [PATCH] refactor: enhanced type definition for `callNormalEvent` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类型体操,伟大,无需多言! --- src/common/framework/event-legacy.ts | 79 +++++++++++-------- src/core/apis/file.ts | 71 +++++++---------- src/core/apis/friend.ts | 5 +- src/core/apis/group.ts | 10 +-- src/core/apis/msg.ts | 109 ++++++++++++--------------- src/core/apis/user.ts | 8 +- src/core/listeners/index.ts | 25 ++++++ src/core/services/index.ts | 36 +++++++++ 8 files changed, 193 insertions(+), 150 deletions(-) diff --git a/src/common/framework/event-legacy.ts b/src/common/framework/event-legacy.ts index 470d0665..7cccc33d 100644 --- a/src/common/framework/event-legacy.ts +++ b/src/common/framework/event-legacy.ts @@ -1,5 +1,6 @@ import { NodeIQQNTWrapperSession } from '@/core/wrapper/wrapper'; import { randomUUID } from 'crypto'; +import { ListenerNamingMapping, ServiceNamingMapping } from '@/core'; interface InternalMapKey { timeout: number; @@ -145,12 +146,21 @@ export class LegacyNTEventWrapper { this.createListenerFunction(ListenerMainName); }); } - async CallNormalEventV2< - EventType extends (...args: any[]) => Promise, - ListenerType extends (...args: any[]) => void + + async callNormalEventV2< + Service extends keyof ServiceNamingMapping, + ServiceMethod extends Exclude, + Listener extends keyof ListenerNamingMapping, + ListenerMethod extends Exclude, + // eslint-disable-next-line + // @ts-ignore + EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod], + // eslint-disable-next-line + // @ts-ignore + ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod] >( - EventName = '', - ListenerName = '', + serviceAndMethod: `${Service}/${ServiceMethod}`, + listenerAndMethod: `${Listener}/${ListenerMethod}`, waitTimes = 1, timeout: number = 3000, checkerEvent: (ret: Awaited>) => boolean = () => true, @@ -163,14 +173,14 @@ export class LegacyNTEventWrapper { let complete = 0; let retData: Parameters | undefined = undefined; let retEvent: any = {}; - const databack = () => { + function sendDataCallback() { if (complete == 0) { reject( new Error( - 'Timeout: NTEvent EventName:' + - EventName + + 'Timeout: NTEvent serviceAndMethod:' + + serviceAndMethod + ' ListenerName:' + - ListenerName + + listenerAndMethod + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n', @@ -179,15 +189,15 @@ export class LegacyNTEventWrapper { } else { resolve([retEvent as Awaited>, ...retData!]); } - }; + } - const ListenerNameList = ListenerName.split('/'); + const ListenerNameList = listenerAndMethod.split('/'); const ListenerMainName = ListenerNameList[0]; const ListenerSubName = ListenerNameList[1]; - const Timeouter = setTimeout(databack, timeout); + const timeoutRef = setTimeout(sendDataCallback, timeout); - const eventCallbak = { + const eventCallback = { timeout: timeout, createtime: Date.now(), checker: checkerListener, @@ -195,8 +205,8 @@ export class LegacyNTEventWrapper { complete++; retData = args as Parameters; if (complete >= waitTimes) { - clearTimeout(Timeouter); - databack(); + clearTimeout(timeoutRef); + sendDataCallback(); } }, }; @@ -206,18 +216,18 @@ export class LegacyNTEventWrapper { 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.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback); this.createListenerFunction(ListenerMainName); - const EventFunc = this.createEventFunction(EventName); + const EventFunc = this.createEventFunction(serviceAndMethod); retEvent = await EventFunc!(...(args as any[])); if (!checkerEvent(retEvent)) { - clearTimeout(Timeouter); + clearTimeout(timeoutRef); reject( new Error( - 'EventChecker Failed: NTEvent EventName:' + - EventName + + 'EventChecker Failed: NTEvent serviceAndMethod:' + + serviceAndMethod + ' ListenerName:' + - ListenerName + + listenerAndMethod + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n', @@ -227,12 +237,21 @@ export class LegacyNTEventWrapper { }, ); } - async CallNormalEvent< - EventType extends (...args: any[]) => Promise, - ListenerType extends (...args: any[]) => void + + async callNormalEvent< + Service extends keyof ServiceNamingMapping, + ServiceMethod extends Exclude, + Listener extends keyof ListenerNamingMapping, + ListenerMethod extends Exclude, + // eslint-disable-next-line + // @ts-ignore + EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod], + // eslint-disable-next-line + // @ts-ignore + ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod] >( - EventName = '', - ListenerName = '', + serviceAndMethod: `${Service}/${ServiceMethod}`, + listenerAndMethod: `${Listener}/${ListenerMethod}`, waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters) => boolean, @@ -249,9 +268,9 @@ export class LegacyNTEventWrapper { reject( new Error( 'Timeout: NTEvent EventName:' + - EventName + + serviceAndMethod + ' ListenerName:' + - ListenerName + + listenerAndMethod + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n', @@ -262,7 +281,7 @@ export class LegacyNTEventWrapper { } }; - const ListenerNameList = ListenerName.split('/'); + const ListenerNameList = listenerAndMethod.split('/'); const ListenerMainName = ListenerNameList[0]; const ListenerSubName = ListenerNameList[1]; @@ -290,7 +309,7 @@ export class LegacyNTEventWrapper { } this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak); this.createListenerFunction(ListenerMainName); - const EventFunc = this.createEventFunction(EventName); + const EventFunc = this.createEventFunction(serviceAndMethod); retEvent = await EventFunc!(...(args as any[])); }, ); diff --git a/src/core/apis/file.ts b/src/core/apis/file.ts index 2afcf31f..b3a39b2d 100644 --- a/src/core/apis/file.ts +++ b/src/core/apis/file.ts @@ -304,66 +304,49 @@ export class NTQQFileApi { return sourcePath; } } - const data = await this.core.eventWrapper.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; - }, - { - fileModelId: '0', - downloadSourceType: 0, - triggerType: 1, - msgId: msgId, - chatType: chatType, - peerUid: peerUid, - elementId: elementId, - thumbSize: 0, - downloadType: 1, - filePath: thumbPath, - }, - ); + const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEvent( + 'NodeIKernelMsgService/downloadRichMedia', + 'NodeIKernelMsgListener/onRichMediaDownloadComplete', + 1, + timeout, + (arg: OnRichMediaDownloadCompleteParams) => { + if (arg.msgId === msgId) { + return true; + } + return false; + }, + { + fileModelId: '0', + downloadSourceType: 0, + triggerType: 1, + msgId: msgId, + chatType: chatType, + peerUid: peerUid, + elementId: elementId, + thumbSize: 0, + downloadType: 1, + filePath: thumbPath, + }, + ); const msg = await this.core.apis.MsgApi.getMsgsByMsgId({ guildId: '', chatType: chatType, peerUid: peerUid, }, [msgId]); if (msg.msgList.length === 0) { - return data[1].filePath; + return fileTransNotifyInfo.filePath; } //获取原始消息 const FileElements = msg?.msgList[0]?.elements?.find(e => e.elementId === elementId); if (!FileElements) { //失败则就乱来 Todo - return data[1].filePath; + return fileTransNotifyInfo.filePath; } //从原始消息获取文件路径 - const filePath = - FileElements?.fileElement?.filePath ?? + return FileElements?.fileElement?.filePath ?? FileElements?.pttElement?.filePath ?? FileElements?.videoElement?.filePath ?? FileElements?.picElement?.sourcePath; - return filePath; } async getImageSize(filePath: string): Promise { diff --git a/src/core/apis/friend.ts b/src/core/apis/friend.ts index 7bd6047e..69e5a366 100644 --- a/src/core/apis/friend.ts +++ b/src/core/apis/friend.ts @@ -74,10 +74,7 @@ export class NTQQFriendApi { return this.context.session.getBuddyService().clearBuddyReqUnreadCnt(); } async getBuddyReq() { - const [, ret] = await this.core.eventWrapper.CallNormalEventV2< - NodeIKernelBuddyService['getBuddyReq'], - NodeIKernelBuddyListener['onBuddyReqChange'] - >( + const [, ret] = await this.core.eventWrapper.callNormalEventV2( 'NodeIKernelBuddyService/getBuddyReq', 'NodeIKernelBuddyListener/onBuddyReqChange', 1, diff --git a/src/core/apis/group.ts b/src/core/apis/group.ts index 9771c5f3..97c90f11 100644 --- a/src/core/apis/group.ts +++ b/src/core/apis/group.ts @@ -43,15 +43,14 @@ export class NTQQGroupApi { async getGroups(forced = false) { type ListenerType = NodeIKernelGroupListener['onGroupListUpdate']; - const [_retData, _updateType, groupList] = await this.core.eventWrapper.CallNormalEvent<(force: boolean) => Promise, ListenerType> - ( + const [,, groupList] = await this.core.eventWrapper.callNormalEvent( 'NodeIKernelGroupService/getGroupList', 'NodeIKernelGroupListener/onGroupListUpdate', 1, 5000, () => true, forced, - ); + ); return groupList; } @@ -255,8 +254,7 @@ export class NTQQGroupApi { } async getSingleScreenNotifies(num: number) { - const [_retData, _doubt, _seq, notifies] = await this.core.eventWrapper.CallNormalEvent<(arg1: boolean, arg2: string, arg3: number) => Promise, (doubt: boolean, seq: string, notifies: GroupNotify[]) => void> - ( + const [,,, notifies] = await this.core.eventWrapper.callNormalEvent( 'NodeIKernelGroupService/getSingleScreenNotifies', 'NodeIKernelGroupListener/onGroupSingleScreenNotifies', 1, @@ -265,7 +263,7 @@ export class NTQQGroupApi { false, '', num, - ); + ); return notifies; } diff --git a/src/core/apis/msg.ts b/src/core/apis/msg.ts index b844068f..2348f5a1 100644 --- a/src/core/apis/msg.ts +++ b/src/core/apis/msg.ts @@ -1,6 +1,5 @@ import { ChatType, GetFileListParam, Peer, RawMessage, SendMessageElement, SendStatusType } from '@/core/entities'; import { InstanceContext, NapCatCore } from '@/core'; -import { GroupFileInfoUpdateParamType } from '@/core/listeners'; import { GeneralCallResult } from '@/core/services/common'; export class NTQQMsgApi { @@ -117,22 +116,19 @@ export class NTQQMsgApi { } async getGroupFileList(GroupCode: string, params: GetFileListParam) { - const data = await this.core.eventWrapper.CallNormalEvent< - (GroupCode: string, params: GetFileListParam) => Promise, - (groupFileListResult: GroupFileInfoUpdateParamType) => void - >( - 'NodeIKernelRichMediaService/getGroupFileList', - 'NodeIKernelMsgListener/onGroupFileInfoUpdate', - 1, - 5000, - (groupFileListResult: GroupFileInfoUpdateParamType) => { + const [, groupFileListResult] = await this.core.eventWrapper.callNormalEvent( + 'NodeIKernelRichMediaService/getGroupFileList', + 'NodeIKernelMsgListener/onGroupFileInfoUpdate', + 1, + 5000, + ( /* groupFileListResult: GroupFileInfoUpdateParamType */) => { //Developer Mlikiowa Todo: 此处有问题 无法判断是否成功 - return true; - }, - GroupCode, - params, - ); - return data[1].item; + return true; + }, + GroupCode, + params, + ); + return groupFileListResult.item; } async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) { @@ -179,33 +175,29 @@ export class NTQQMsgApi { } const msgId = await this.generateMsgUniqueId(peer.chatType, await this.getServerTime()); peer.guildId = msgId; - const data = await this.core.eventWrapper.CallNormalEvent< - (msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map) => Promise, - (msgList: RawMessage[]) => void - >( - 'NodeIKernelMsgService/sendMsg', - 'NodeIKernelMsgListener/onMsgInfoListUpdate', - 1, - timeout, - (msgRecords: RawMessage[]) => { - for (const msgRecord of msgRecords) { - if (msgRecord.guildId === msgId && msgRecord.sendStatus === SendStatusType.KSEND_STATUS_SUCCESS) { - return true; - } + const [, msgList] = await this.core.eventWrapper.callNormalEvent( + 'NodeIKernelMsgService/sendMsg', + 'NodeIKernelMsgListener/onMsgInfoListUpdate', + 1, + timeout, + (msgRecords: RawMessage[]) => { + for (const msgRecord of msgRecords) { + if (msgRecord.guildId === msgId && msgRecord.sendStatus === SendStatusType.KSEND_STATUS_SUCCESS) { + return true; } - return false; - }, - '0', - peer, - msgElements, - new Map(), - ); - const retMsg = data[1].find(msgRecord => { + } + return false; + }, + '0', + peer, + msgElements, + new Map(), + ); + return msgList.find(msgRecord => { if (msgRecord.guildId === msgId) { return true; } }); - return retMsg; } async generateMsgUniqueId(chatType: number, time: string) { @@ -224,29 +216,26 @@ export class NTQQMsgApi { const msgInfos = msgIds.map(id => { return { msgId: id, senderShowName: this.core.selfInfo.nick }; }); - const data = await this.core.eventWrapper.CallNormalEvent< - (msgInfo: typeof msgInfos, srcPeer: Peer, destPeer: Peer, comment: Array, attr: Map) => Promise, - (msgList: RawMessage[]) => void - >( - 'NodeIKernelMsgService/multiForwardMsgWithComment', - 'NodeIKernelMsgListener/onMsgInfoListUpdate', - 1, - 5000, - (msgRecords: RawMessage[]) => { - for (const msgRecord of msgRecords) { - if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) { - return true; - } + const [, msgList] = await this.core.eventWrapper.callNormalEvent( + 'NodeIKernelMsgService/multiForwardMsgWithComment', + 'NodeIKernelMsgListener/onMsgInfoListUpdate', + 1, + 5000, + (msgRecords: RawMessage[]) => { + for (const msgRecord of msgRecords) { + if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) { + return true; } - return false; - }, - msgInfos, - srcPeer, - destPeer, - [], - new Map(), - ); - for (const msg of data[1]) { + } + return false; + }, + msgInfos, + srcPeer, + destPeer, + [], + new Map(), + ); + for (const msg of msgList) { const arkElement = msg.elements.find(ele => ele.arkElement); if (!arkElement) { continue; diff --git a/src/core/apis/user.ts b/src/core/apis/user.ts index 81dfc6ca..06adf7fb 100644 --- a/src/core/apis/user.ts +++ b/src/core/apis/user.ts @@ -69,9 +69,7 @@ export class NTQQUserApi { type EventService = NodeIKernelProfileService['fetchUserDetailInfo']; type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged']; const retData: User[] = []; - const [_retData, _retListener] = await this.core.eventWrapper.CallNormalEvent< - EventService, EventListener - >( + const [_retData, _retListener] = await this.core.eventWrapper.callNormalEvent( 'NodeIKernelProfileService/fetchUserDetailInfo', 'NodeIKernelProfileListener/onUserDetailInfoChanged', uids.length, @@ -102,9 +100,7 @@ export class NTQQUserApi { } async fetchUserDetailInfo(uid: string, mode: UserDetailSource = UserDetailSource.KDB) { - type EventService = NodeIKernelProfileService['fetchUserDetailInfo']; - type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged']; - const [_retData, profile] = await this.core.eventWrapper.CallNormalEvent( + const [_retData, profile] = await this.core.eventWrapper.callNormalEvent( 'NodeIKernelProfileService/fetchUserDetailInfo', 'NodeIKernelProfileListener/onUserDetailInfoChanged', 1, diff --git a/src/core/listeners/index.ts b/src/core/listeners/index.ts index ad8c7ca1..4bdee0a6 100644 --- a/src/core/listeners/index.ts +++ b/src/core/listeners/index.ts @@ -10,3 +10,28 @@ export * from './NodeIKernelTicketListener'; export * from './NodeIKernelStorageCleanListener'; export * from './NodeIKernelFileAssistantListener'; +import type { + NodeIKernelSessionListener, + NodeIKernelLoginListener, + NodeIKernelMsgListener, + NodeIKernelGroupListener, + NodeIKernelBuddyListener, + NodeIKernelProfileListener, + NodeIKernelRobotListener, + NodeIKernelTicketListener, + NodeIKernelStorageCleanListener, + NodeIKernelFileAssistantListener, +} from '.'; + +export type ListenerNamingMapping = { + NodeIKernelSessionListener: NodeIKernelSessionListener; + NodeIKernelLoginListener: NodeIKernelLoginListener; + NodeIKernelMsgListener: NodeIKernelMsgListener; + NodeIKernelGroupListener: NodeIKernelGroupListener; + NodeIKernelBuddyListener: NodeIKernelBuddyListener; + NodeIKernelProfileListener: NodeIKernelProfileListener; + NodeIKernelRobotListener: NodeIKernelRobotListener; + NodeIKernelTicketListener: NodeIKernelTicketListener; + NodeIKernelStorageCleanListener: NodeIKernelStorageCleanListener; + NodeIKernelFileAssistantListener: NodeIKernelFileAssistantListener; +}; diff --git a/src/core/services/index.ts b/src/core/services/index.ts index b17c49bd..bd9d015e 100644 --- a/src/core/services/index.ts +++ b/src/core/services/index.ts @@ -14,3 +14,39 @@ export * from './NodeIKernelRobotService'; export * from './NodeIKernelRichMediaService'; export * from './NodeIKernelDbToolsService'; export * from './NodeIKernelTipOffService'; + +import type { + NodeIKernelAvatarService, + NodeIKernelBuddyService, + NodeIKernelDbToolsService, + NodeIKernelFileAssistantService, + NodeIKernelGroupService, + NodeIKernelLoginService, + NodeIKernelMsgService, + NodeIKernelOnlineStatusService, + NodeIKernelProfileLikeService, + NodeIKernelProfileService, + NodeIKernelRichMediaService, + NodeIKernelRobotService, + NodeIKernelStorageCleanService, + NodeIKernelTicketService, + NodeIKernelTipOffService, +} from '.'; + +export type ServiceNamingMapping = { + NodeIKernelAvatarService: NodeIKernelAvatarService; + NodeIKernelBuddyService: NodeIKernelBuddyService; + NodeIKernelFileAssistantService: NodeIKernelFileAssistantService; + NodeIKernelGroupService: NodeIKernelGroupService; + NodeIKernelLoginService: NodeIKernelLoginService; + NodeIKernelMsgService: NodeIKernelMsgService; + NodeIKernelOnlineStatusService: NodeIKernelOnlineStatusService; + NodeIKernelProfileLikeService: NodeIKernelProfileLikeService; + NodeIKernelProfileService: NodeIKernelProfileService; + NodeIKernelTicketService: NodeIKernelTicketService; + NodeIKernelStorageCleanService: NodeIKernelStorageCleanService; + NodeIKernelRobotService: NodeIKernelRobotService; + NodeIKernelRichMediaService: NodeIKernelRichMediaService; + NodeIKernelDbToolsService: NodeIKernelDbToolsService; + NodeIKernelTipOffService: NodeIKernelTipOffService; +};