From 9f35edf24cc71889f440f171b2efbec48795fa12 Mon Sep 17 00:00:00 2001 From: "Wesley F. Young" Date: Wed, 28 Aug 2024 19:27:31 +0800 Subject: [PATCH] feat: emit message/* events --- src/core/events.ts | 84 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/src/core/events.ts b/src/core/events.ts index dbdeb77b..7502fdaa 100644 --- a/src/core/events.ts +++ b/src/core/events.ts @@ -1,8 +1,19 @@ -import { FileElement, FriendRequest, GrayTipElement, GroupNotify, RawMessage } from '@/core/entities'; +import { + ChatType, + FileElement, + FriendRequest, + GrayTipElement, + GroupNotify, + RawMessage, + SendStatusType, +} from '@/core/entities'; import { NodeIKernelMsgListener } from '@/core/listeners'; import EventEmitter from 'node:events'; import TypedEmitter from 'typed-emitter/rxjs'; import { NapCatCore } from '@/core/index'; +import { MessageUnique } from '@/common/message-unique'; +import { LRUCache } from '@/common/lru-cache'; +import { proxiedListenerOf } from '@/common/proxy-handler'; type NapCatInternalEvents = { 'message/receive': (msg: RawMessage) => PromiseLike; @@ -18,7 +29,7 @@ type NapCatInternalEvents = { 'buddy/poke': (initiatorUin: string, targetUin: string, displayMsg: string, xMsg: RawMessage) => PromiseLike; - 'buddy/recall': (uin: string, messageId: string, + 'buddy/recall': (uin: string, internalMessageId: number, xMsg: RawMessage) => PromiseLike; 'buddy/input-status': (data: Parameters[0]) => PromiseLike; @@ -44,11 +55,11 @@ type NapCatInternalEvents = { 'group/member-decrease': (groupCode: string, targetUin: string, operatorUin: string, reason: 'leave' | 'kick' | 'unknown', xGrayTipElement: GrayTipElement, xMsg: RawMessage) => PromiseLike; - 'group/essence': (groupCode: string, messageId: string, senderUin: string, operation: 'add' | 'delete', + 'group/essence': (groupCode: string, internalMessageId: number, senderUin: string, operation: 'add' | 'delete', xGrayTipElement: GrayTipElement, xGrayTipSourceMsg: RawMessage /* this is not the message that is set to be essence msg */) => PromiseLike; - 'group/recall': (groupCode: string, operatorUin: string, messageId: string, + 'group/recall': (groupCode: string, operatorUin: string, internalMessageId: number, xGrayTipSourceMsg: RawMessage /* This is not the message that is recalled */) => PromiseLike; 'group/title': (groupCode: string, targetUin: string, newTitle: string, @@ -57,7 +68,7 @@ type NapCatInternalEvents = { 'group/upload': (groupCode: string, uploaderUin: string, fileElement: FileElement, xMsg: RawMessage) => PromiseLike; - 'group/emoji-like': (groupCode: string, operatorUin: string, messageId: string, likes: { emojiId: string, count: number }[], + 'group/emoji-like': (groupCode: string, operatorUin: string, internalMessageId: number, likes: { emojiId: string, count: number }[], // If it comes from onRecvMsg xGrayTipElement?: GrayTipElement, xMsg?: RawMessage, // If it comes from onRecvSysMsg @@ -74,5 +85,68 @@ export class NapCatEventChannel extends constructor(public core: NapCatCore) { super(); + + this.initMsgListener(); + } + + private initMsgListener() { + const msgListener = new NodeIKernelMsgListener(); + + msgListener.onRecvMsg = msgList => { + for (const msg of msgList) { + msg.id = MessageUnique.createUniqueMsgId( + { + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }, + msg.msgId, + ); + if (msg.senderUin !== this.core.selfInfo.uin) { + this.emit('message/receive', msg); + } + } + }; + + const msgIdSentCache = new LRUCache(100); + const recallMsgCache = new LRUCache(100); + msgListener.onMsgInfoListUpdate = async msgList => { + for (const msg of msgList) { + // Handle message recall + if (msg.recallTime !== '0' && !recallMsgCache.get(msg.msgId)) { + recallMsgCache.put(msg.msgId, true); + const originalMsgId = MessageUnique.getShortIdByMsgId(msg.msgId); + if (!originalMsgId) continue; + + if (msg.chatType === ChatType.KCHATTYPEC2C) { + this.emit('buddy/recall', msg.peerUin, originalMsgId, msg); + } else if (msg.chatType == ChatType.KCHATTYPEGROUP) { + let operatorId = msg.senderUin; + for (const element of msg.elements) { + const operatorUid = element.grayTipElement?.revokeElement.operatorUid; + if (!operatorUid) return; + const operator = await this.core.apis.GroupApi.getGroupMember(msg.peerUin, operatorUid); + operatorId = operator?.uin || msg.senderUin; + } + this.emit('group/recall', msg.peerUin, operatorId, originalMsgId, msg); + } + } + + // Handle message send + if (msg.sendStatus === SendStatusType.KSEND_STATUS_SUCCESS && !msgIdSentCache.get(msg.msgId)) { + msgIdSentCache.put(msg.msgId, true); + msg.id = MessageUnique.createUniqueMsgId({ + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }, msg.msgId); + this.emit('message/send', msg); + } + } + }; + + this.core.context.session.getMsgService().addKernelMsgListener( + proxiedListenerOf(msgListener, this.core.context.logger) as any, + ); } }