This commit is contained in:
pk5ls20
2025-02-05 08:07:58 +08:00
parent eb1140d7ba
commit b758a06ceb
13 changed files with 508 additions and 105 deletions

View File

@@ -3,6 +3,7 @@ import { OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageForward,
import { ActionName } from '@/onebot/action/router';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
import { ChatType, ElementType, MsgSourceType, NTMsgType, RawMessage } from '@/core';
const SchemaData = Type.Object({
message_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
@@ -57,24 +58,72 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, {
throw new Error('message_id is required');
}
const fakeForwardMsg = (res_id: string) => {
return {
chatType: ChatType.KCHATTYPEGROUP,
elements: [{
elementType: ElementType.MULTIFORWARD,
elementId: '',
multiForwardMsgElement: {
resId: res_id,
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,
} as RawMessage;
};
const protocolFallbackLogic = async (res_id: string) => {
const ob = (await this.obContext.apis.MsgApi.parseMessageV2(fakeForwardMsg(res_id)))?.arrayMsg;
if (ob) {
return {
messages: (ob?.message?.[0] as OB11MessageForward)?.data?.content
};
}
throw new Error('protocolFallbackLogic: 找不到相关的聊天记录');
};
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId.toString());
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
if (!rootMsg) {
throw new Error('msg not found');
return await protocolFallbackLogic(msgId.toString());
}
const data = await this.core.apis.MsgApi.getMsgsByMsgId(rootMsg.Peer, [rootMsg.MsgId]);
if (!data || data.result !== 0) {
throw new Error('找不到相关的聊天记录' + data?.errMsg);
return await protocolFallbackLogic(msgId.toString());
}
const singleMsg = data.msgList[0];
if (!singleMsg) {
throw new Error('找不到相关的聊天记录');
return await protocolFallbackLogic(msgId.toString());
}
const resMsg = (await this.obContext.apis.MsgApi.parseMessageV2(singleMsg))?.arrayMsg;//强制array 以便处理
if (!(resMsg?.message?.[0] as OB11MessageForward)?.data?.content) {
throw new Error('找不到相关的聊天记录');
return await protocolFallbackLogic(msgId.toString());
}
return {
messages: (resMsg?.message?.[0] as OB11MessageForward)?.data?.content

View File

@@ -1,41 +1,50 @@
import { FileNapCatOneBotUUID } from '@/common/file-uuid';
import { MessageUnique } from '@/common/message-unique';
import {FileNapCatOneBotUUID} from '@/common/file-uuid';
import {MessageUnique} from '@/common/message-unique';
import {
NTMsgAtType,
ChatType,
CustomMusicSignPostData,
ElementType,
FaceIndex,
FaceType,
GrayTipElement,
GroupNotify,
IdMusicSignPostData,
MessageElement,
NapCatCore,
NTGrayTipElementSubTypeV2,
NTMsgAtType,
Peer,
RawMessage,
SendMessageElement,
SendTextElement,
FaceType,
GrayTipElement,
GroupNotify,
} from '@/core';
import faceConfig from '@/core/external/face_config.json';
import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageFileBase, OB11MessageForward, OB11MessageImage, OB11MessageVideo, } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { EventType } from '@/onebot/event/OneBotEvent';
import { encodeCQCode } from '@/onebot/helper/cqcode';
import { uriToLocalFile } from '@/common/file';
import { RequestUtil } from '@/common/request';
import fsPromise, { constants } from 'node:fs/promises';
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
import { ForwardMsgBuilder } from '@/common/forward-msg-builder';
import { NapProtoMsg } from '@napneko/nap-proto-core';
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
import { OB11GroupDecreaseEvent, GroupDecreaseSubType } from '../event/notice/OB11GroupDecreaseEvent';
import { GroupAdmin } from '@/core/packet/transformer/proto/message/groupAdmin';
import { OB11GroupAdminNoticeEvent } from '../event/notice/OB11GroupAdminNoticeEvent';
import { GroupChange, GroupChangeInfo, GroupInvite, PushMsgBody } from '@/core/packet/transformer/proto';
import { OB11GroupRequestEvent } from '../event/request/OB11GroupRequest';
import { LRUCache } from '@/common/lru-cache';
import {
NapCatOneBot11Adapter,
OB11Message,
OB11MessageData,
OB11MessageDataType,
OB11MessageFileBase,
OB11MessageForward,
OB11MessageImage,
OB11MessageVideo,
} from '@/onebot';
import {OB11Construct} from '@/onebot/helper/data';
import {EventType} from '@/onebot/event/OneBotEvent';
import {encodeCQCode} from '@/onebot/helper/cqcode';
import {uriToLocalFile} from '@/common/file';
import {RequestUtil} from '@/common/request';
import fsPromise, {constants} from 'node:fs/promises';
import {OB11FriendAddNoticeEvent} from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
import {ForwardMsgBuilder} from '@/common/forward-msg-builder';
import {NapProtoMsg} from '@napneko/nap-proto-core';
import {OB11GroupIncreaseEvent} from '../event/notice/OB11GroupIncreaseEvent';
import {GroupDecreaseSubType, OB11GroupDecreaseEvent} from '../event/notice/OB11GroupDecreaseEvent';
import {GroupAdmin} from '@/core/packet/transformer/proto/message/groupAdmin';
import {OB11GroupAdminNoticeEvent} from '../event/notice/OB11GroupAdminNoticeEvent';
import {GroupChange, GroupChangeInfo, GroupInvite, PushMsgBody} from '@/core/packet/transformer/proto';
import {OB11GroupRequestEvent} from '../event/request/OB11GroupRequest';
import {LRUCache} from '@/common/lru-cache';
type RawToOb11Converters = {
[Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: (
@@ -84,12 +93,12 @@ export class OneBotMsgApi {
}
return {
type: OB11MessageDataType.text,
data: { text },
data: {text},
};
} else {
let qq: string = 'all';
if (element.atType !== NTMsgAtType.ATTYPEALL) {
const { atNtUid, atUid } = element;
const {atNtUid, atUid} = element;
qq = !atUid || atUid === '0' ? await this.core.apis.UserApi.getUinByUidV2(atNtUid) : atUid;
}
return {
@@ -197,7 +206,7 @@ export class OneBotMsgApi {
peerUid: msg.peerUid,
guildId: '',
};
const { emojiId } = _;
const {emojiId} = _;
const dir = emojiId.substring(0, 2);
const url = `https://gxh.vip.qq.com/club/item/parcel/item/${dir}/${emojiId}/raw300.gif`;
const filename = `${dir}-${emojiId}.gif`;
@@ -264,7 +273,6 @@ export class OneBotMsgApi {
}
// 丢弃该消息段
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
this.core.context.logger.logError(
@@ -355,18 +363,25 @@ export class OneBotMsgApi {
};
},
multiForwardMsgElement: async (_, msg, _wrapper, context) => {
multiForwardMsgElement: async (element, msg, _wrapper, context) => {
const parentMsgPeer = msg.parentMsgPeer ?? {
chatType: msg.chatType,
guildId: '',
peerUid: msg.peerUid,
};
const multiMsgs = await this.getMultiMessages(msg, parentMsgPeer);
let multiMsgs = await this.getMultiMessages(msg, parentMsgPeer);
// 拉取失败则跳过
if (!multiMsgs) return null;
if (!multiMsgs || multiMsgs.length === 0) {
try {
multiMsgs = await this.core.apis.PacketApi.pkt.operation.FetchForwardMsg(element.resId);
} catch (e) {
this.core.context.logger.logError('Protocol FetchForwardMsg fallback failed!', e);
return null;
}
}
const forward: OB11MessageForward = {
type: OB11MessageDataType.forward,
data: { id: msg.msgId }
data: {id: msg.msgId}
};
if (!context.parseMultMsg) return forward;
forward.data.content = await this.parseMultiMessageContent(
@@ -397,7 +412,7 @@ export class OneBotMsgApi {
};
ob11ToRawConverters: Ob11ToRawConverters = {
[OB11MessageDataType.text]: async ({ data: { text } }) => ({
[OB11MessageDataType.text]: async ({data: {text}}) => ({
elementType: ElementType.TEXT,
elementId: '',
textElement: {
@@ -409,7 +424,7 @@ export class OneBotMsgApi {
},
}),
[OB11MessageDataType.at]: async ({ data: { qq: atQQ } }, context) => {
[OB11MessageDataType.at]: async ({data: {qq: atQQ}}, context) => {
function at(atUid: string, atNtUid: string, atType: NTMsgAtType, atName: string): SendTextElement {
return {
elementType: ElementType.TEXT,
@@ -436,7 +451,7 @@ export class OneBotMsgApi {
return at(atQQ, uid, NTMsgAtType.ATTYPEONE, info.nick || '');
},
[OB11MessageDataType.reply]: async ({ data: { id } }) => {
[OB11MessageDataType.reply]: async ({data: {id}}) => {
const replyMsgM = MessageUnique.getMsgIdAndPeerByShortId(parseInt(id));
if (!replyMsgM) {
this.core.context.logger.logWarn('回复消息不存在', id);
@@ -458,7 +473,7 @@ export class OneBotMsgApi {
undefined;
},
[OB11MessageDataType.face]: async ({ data: { id, resultId, chainCount } }) => {
[OB11MessageDataType.face]: async ({data: {id, resultId, chainCount}}) => {
const parsedFaceId = +id;
// 从face_config.json中获取表情名称
const sysFaces = faceConfig.sysface;
@@ -522,12 +537,12 @@ export class OneBotMsgApi {
},
[OB11MessageDataType.file]: async (sendMsg, context) => {
const { path, fileName } = await this.handleOb11FileLikeMessage(sendMsg, context);
const {path, fileName} = await this.handleOb11FileLikeMessage(sendMsg, context);
return await this.core.apis.FileApi.createValidSendFileElement(context, path, fileName);
},
[OB11MessageDataType.video]: async (sendMsg, context) => {
const { path, fileName } = await this.handleOb11FileLikeMessage(sendMsg, context);
const {path, fileName} = await this.handleOb11FileLikeMessage(sendMsg, context);
let thumb = sendMsg.data.thumb;
if (thumb) {
@@ -545,7 +560,7 @@ export class OneBotMsgApi {
this.core.apis.FileApi.createValidSendPttElement(
(await this.handleOb11FileLikeMessage(sendMsg, context)).path),
[OB11MessageDataType.json]: async ({ data: { data } }) => ({
[OB11MessageDataType.json]: async ({data: {data}}) => ({
elementType: ElementType.ARK,
elementId: '',
arkElement: {
@@ -588,13 +603,13 @@ export class OneBotMsgApi {
}),
// Need signing
[OB11MessageDataType.markdown]: async ({ data: { content } }) => ({
[OB11MessageDataType.markdown]: async ({data: {content}}) => ({
elementType: ElementType.MARKDOWN,
elementId: '',
markdownElement: { content },
markdownElement: {content},
}),
[OB11MessageDataType.music]: async ({ data }, context) => {
[OB11MessageDataType.music]: async ({data}, context) => {
// 保留, 直到...找到更好的解决方案
if (data.id !== undefined) {
if (!['qq', '163', 'kugou', 'kuwo', 'migu'].includes(data.type)) {
@@ -618,8 +633,8 @@ export class OneBotMsgApi {
let postData: IdMusicSignPostData | CustomMusicSignPostData;
if (data.id === undefined && data.content) {
const { content, ...others } = data;
postData = { singer: content, ...others };
const {content, ...others} = data;
postData = {singer: content, ...others};
} else {
postData = data;
}
@@ -631,7 +646,7 @@ export class OneBotMsgApi {
try {
const musicJson = await RequestUtil.HttpGetJson<string>(signUrl, 'POST', postData);
return this.ob11ToRawConverters.json({
data: { data: musicJson },
data: {data: musicJson},
type: OB11MessageDataType.json
}, context);
} catch (e) {
@@ -642,10 +657,10 @@ export class OneBotMsgApi {
[OB11MessageDataType.node]: async () => undefined,
[OB11MessageDataType.forward]: async ({ data }, context) => {
[OB11MessageDataType.forward]: async ({data}, context) => {
const jsonData = ForwardMsgBuilder.fromResId(data.id);
return this.ob11ToRawConverters.json({
data: { data: JSON.stringify(jsonData) },
data: {data: JSON.stringify(jsonData)},
type: OB11MessageDataType.json
}, context);
},
@@ -665,17 +680,17 @@ export class OneBotMsgApi {
[OB11MessageDataType.miniapp]: async () => undefined,
[OB11MessageDataType.contact]: async ({ data: { type = 'qq', id } }, context) => {
[OB11MessageDataType.contact]: async ({data: {type = 'qq', id}}, context) => {
if (type === 'qq') {
const arkJson = await this.core.apis.UserApi.getBuddyRecommendContactArkJson(id.toString(), '');
return this.ob11ToRawConverters.json({
data: { data: arkJson.arkMsg },
data: {data: arkJson.arkMsg},
type: OB11MessageDataType.json
}, context);
} else if (type === 'group') {
const arkJson = await this.core.apis.GroupApi.getGroupRecommendContactArkJson(id.toString());
return this.ob11ToRawConverters.json({
data: { data: arkJson.arkJson },
data: {data: arkJson.arkJson},
type: OB11MessageDataType.json
}, context);
}
@@ -692,7 +707,10 @@ export class OneBotMsgApi {
if (grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
const PokeEvent = await this.obContext.apis.FriendApi.parsePrivatePokeEvent(grayTipElement, Number(await this.core.apis.UserApi.getUinByUidV2(msg.peerUid)));
if (PokeEvent) { return PokeEvent; };
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)));
}
@@ -849,7 +867,7 @@ export class OneBotMsgApi {
element[key],
msg,
element,
{ parseMultMsg }
{parseMultMsg}
);
if (key === 'faceElement' && !parsedElement) {
return null;
@@ -902,13 +920,13 @@ export class OneBotMsgApi {
) => Promise<SendMessageElement | undefined>;
const callResult = converter(
sendMsg,
{ peer, deleteAfterSentFiles },
{peer, deleteAfterSentFiles},
)?.catch(undefined);
callResultList.push(callResult);
}
const ret = await Promise.all(callResultList);
const sendElements: SendMessageElement[] = ret.filter(ele => !!ele);
return { sendElements, deleteAfterSentFiles };
return {sendElements, deleteAfterSentFiles};
}
async sendMsgWithOb11UniqueId(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[]) {
@@ -970,8 +988,8 @@ export class OneBotMsgApi {
}
private async handleOb11FileLikeMessage(
{ data: inputdata }: OB11MessageFileBase,
{ deleteAfterSentFiles }: SendMessageContext
{data: inputdata}: OB11MessageFileBase,
{deleteAfterSentFiles}: SendMessageContext
) {
let realUri = [inputdata.url, inputdata.file, inputdata.path].find(uri => uri && uri.trim()) ?? '';
if (!realUri) {
@@ -980,28 +998,29 @@ export class OneBotMsgApi {
}
const downloadFile = async (uri: string) => {
const { path, fileName, errMsg, success } = await uriToLocalFile(this.core.NapCatTempPath, uri);
const {path, fileName, errMsg, success} = await uriToLocalFile(this.core.NapCatTempPath, uri);
if (!success) {
this.core.context.logger.logError('文件下载失败', errMsg);
throw new Error('文件下载失败: ' + errMsg);
}
return { path, fileName };
return {path, fileName};
};
try {
const { path, fileName } = await downloadFile(realUri);
const {path, fileName} = await downloadFile(realUri);
deleteAfterSentFiles.push(path);
return { path, fileName: inputdata.name ?? fileName };
return {path, fileName: inputdata.name ?? fileName};
} catch {
realUri = await this.handleObfuckName(realUri);
const { path, fileName } = await downloadFile(realUri);
const {path, fileName} = await downloadFile(realUri);
deleteAfterSentFiles.push(path);
return { path, fileName: inputdata.name ?? fileName };
return {path, fileName: inputdata.name ?? fileName};
}
}
async handleObfuckName(name: string) {
const contextMsgFile = FileNapCatOneBotUUID.decode(name);
if (contextMsgFile && contextMsgFile.msgId && contextMsgFile.elementId) {
const { peer, msgId, elementId } = contextMsgFile;
const {peer, msgId, elementId} = contextMsgFile;
const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList.find(msg => msg.msgId === msgId);
const mixElement = rawMessage?.elements.find(e => e.elementId === elementId);
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
@@ -1009,18 +1028,19 @@ export class OneBotMsgApi {
let url = '';
if (mixElement?.picElement && rawMessage) {
const tempData =
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageImage | undefined;
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, {parseMultMsg: false}) as OB11MessageImage | undefined;
url = tempData?.data.url ?? '';
}
if (mixElement?.videoElement && rawMessage) {
const tempData =
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageVideo | undefined;
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, {parseMultMsg: false}) as OB11MessageVideo | undefined;
url = tempData?.data.url ?? '';
}
return url !== '' ? url : await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
}
throw new Error('文件名解析失败');
}
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
switch (type) {
case 130: