mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Merge branch 'main' into pr/567
This commit is contained in:
@@ -255,7 +255,7 @@ export class NodeIKernelMsgListener {
|
||||
|
||||
}
|
||||
|
||||
onMsgRecall(i2: unknown, str: unknown, j2: unknown): any {
|
||||
onMsgRecall(chatType: ChatType, uid: string, msgSeq: string): any {
|
||||
|
||||
}
|
||||
|
||||
|
@@ -40,17 +40,18 @@ export interface FaceElement {
|
||||
surpriseId?: string;
|
||||
randomType?: number;
|
||||
}
|
||||
|
||||
export interface GrayTipElement {
|
||||
subElementType: NTGrayTipElementSubTypeV2;
|
||||
revokeElement: {
|
||||
export interface GrayTipRovokeElement {
|
||||
operatorRole: string;
|
||||
operatorUid: string;
|
||||
operatorNick: string;
|
||||
operatorRemark: string;
|
||||
operatorMemRemark?: string;
|
||||
wording: string; // 自定义的撤回提示语
|
||||
};
|
||||
}
|
||||
|
||||
export interface GrayTipElement {
|
||||
subElementType: NTGrayTipElementSubTypeV2;
|
||||
revokeElement: GrayTipRovokeElement;
|
||||
aioOpGrayTipElement: TipAioOpGrayTipElement;
|
||||
groupElement: TipGroupElement;
|
||||
xmlElement: {
|
||||
|
@@ -1,10 +1,15 @@
|
||||
import {
|
||||
ChatType,
|
||||
FileElement,
|
||||
GrayTipElement,
|
||||
InstanceContext,
|
||||
JsonGrayBusiId,
|
||||
MessageElement,
|
||||
NapCatCore,
|
||||
NTGrayTipElementSubTypeV2,
|
||||
NTMsgType,
|
||||
RawMessage,
|
||||
TipGroupElement,
|
||||
TipGroupElementType,
|
||||
} from '@/core';
|
||||
import { NapCatOneBot11Adapter } from '@/onebot';
|
||||
@@ -15,13 +20,13 @@ 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 { OB11EmitEventContent } from '../network';
|
||||
import { OB11GroupUploadNoticeEvent } from '../event/notice/OB11GroupUploadNoticeEvent';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||
|
||||
export class OneBotGroupApi {
|
||||
obContext: NapCatOneBot11Adapter;
|
||||
@@ -32,137 +37,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 +174,151 @@ 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(msg: RawMessage, element: FileElement, elementWrapper: MessageElement) {
|
||||
return new OB11GroupUploadNoticeEvent(
|
||||
this.core,
|
||||
parseInt(msg.peerUid), parseInt(msg.senderUin || ''),
|
||||
{
|
||||
id: FileNapCatOneBotUUID.encode({
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
peerUid: msg.peerUid,
|
||||
}, msg.msgId, elementWrapper.elementId, elementWrapper?.fileElement?.fileUuid, "." + element.fileName),
|
||||
url: pathToFileURL(element.filePath).href,
|
||||
name: element.fileName,
|
||||
size: parseInt(element.fileSize),
|
||||
busid: element.fileBizId ?? 0,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async parseGrayTipElement(msg: RawMessage, grayTipElement: GrayTipElement) {
|
||||
if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_GROUP) {
|
||||
// 解析群组事件
|
||||
return await this.parseGroupElement(msg, grayTipElement.groupElement, grayTipElement);
|
||||
|
||||
} else if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_XMLMSG) {
|
||||
// 筛选出表情回应 事件
|
||||
if (grayTipElement.xmlElement?.templId === '10382') {
|
||||
return await this.obContext.apis.GroupApi.parseGroupEmojiLikeEventByGrayTip(msg.peerUid, grayTipElement);
|
||||
|
||||
} else {
|
||||
return await this.obContext.apis.GroupApi.parseGroupIncreaseEvent(msg.peerUid, grayTipElement);
|
||||
}
|
||||
} else if (grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
|
||||
// 解析json事件
|
||||
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||
return await this.parsePaiYiPai(msg, grayTipElement.jsonGrayTipElement.jsonStr);
|
||||
} else if (grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.AIO_GROUP_ESSENCE_MSG_TIP) {
|
||||
return await this.parseEssenceMsg(msg, grayTipElement.jsonGrayTipElement.jsonStr);
|
||||
} else {
|
||||
return await this.parseOtherJsonEvent(msg, grayTipElement.jsonGrayTipElement.jsonStr, this.core.context)
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import {
|
||||
SendTextElement,
|
||||
BaseEmojiType,
|
||||
FaceType,
|
||||
GrayTipElement,
|
||||
} from '@/core';
|
||||
import faceConfig from '@/core/external/face_config.json';
|
||||
import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageFileBase, OB11MessageForward, } from '@/onebot';
|
||||
@@ -664,23 +665,16 @@ export class OneBotMsgApi {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
async parsePrivateMsgEvent(msg: RawMessage) {
|
||||
if (msg.chatType !== ChatType.KCHATTYPEC2C) {
|
||||
return;
|
||||
}
|
||||
for (const element of msg.elements) {
|
||||
if (element.grayTipElement && element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||
const PokeEvent = await this.obContext.apis.FriendApi.parsePrivatePokeEvent(element.grayTipElement);
|
||||
if (PokeEvent) return PokeEvent;
|
||||
}
|
||||
//好友添加成功事件
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 19324 && msg.peerUid !== '') {
|
||||
async parsePrivateMsgEvent(msg: RawMessage, grayTipElement: GrayTipElement) {
|
||||
if (grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
|
||||
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||
const PokeEvent = await this.obContext.apis.FriendApi.parsePrivatePokeEvent(grayTipElement);
|
||||
if (PokeEvent) { return PokeEvent };
|
||||
} else if (grayTipElement.jsonGrayTipElement.busiId == 19324 && msg.peerUid !== '') {
|
||||
return new OB11FriendAddNoticeEvent(this.core, Number(await this.core.apis.UserApi.getUinByUidV2(msg.peerUid)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getMultiMessages(msg: RawMessage, parentMsgPeer: Peer) {
|
||||
//判断是否在合并消息内
|
||||
@@ -727,8 +721,33 @@ export class OneBotMsgApi {
|
||||
) {
|
||||
if (msg.senderUin == '0' || msg.senderUin == '') return;
|
||||
if (msg.peerUin == '0' || msg.peerUin == '') return;
|
||||
//跳过空消息
|
||||
const resMsg: OB11Message = {
|
||||
|
||||
const resMsg = this.initializeMessage(msg);
|
||||
|
||||
if (this.core.selfInfo.uin == msg.senderUin) {
|
||||
resMsg.message_sent_type = 'self';
|
||||
}
|
||||
|
||||
if (msg.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
await this.handleGroupMessage(resMsg, msg);
|
||||
} else if (msg.chatType == ChatType.KCHATTYPEC2C) {
|
||||
await this.handlePrivateMessage(resMsg, msg);
|
||||
} else if (msg.chatType == ChatType.KCHATTYPETEMPC2CFROMGROUP) {
|
||||
await this.handleTempGroupMessage(resMsg, msg);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const validSegments = await this.parseMessageSegments(msg, parseMultMsg);
|
||||
resMsg.message = validSegments;
|
||||
resMsg.raw_message = validSegments.map(msg => encodeCQCode(msg)).join('').trim();
|
||||
|
||||
const stringMsg = await this.convertArrayToStringMessage(resMsg);
|
||||
return { stringMsg, arrayMsg: resMsg };
|
||||
}
|
||||
|
||||
private initializeMessage(msg: RawMessage): OB11Message {
|
||||
return {
|
||||
self_id: parseInt(this.core.selfInfo.uin),
|
||||
user_id: parseInt(msg.senderUin),
|
||||
time: parseInt(msg.msgTime) || Date.now(),
|
||||
@@ -748,11 +767,10 @@ export class OneBotMsgApi {
|
||||
message_format: 'array',
|
||||
post_type: this.core.selfInfo.uin == msg.senderUin ? EventType.MESSAGE_SENT : EventType.MESSAGE,
|
||||
};
|
||||
if (this.core.selfInfo.uin == msg.senderUin) {
|
||||
resMsg.message_sent_type = 'self';
|
||||
}
|
||||
if (msg.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
resMsg.sub_type = 'normal'; // 这里go-cqhttp是group,而onebot11标准是normal, 蛋疼
|
||||
|
||||
private async handleGroupMessage(resMsg: OB11Message, msg: RawMessage) {
|
||||
resMsg.sub_type = 'normal';
|
||||
resMsg.group_id = parseInt(msg.peerUin);
|
||||
let member = await this.core.apis.GroupApi.getGroupMember(msg.peerUin, msg.senderUin);
|
||||
if (!member) member = await this.core.apis.GroupApi.getGroupMember(msg.peerUin, msg.senderUin);
|
||||
@@ -760,10 +778,14 @@ export class OneBotMsgApi {
|
||||
resMsg.sender.role = OB11Construct.groupMemberRole(member.role);
|
||||
resMsg.sender.nickname = member.nick;
|
||||
}
|
||||
} else if (msg.chatType == ChatType.KCHATTYPEC2C) {
|
||||
}
|
||||
|
||||
private async handlePrivateMessage(resMsg: OB11Message, msg: RawMessage) {
|
||||
resMsg.sub_type = 'friend';
|
||||
resMsg.sender.nickname = (await this.core.apis.UserApi.getUserDetailInfo(msg.senderUid)).nick;
|
||||
} else if (msg.chatType == ChatType.KCHATTYPETEMPC2CFROMGROUP) {
|
||||
}
|
||||
|
||||
private async handleTempGroupMessage(resMsg: OB11Message, msg: RawMessage) {
|
||||
resMsg.sub_type = 'group';
|
||||
const ret = await this.core.apis.MsgApi.getTempChatInfo(ChatType.KCHATTYPETEMPC2CFROMGROUP, msg.senderUid);
|
||||
if (ret.result === 0) {
|
||||
@@ -772,13 +794,13 @@ export class OneBotMsgApi {
|
||||
resMsg.sender.nickname = member?.nick ?? member?.cardName ?? '临时会话';
|
||||
resMsg.temp_source = resMsg.group_id;
|
||||
} else {
|
||||
resMsg.group_id = 284840486; //兜底数据
|
||||
resMsg.group_id = 284840486;
|
||||
resMsg.temp_source = resMsg.group_id;
|
||||
resMsg.sender.nickname = '临时会话';
|
||||
}
|
||||
}
|
||||
|
||||
// 处理消息段
|
||||
private async parseMessageSegments(msg: RawMessage, parseMultMsg: boolean): Promise<OB11MessageData[]> {
|
||||
const msgSegments = await Promise.allSettled(msg.elements.map(
|
||||
async (element) => {
|
||||
for (const key in element) {
|
||||
@@ -793,43 +815,41 @@ export class OneBotMsgApi {
|
||||
element[key],
|
||||
msg,
|
||||
element,
|
||||
{
|
||||
parseMultMsg: parseMultMsg
|
||||
}
|
||||
{ parseMultMsg }
|
||||
);
|
||||
// 对于 face 类型的消息,检查是否存在
|
||||
if (key === 'faceElement' && !parsedElement) {
|
||||
return null; // 如果没有找到对应的表情,返回 null
|
||||
return null;
|
||||
}
|
||||
|
||||
return parsedElement;
|
||||
}
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
// 过滤掉无效的消息段
|
||||
const validSegments = msgSegments.filter(entry => {
|
||||
return msgSegments.filter(entry => {
|
||||
if (entry.status === 'fulfilled') {
|
||||
return !!entry.value;
|
||||
} else {
|
||||
this.core.context.logger.logError.bind(this.core.context.logger)('消息段解析失败', entry.reason);
|
||||
this.core.context.logger.logError('消息段解析失败', entry.reason);
|
||||
return false;
|
||||
}
|
||||
}).map((entry) => (<PromiseFulfilledResult<OB11MessageData>>entry).value).filter(value => value != null);
|
||||
|
||||
const msgAsCQCode = validSegments.map(msg => encodeCQCode(msg)).join('').trim();
|
||||
resMsg.message = validSegments;
|
||||
resMsg.raw_message = msgAsCQCode;
|
||||
let stringMsg = structuredClone(resMsg);
|
||||
stringMsg = await this.importArrayTostringMsg(stringMsg);
|
||||
return { stringMsg: stringMsg, arrayMsg: resMsg };
|
||||
}
|
||||
async importArrayTostringMsg(msg: OB11Message) {
|
||||
|
||||
private async convertArrayToStringMessage(originMsg: OB11Message): Promise<OB11Message> {
|
||||
let msg = structuredClone(originMsg);
|
||||
msg.message_format = 'string';
|
||||
msg.message = msg.raw_message;
|
||||
return msg;
|
||||
}
|
||||
|
||||
async importArrayTostringMsg(originMsg: OB11Message) {
|
||||
let msg = structuredClone(originMsg);
|
||||
msg.message_format = 'string';
|
||||
msg.message = msg.raw_message;
|
||||
return msg;
|
||||
}
|
||||
|
||||
async createSendElements(
|
||||
messageData: OB11MessageData[],
|
||||
peer: Peer,
|
||||
@@ -892,11 +912,19 @@ export class OneBotMsgApi {
|
||||
guildId: '',
|
||||
peerUid: peer.peerUid,
|
||||
}, returnMsg.msgId);
|
||||
|
||||
setTimeout(() => {
|
||||
deleteAfterSentFiles.forEach(file => {
|
||||
try {
|
||||
if (fs.existsSync(file)) {
|
||||
fsPromise.unlink(file).then().catch(e => this.core.context.logger.logError.bind(this.core.context.logger)('发送消息删除文件失败', e));
|
||||
}
|
||||
} catch (error) {
|
||||
this.core.context.logger.logError.bind(this.core.context.logger)('发送消息删除文件失败', (error as Error).message)
|
||||
}
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
return returnMsg;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { NapCatCore } from '@/core';
|
||||
import { GrayTipRovokeElement, NapCatCore, RawMessage } from '@/core';
|
||||
import { NapCatOneBot11Adapter } from '@/onebot';
|
||||
import { OB11ProfileLikeEvent } from '@/onebot/event/notice/OB11ProfileLikeEvent';
|
||||
import { decodeProfileLikeTip } from "@/core/helper/adaptDecoder";
|
||||
|
@@ -13,6 +13,8 @@ import {
|
||||
Peer,
|
||||
RawMessage,
|
||||
SendStatusType,
|
||||
NTMsgType,
|
||||
MessageElement,
|
||||
} from '@/core';
|
||||
import { OB11ConfigLoader } from '@/onebot/config';
|
||||
import {
|
||||
@@ -263,21 +265,14 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
};
|
||||
|
||||
const msgIdSend = new LRUCache<string, number>(100);
|
||||
const recallMsgs = new LRUCache<string, boolean>(100);
|
||||
msgListener.onAddSendMsg = async (msg) => {
|
||||
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) {
|
||||
msgIdSend.put(msg.msgId, 0);
|
||||
}
|
||||
};
|
||||
msgListener.onMsgInfoListUpdate = async (msgList) => {
|
||||
this.emitRecallMsg(msgList, recallMsgs).catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)
|
||||
await this.core.eventWrapper.registerListen('NodeIKernelMsgListener/onMsgInfoListUpdate', (msgList: RawMessage[]) => {
|
||||
const report = msgList.find((e) =>
|
||||
e.senderUin == this.core.selfInfo.uin && e.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && e.msgId === msg.msgId
|
||||
);
|
||||
for (const msg of msgList.filter((e) => e.senderUin == this.core.selfInfo.uin)) {
|
||||
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && msgIdSend.get(msg.msgId) == 0) {
|
||||
msgIdSend.put(msg.msgId, 1);
|
||||
// 完成后再post
|
||||
return !!report;
|
||||
}, 1, 300);
|
||||
msg.id = MessageUnique.createUniqueMsgId(
|
||||
{
|
||||
chatType: msg.chatType,
|
||||
@@ -286,10 +281,29 @@ export class NapCatOneBot11Adapter {
|
||||
},
|
||||
msg.msgId
|
||||
);
|
||||
//此时上报的seq不是对的 不过对onebot业务无影响
|
||||
this.emitMsg(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
msgListener.onMsgRecall = async (chatType: ChatType, uid: string, msgSeq: string) => {
|
||||
const peer: Peer = {
|
||||
chatType: chatType,
|
||||
peerUid: uid,
|
||||
guildId: ''
|
||||
};
|
||||
let msg = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, msgSeq)).msgList.find(e => e.msgType == NTMsgType.KMSGTYPEGRAYTIPS);
|
||||
let element = msg?.elements[0];
|
||||
if (msg && element) {
|
||||
let recallEvent = await this.emitRecallMsg(msg, element);
|
||||
try {
|
||||
if (recallEvent) {
|
||||
await this.networkManager.emitEvent(recallEvent);
|
||||
}
|
||||
} catch (e) {
|
||||
this.context.logger.logError('处理消息撤回失败', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
msgListener.onKickedOffLine = async (kick) => {
|
||||
const event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc);
|
||||
this.networkManager
|
||||
@@ -526,10 +540,12 @@ export class NapCatOneBot11Adapter {
|
||||
private async emitMsg(message: RawMessage) {
|
||||
const network = Object.values(this.configLoader.configData.network).flat() as Array<AdapterConfigWrap>;
|
||||
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
||||
await this.handleMsg(message, network);
|
||||
await this.handleGroupEvent(message);
|
||||
await this.handlePrivateMsgEvent(message);
|
||||
await Promise.allSettled([
|
||||
this.handleMsg(message, network),
|
||||
message.chatType == ChatType.KCHATTYPEGROUP ? this.handleGroupEvent(message) : this.handlePrivateMsgEvent(message)
|
||||
]);
|
||||
}
|
||||
|
||||
private async handleMsg(message: RawMessage, network: Array<AdapterConfigWrap>) {
|
||||
try {
|
||||
const ob11Msg = await this.apis.MsgApi.parseMessageV2(message, this.configLoader.configData.parseMultMsg);
|
||||
@@ -597,9 +613,25 @@ export class NapCatOneBot11Adapter {
|
||||
|
||||
private async handleGroupEvent(message: RawMessage) {
|
||||
try {
|
||||
const groupEvent = await this.apis.GroupApi.parseGroupEvent(message);
|
||||
if (groupEvent) {
|
||||
this.networkManager.emitEvent(groupEvent);
|
||||
// 群名片修改事件解析 任何都该判断
|
||||
if (message.senderUin && message.senderUin !== '0') {
|
||||
const cardChangedEvent = await this.apis.GroupApi.parseCardChangedEvent(message);
|
||||
cardChangedEvent && await this.networkManager.emitEvent(cardChangedEvent);
|
||||
}
|
||||
if (message.msgType === NTMsgType.KMSGTYPEFILE) {
|
||||
// 文件为单元素消息
|
||||
const elementWrapper = message.elements.find(e => !!e.fileElement);
|
||||
if (elementWrapper?.fileElement) {
|
||||
const uploadGroupFileEvent = await this.apis.GroupApi.parseGroupUploadFileEvene(message, elementWrapper.fileElement, elementWrapper);
|
||||
uploadGroupFileEvent && await this.networkManager.emitEvent(uploadGroupFileEvent);
|
||||
}
|
||||
} else if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) {
|
||||
// 灰条为单元素消息
|
||||
const grayTipElement = message.elements[0].grayTipElement;
|
||||
if (grayTipElement) {
|
||||
const event = await this.apis.GroupApi.parseGrayTipElement(message, grayTipElement);
|
||||
event && await this.networkManager.emitEvent(event);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.context.logger.logError('constructGroupEvent error: ', e);
|
||||
@@ -608,59 +640,51 @@ export class NapCatOneBot11Adapter {
|
||||
|
||||
private async handlePrivateMsgEvent(message: RawMessage) {
|
||||
try {
|
||||
const privateEvent = await this.apis.MsgApi.parsePrivateMsgEvent(message);
|
||||
if (privateEvent) {
|
||||
this.networkManager.emitEvent(privateEvent);
|
||||
if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) {
|
||||
// 灰条为单元素消息
|
||||
const grayTipElement = message.elements[0].grayTipElement;
|
||||
if (grayTipElement) {
|
||||
const event = await this.apis.MsgApi.parsePrivateMsgEvent(message, grayTipElement);
|
||||
event && await this.networkManager.emitEvent(event);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.context.logger.logError('constructPrivateEvent error: ', e);
|
||||
}
|
||||
}
|
||||
private async emitRecallMsg(msgList: RawMessage[], cache: LRUCache<string, boolean>) {
|
||||
for (const message of msgList) {
|
||||
// log("message update", message.sendStatus, message.msgId, message.msgSeq)
|
||||
|
||||
private async emitRecallMsg(message: RawMessage, element: MessageElement) {
|
||||
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
||||
if (message.recallTime != '0' && !cache.get(message.msgId)) {
|
||||
//TODO: 这个判断方法不太好,应该使用灰色消息元素来判断?
|
||||
cache.put(message.msgId, true);
|
||||
// 撤回消息上报
|
||||
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId);
|
||||
if (!oriMessageId) {
|
||||
oriMessageId = MessageUnique.createUniqueMsgId(peer, message.msgId);
|
||||
}
|
||||
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
|
||||
if (message.chatType == ChatType.KCHATTYPEC2C) {
|
||||
const friendRecallEvent = new OB11FriendRecallNoticeEvent(
|
||||
return await this.emitFriendRecallMsg(message, oriMessageId, element);
|
||||
} else if (message.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
return await this.emitGroupRecallMsg(message, oriMessageId, element);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async emitFriendRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||
return new OB11FriendRecallNoticeEvent(
|
||||
this.core,
|
||||
+message.senderUin,
|
||||
oriMessageId
|
||||
);
|
||||
this.networkManager
|
||||
.emitEvent(friendRecallEvent)
|
||||
.catch((e) =>
|
||||
this.context.logger.logError.bind(this.context.logger)('处理好友消息撤回失败', e)
|
||||
);
|
||||
} else if (message.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
let operatorId = message.senderUin;
|
||||
for (const element of message.elements) {
|
||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||
if (!operatorUid) return;
|
||||
const operator = await this.core.apis.GroupApi.getGroupMember(message.peerUin, operatorUid);
|
||||
operatorId = operator?.uin ?? message.senderUin;
|
||||
}
|
||||
const groupRecallEvent = new OB11GroupRecallNoticeEvent(
|
||||
|
||||
private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||
if (!operatorUid) return undefined;
|
||||
let operatorId = message.senderUin ?? await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
||||
return new OB11GroupRecallNoticeEvent(
|
||||
this.core,
|
||||
+message.peerUin,
|
||||
+message.senderUin,
|
||||
+operatorId,
|
||||
oriMessageId
|
||||
);
|
||||
this.networkManager
|
||||
.emitEvent(groupRecallEvent)
|
||||
.catch((e) => this.context.logger.logError.bind(this.context.logger)('处理群消息撤回失败', e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export * from './types';
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user