NapCatQQ/packages/napcat-onebot/action/go-cqhttp/GetForwardMsg.ts
手瓜一十雪 8623fb1df0 Refactor action examples and enhance metadata
Replaced generic ActionExamples imports with more specific examples modules (FileActionsExamples, GroupActionsExamples, GoCQHTTPActionsExamples) across file, group, and go-cqhttp actions. Added or updated actionSummary, actionDescription, actionTags, payloadExample, and returnExample properties for improved API documentation and clarity.
2026-01-25 18:18:25 +08:00

171 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { OneBotAction } from '@/napcat-onebot/action/OneBotAction';
import { OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageForward, OB11MessageNodePlain as OB11MessageNode } from '@/napcat-onebot/index';
import { ActionName } from '@/napcat-onebot/action/router';
import { MessageUnique } from 'napcat-common/src/message-unique';
import { Static, Type } from '@sinclair/typebox';
import { ChatType, ElementType, MsgSourceType, NTMsgType, RawMessage } from 'napcat-core';
import { isNumeric } from 'napcat-common/src/helper';
import { GoCQHTTPActionsExamples } from './examples';
const PayloadSchema = Type.Object({
message_id: Type.Optional(Type.String({ description: '消息ID' })),
id: Type.Optional(Type.String({ description: '消息ID' })),
});
type PayloadType = Static<typeof PayloadSchema>;
const ReturnSchema = Type.Object({
messages: Type.Optional(Type.Array(Type.Unknown(), { description: '消息列表' })),
}, { description: '合并转发消息' });
type ReturnType = Static<typeof ReturnSchema>;
function isForward (msg: OB11MessageData | string): msg is OB11MessageForward {
return typeof msg !== 'string' && msg.type === OB11MessageDataType.forward;
}
export class GoCQHTTPGetForwardMsgAction extends OneBotAction<PayloadType, ReturnType> {
override actionName = ActionName.GoCQHTTP_GetForwardMsg;
override payloadSchema = PayloadSchema;
override returnSchema = ReturnSchema;
override actionSummary = '获取合并转发消息';
override actionDescription = '获取合并转发消息的具体内容';
override actionTags = ['Go-CQHTTP'];
override payloadExample = GoCQHTTPActionsExamples.GetForwardMsg.payload;
override returnExample = GoCQHTTPActionsExamples.GetForwardMsg.response;
private createTemplateNode (message: OB11Message): OB11MessageNode {
return {
type: OB11MessageDataType.node,
data: {
user_id: message.user_id,
nickname: message.sender.nickname,
message: [],
content: [],
},
};
}
async parseForward (messages: OB11Message[]): Promise<OB11MessageNode[]> {
const retMsg: OB11MessageNode[] = [];
for (const message of messages) {
const templateNode = this.createTemplateNode(message);
for (const msgdata of message.message) {
if (isForward(msgdata)) {
const newNode = this.createTemplateNode(message);
newNode.data.message = await this.parseForward(msgdata.data.content ?? []);
templateNode.data.message.push(newNode);
} else {
if (typeof msgdata === 'string') {
const textMsg: OB11MessageData = { type: OB11MessageDataType.text, data: { text: msgdata } };
templateNode.data.message.push(textMsg);
} else {
templateNode.data.message.push(msgdata);
}
}
}
retMsg.push(templateNode);
}
return retMsg;
}
async _handle (payload: PayloadType) {
// 1. 检查消息ID是否存在
const msgId = payload.message_id || payload.id;
if (!msgId) {
throw new Error('message_id is required');
}
// 2. 定义辅助函数 - 创建伪转发消息对象
const createFakeForwardMsg = (resId: string): RawMessage => {
const fakeMsg: RawMessage = {
chatType: ChatType.KCHATTYPEGROUP,
elements: [{
elementType: ElementType.MULTIFORWARD,
elementId: '',
multiForwardMsgElement: {
resId,
fileName: '',
xmlContent: '',
},
}],
guildId: '',
isOnlineMsg: false,
msgId: '', // TODO: no necessary
msgRandom: '0',
msgSeq: '',
msgTime: '',
msgType: NTMsgType.KMSGTYPEMIX,
parentMsgIdList: [],
parentMsgPeer: {
chatType: ChatType.KCHATTYPEGROUP,
peerUid: '',
},
peerName: '',
peerUid: '284840486',
peerUin: '284840486',
recallTime: '0',
records: [],
sendNickName: '',
sendRemarkName: '',
senderUid: '',
senderUin: '1094950020',
sourceType: MsgSourceType.K_DOWN_SOURCETYPE_UNKNOWN,
subMsgType: 1,
};
return fakeMsg;
};
// 3. 定义协议回退逻辑函数
const protocolFallbackLogic = async (resId: string) => {
const ob = (await this.obContext.apis.MsgApi.parseMessageV2(createFakeForwardMsg(resId), true))?.arrayMsg;
const firstMsg = ob?.message?.[0];
if (firstMsg && isForward(firstMsg)) {
return {
messages: firstMsg.data.content,
};
}
throw new Error('protocolFallbackLogic: 找不到相关的聊天记录');
};
// 4. 尝试通过正常渠道获取消息
// 如果是数字ID优先使用getMsgsByMsgId获取
if (!isNumeric(msgId)) {
const ret = await protocolFallbackLogic(msgId);
if (ret.messages) {
return ret;
}
throw new Error('ResId无效: 找不到相关的聊天记录');
}
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId.toString());
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
if (rootMsg) {
// 5. 获取消息内容
const data = await this.core.apis.MsgApi.getMsgHistory(rootMsg.Peer, rootMsg.MsgId, 1);//getMsgsIncludeSelf
if (data && data.result === 0 && data.msgList.length > 0) {
const singleMsg = data.msgList[0];
if (!singleMsg) {
throw new Error('消息不存在或已过期');
}
// 6. 解析消息内容
const resMsg = (await this.obContext.apis.MsgApi.parseMessage(singleMsg, 'array', true));
const firstMsg = resMsg?.message?.[0];
if (firstMsg && isForward(firstMsg)) {
const forwardContent = firstMsg.data.content;
if (forwardContent) {
return { messages: forwardContent };
}
}
}
}
// 说明消息已过期或者为内层消息 NapCat 一次返回不处理内层消息
throw new Error('消息已过期或者为内层消息,无法获取转发消息');
}
}