diff --git a/src/onebot/api/group.ts b/src/onebot/api/group.ts index bd3300d4..edb1bd8f 100644 --- a/src/onebot/api/group.ts +++ b/src/onebot/api/group.ts @@ -1,10 +1,12 @@ import { ChatType, GrayTipElement, + InstanceContext, JsonGrayBusiId, NapCatCore, NTGrayTipElementSubTypeV2, RawMessage, + TipGroupElement, TipGroupElementType, } from '@/core'; import { NapCatOneBot11Adapter } from '@/onebot'; @@ -15,13 +17,10 @@ import fastXmlParser from 'fast-xml-parser'; import { OB11GroupMsgEmojiLikeEvent } from '@/onebot/event/notice/OB11MsgEmojiLikeEvent'; import { MessageUnique } from '@/common/message-unique'; import { OB11GroupCardEvent } from '@/onebot/event/notice/OB11GroupCardEvent'; -import { OB11GroupUploadNoticeEvent } from '@/onebot/event/notice/OB11GroupUploadNoticeEvent'; import { OB11GroupPokeEvent } from '@/onebot/event/notice/OB11PokeEvent'; import { OB11GroupEssenceEvent } from '@/onebot/event/notice/OB11GroupEssenceEvent'; import { OB11GroupTitleEvent } from '@/onebot/event/notice/OB11GroupTitleEvent'; -import { FileNapCatOneBotUUID } from '@/common/helper'; -import { pathToFileURL } from 'node:url'; - +import { OB11EmitEventContent } from '../network'; export class OneBotGroupApi { obContext: NapCatOneBot11Adapter; @@ -32,137 +31,6 @@ export class OneBotGroupApi { this.core = core; } - async parseGroupEvent(msg: RawMessage) { - const logger = this.core.context.logger; - if (msg.chatType !== ChatType.KCHATTYPEGROUP) { - return; - } - //log("group msg", msg); - if (msg.senderUin && msg.senderUin !== '0') { - const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin); - if (member && member.cardName !== msg.sendMemberName) { - const newCardName = msg.sendMemberName ?? ''; - const event = new OB11GroupCardEvent(this.core, parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName); - member.cardName = newCardName; - return event; - } - } - - for (const element of msg.elements) { - if (element.grayTipElement?.groupElement) { - const groupElement = element.grayTipElement.groupElement; - if (groupElement.type == TipGroupElementType.KMEMBERADD) { - const MemberIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupMemberIncreaseEvent(msg.peerUid, element.grayTipElement); - if (MemberIncreaseEvent) return MemberIncreaseEvent; - } else if (groupElement.type === TipGroupElementType.KSHUTUP) { - const BanEvent = await this.obContext.apis.GroupApi.parseGroupBanEvent(msg.peerUid, element.grayTipElement); - if (BanEvent) return BanEvent; - } else if (groupElement.type == TipGroupElementType.KQUITTE) { - this.core.apis.GroupApi.quitGroup(msg.peerUid).then(); - try { - const KickEvent = await this.obContext.apis.GroupApi.parseGroupKickEvent(msg.peerUid, element.grayTipElement); - if (KickEvent) return KickEvent; - } catch (e) { - return new OB11GroupDecreaseEvent( - this.core, - parseInt(msg.peerUid), - parseInt(this.core.selfInfo.uin), - 0, - 'leave', - ); - } - } - } else if (element.fileElement) { - return new OB11GroupUploadNoticeEvent( - this.core, - parseInt(msg.peerUid), parseInt(msg.senderUin || ''), - { - id: FileNapCatOneBotUUID.encode({ - chatType: ChatType.KCHATTYPEGROUP, - peerUid: msg.peerUid, - }, msg.msgId, element.elementId, element.fileElement.fileUuid, "." + element.fileElement.fileName), - url: pathToFileURL(element.fileElement.filePath).href, - name: element.fileElement.fileName, - size: parseInt(element.fileElement.fileSize), - busid: element.fileElement.fileBizId ?? 0, - }, - ); - } - if (element.grayTipElement) { - if (element.grayTipElement.xmlElement?.templId === '10382') { - const emojiLikeEvent = await this.obContext.apis.GroupApi.parseGroupEmojiLikeEventByGrayTip(msg.peerUid, element.grayTipElement); - if (emojiLikeEvent) return emojiLikeEvent; - } - if (element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_XMLMSG) { - const GroupIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupIncreaseEvent(msg.peerUid, element.grayTipElement); - if (GroupIncreaseEvent) return GroupIncreaseEvent; - } - - else if (element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) { - const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr); - if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) { - //判断业务类型 - //Poke事件 - const pokedetail: any[] = json.items; - //筛选item带有uid的元素 - const poke_uid = pokedetail.filter(item => item.uid); - if (poke_uid.length == 2) { - return new OB11GroupPokeEvent( - this.core, - parseInt(msg.peerUid), - +await this.core.apis.UserApi.getUinByUidV2(poke_uid[0].uid), - +await this.core.apis.UserApi.getUinByUidV2(poke_uid[1].uid), - pokedetail, - ); - } - } - if (element.grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.AIO_GROUP_ESSENCE_MSG_TIP) { - const searchParams = new URL(json.items[0].jp).searchParams; - const msgSeq = searchParams.get('msgSeq')!; - const Group = searchParams.get('groupCode'); - if (!Group) return; - // const businessId = searchParams.get('businessid'); - const Peer = { - guildId: '', - chatType: ChatType.KCHATTYPEGROUP, - peerUid: Group, - }; - const msgData = await this.core.apis.MsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true); - const msgList = (await this.core.apis.WebApi.getGroupEssenceMsgAll(Group)).flatMap((e) => e.data.msg_list); - const realMsg = msgList.find((e) => e.msg_seq.toString() == msgSeq); - return new OB11GroupEssenceEvent( - this.core, - parseInt(msg.peerUid), - MessageUnique.getShortIdByMsgId(msgData.msgList[0].msgId)!, - parseInt(msgData.msgList[0].senderUin), - parseInt(realMsg?.add_digest_uin ?? '0'), - ); - // 获取MsgSeq+Peer可获取具体消息 - } - if (element.grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.GROUP_AIO_CONFIGURABLE_GRAY_TIPS) { - const type = json.items[json.items.length - 1]?.txt; - if (type === "头衔") { - const memberUin = json.items[1].param[0]; - const title = json.items[3].txt; - logger.logDebug('收到群成员新头衔消息', json); - return new OB11GroupTitleEvent( - this.core, - parseInt(msg.peerUid), - parseInt(memberUin), - title, - ); - } else if (type === "移出") { - logger.logDebug('收到机器人被踢消息', json); - return; - } else { - logger.logWarn('收到未知的灰条消息', json); - } - } - } - } - } - } - async parseGroupBanEvent(GroupCode: string, grayTipElement: GrayTipElement) { const groupElement = grayTipElement?.groupElement; if (!groupElement?.shutUp) return undefined; @@ -300,4 +168,176 @@ export class OneBotGroupApi { }], ); } + async parseCardChangedEvent(msg: RawMessage) { + if (msg.senderUin && msg.senderUin !== '0') { + const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin); + if (member && member.cardName !== msg.sendMemberName) { + const newCardName = msg.sendMemberName ?? ''; + const event = new OB11GroupCardEvent(this.core, parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName); + member.cardName = newCardName; + return event; + } + } + return undefined; + } + + async parseGroupElement(msg: RawMessage, groupElement: TipGroupElement, elementWrapper: GrayTipElement) { + if (groupElement.type == TipGroupElementType.KMEMBERADD) { + const MemberIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupMemberIncreaseEvent(msg.peerUid, elementWrapper); + if (MemberIncreaseEvent) return MemberIncreaseEvent; + } else if (groupElement.type === TipGroupElementType.KSHUTUP) { + const BanEvent = await this.obContext.apis.GroupApi.parseGroupBanEvent(msg.peerUid, elementWrapper); + if (BanEvent) return BanEvent; + } else if (groupElement.type == TipGroupElementType.KQUITTE) { + this.core.apis.GroupApi.quitGroup(msg.peerUid).then(); + try { + const KickEvent = await this.obContext.apis.GroupApi.parseGroupKickEvent(msg.peerUid, elementWrapper); + if (KickEvent) return KickEvent; + } catch (e) { + return new OB11GroupDecreaseEvent( + this.core, + parseInt(msg.peerUid), + parseInt(this.core.selfInfo.uin), + 0, + 'leave', + ); + } + } + return undefined; + } + + async parsePaiYiPai(msg: RawMessage, jsonStr: string) { + const json = JSON.parse(jsonStr); + + //判断业务类型 + //Poke事件 + const pokedetail: any[] = json.items; + //筛选item带有uid的元素 + const poke_uid = pokedetail.filter(item => item.uid); + if (poke_uid.length == 2) { + return new OB11GroupPokeEvent( + this.core, + parseInt(msg.peerUid), + +await this.core.apis.UserApi.getUinByUidV2(poke_uid[0].uid), + +await this.core.apis.UserApi.getUinByUidV2(poke_uid[1].uid), + pokedetail, + ); + } + return undefined; + } + + async parseOtherJsonEvent(msg: RawMessage, jsonStr: string, context: InstanceContext) { + const json = JSON.parse(jsonStr); + const type = json.items[json.items.length - 1]?.txt; + if (type === "头衔") { + const memberUin = json.items[1].param[0]; + const title = json.items[3].txt; + context.logger.logDebug('收到群成员新头衔消息', json); + return new OB11GroupTitleEvent( + this.core, + parseInt(msg.peerUid), + parseInt(memberUin), + title, + ); + } else if (type === "移出") { + context.logger.logDebug('收到机器人被踢消息', json); + return; + } else { + context.logger.logWarn('收到未知的灰条消息', json); + } + } + + async parseEssenceMsg(msg: RawMessage, jsonStr: string) { + const json = JSON.parse(jsonStr); + const searchParams = new URL(json.items[0].jp).searchParams; + const msgSeq = searchParams.get('msgSeq')!; + const Group = searchParams.get('groupCode'); + if (!Group) return; + // const businessId = searchParams.get('businessid'); + const Peer = { + guildId: '', + chatType: ChatType.KCHATTYPEGROUP, + peerUid: Group, + }; + const msgData = await this.core.apis.MsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true); + const msgList = (await this.core.apis.WebApi.getGroupEssenceMsgAll(Group)).flatMap((e) => e.data.msg_list); + const realMsg = msgList.find((e) => e.msg_seq.toString() == msgSeq); + return new OB11GroupEssenceEvent( + this.core, + parseInt(msg.peerUid), + MessageUnique.getShortIdByMsgId(msgData.msgList[0].msgId)!, + parseInt(msgData.msgList[0].senderUin), + parseInt(realMsg?.add_digest_uin ?? '0'), + ); + // 获取MsgSeq+Peer可获取具体消息 + } + + // async parseGroupUploadFileEvene() { + // return new OB11GroupUploadNoticeEvent( + // this.core, + // parseInt(msg.peerUid), parseInt(msg.senderUin || ''), + // { + // id: FileNapCatOneBotUUID.encode({ + // chatType: ChatType.KCHATTYPEGROUP, + // peerUid: msg.peerUid, + // }, msg.msgId, element.elementId, element.fileElement.fileUuid, "." + element.fileElement.fileName), + // url: pathToFileURL(element.fileElement.filePath).href, + // name: element.fileElement.fileName, + // size: parseInt(element.fileElement.fileSize), + // busid: element.fileElement.fileBizId ?? 0, + // }, + // ); + // } + + async parseGrayTipElement(msg: RawMessage, grayTipElement: GrayTipElement) { + let events: Array = []; + + // 群名片修改事件解析 + + const cardChangedEvent = await this.parseCardChangedEvent(msg); + if (cardChangedEvent) { + events.push(cardChangedEvent); + } + + // 解析群组事件 + if (grayTipElement.groupElement) { + const groupEvent = await this.parseGroupElement(msg, grayTipElement.groupElement, grayTipElement); + if (groupEvent) { + events.push(groupEvent); + } + } + + if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_XMLMSG) { + // 筛选出表情回应 事件 + if (grayTipElement.xmlElement?.templId === '10382') { + const emojiLikeEvent = await this.obContext.apis.GroupApi.parseGroupEmojiLikeEventByGrayTip(msg.peerUid, grayTipElement); + if (emojiLikeEvent) { + events.push(emojiLikeEvent); + } + } else { + const GroupIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupIncreaseEvent(msg.peerUid, grayTipElement); + if (GroupIncreaseEvent) { + events.push(GroupIncreaseEvent); + } + } + } else if (grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) { + if (grayTipElement.jsonGrayTipElement.busiId == 1061) { + const paiYiPaiEvent = await this.parsePaiYiPai(msg, grayTipElement.jsonGrayTipElement.jsonStr); + if (paiYiPaiEvent) { + events.push(paiYiPaiEvent); + } + } else if (grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.AIO_GROUP_ESSENCE_MSG_TIP) { + const essenceMsgEvent = await this.parseEssenceMsg(msg, grayTipElement.jsonGrayTipElement.jsonStr); + if (essenceMsgEvent) { + events.push(essenceMsgEvent); + } + } else { + const otherJsonEvent = await this.parseOtherJsonEvent(msg, grayTipElement.jsonGrayTipElement.jsonStr, this.core.context) + if (otherJsonEvent) { + events.push(otherJsonEvent); + } + } + } + return events; + } } diff --git a/src/onebot/index.ts b/src/onebot/index.ts index 0eb5bdfc..56a853af 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -527,8 +527,11 @@ export class NapCatOneBot11Adapter { const network = Object.values(this.configLoader.configData.network).flat() as Array; this.context.logger.logDebug('收到新消息 RawMessage', message); await this.handleMsg(message, network); - await this.handleGroupEvent(message); - await this.handlePrivateMsgEvent(message); + if (message.chatType == ChatType.KCHATTYPEGROUP) { + await this.handleGroupEvent(message); + } else { + await this.handlePrivateMsgEvent(message); + } } private async handleMsg(message: RawMessage, network: Array) { try { @@ -597,10 +600,10 @@ export class NapCatOneBot11Adapter { private async handleGroupEvent(message: RawMessage) { try { - const groupEvent = await this.apis.GroupApi.parseGroupEvent(message); - if (groupEvent) { - this.networkManager.emitEvent(groupEvent); - } + const grayTipElement = message.elements.find((element) => element.grayTipElement)?.grayTipElement; + if (!grayTipElement) return; + const events = await this.apis.GroupApi.parseGrayTipElement(message, grayTipElement); + await this.networkManager.emitEvents(events); } catch (e) { this.context.logger.logError('constructGroupEvent error: ', e); } diff --git a/src/onebot/network/index.ts b/src/onebot/network/index.ts index 5663f241..cbe1140b 100644 --- a/src/onebot/network/index.ts +++ b/src/onebot/network/index.ts @@ -37,6 +37,10 @@ export class OB11NetworkManager { return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.onEvent(event))); } + async emitEvents(events: OB11EmitEventContent[]) { + return Promise.all(events.map(event => this.emitEvent(event))); + } + async emitEventByName(names: string[], event: OB11EmitEventContent) { return Promise.all(names.map(name => { const adapter = this.adapters.get(name); @@ -71,7 +75,7 @@ export class OB11NetworkManager { async closeSomeAdaterWhenOpen(adaptersToClose: IOB11NetworkAdapter[]) { for (const adapter of adaptersToClose) { this.adapters.delete(adapter.name); - if(adapter.isEnable){ + if (adapter.isEnable) { await adapter.close(); } }