refactor & fix: refactor msg entity & adjust some wrong definition

This commit is contained in:
pk5ls20 2024-10-27 04:16:15 +08:00
parent fb09af0e64
commit 7ab6a10fc9
No known key found for this signature in database
GPG Key ID: 6370ED7A169F493A
4 changed files with 136 additions and 246 deletions

View File

@ -238,7 +238,7 @@ export class NTQQFileApi {
fileName: fileName, fileName: fileName,
filePath: path, filePath: path,
md5HexStr: md5, md5HexStr: md5,
fileSize: fileSize, fileSize: fileSize.toString(),
duration: duration ?? 1, duration: duration ?? 1,
formatType: 1, formatType: 1,
voiceType: 1, voiceType: 1,

View File

@ -27,94 +27,70 @@ export interface GetFileListParam {
export enum ElementType { export enum ElementType {
UNKNOWN = 0, UNKNOWN = 0,
TEXT = 1, TEXT = 1,
PIC = 2, PIC = 2,
FILE = 3, FILE = 3,
PTT = 4, PTT = 4,
VIDEO = 5, VIDEO = 5,
FACE = 6, FACE = 6,
REPLY = 7, REPLY = 7,
GreyTip = 8, // “小灰条”,包括拍一拍 (Poke)、撤回提示等
WALLET = 9, WALLET = 9,
/**
* (Poke)
*/
GreyTip = 8,
ARK = 10, ARK = 10,
MFACE = 11, MFACE = 11,
LIVEGIFT = 12, LIVEGIFT = 12,
STRUCTLONGMSG = 13, STRUCTLONGMSG = 13,
MARKDOWN = 14, MARKDOWN = 14,
GIPHY = 15, GIPHY = 15,
MULTIFORWARD = 16, MULTIFORWARD = 16,
INLINEKEYBOARD = 17, INLINEKEYBOARD = 17,
INTEXTGIFT = 18, INTEXTGIFT = 18,
CALENDAR = 19, CALENDAR = 19,
YOLOGAMERESULT = 20, YOLOGAMERESULT = 20,
AVRECORD = 21, AVRECORD = 21,
FEED = 22, FEED = 22,
TOFURECORD = 23, TOFURECORD = 23,
ACEBUBBLE = 24, ACEBUBBLE = 24,
ACTIVITY = 25, ACTIVITY = 25,
TOFU = 26, TOFU = 26,
FACEBUBBLE = 27, FACEBUBBLE = 27,
SHARELOCATION = 28, SHARELOCATION = 28,
TASKTOPMSG = 29, TASKTOPMSG = 29,
RECOMMENDEDMSG = 43, RECOMMENDEDMSG = 43,
ACTIONBAR = 44 ACTIONBAR = 44
} }
type ElementFullBase = Omit<MessageElement, 'elementType' | 'elementId' | 'extBufForUI'>;
type ElementBase<
K extends keyof ElementFullBase,
S extends Partial<{ [P in K]: keyof NonNullable<ElementFullBase[P]> | Array<keyof NonNullable<ElementFullBase[P]>> }> = {}
> = {
[P in K]:
S[P] extends Array<infer U>
? Pick<NonNullable<ElementFullBase[P]>, U & keyof NonNullable<ElementFullBase[P]>>
: S[P] extends keyof NonNullable<ElementFullBase[P]>
? Pick<NonNullable<ElementFullBase[P]>, S[P]>
: NonNullable<ElementFullBase[P]>;
};
export interface SendElementBase<ET extends ElementType> {
elementType: ET;
elementId: string;
extBufForUI?: string;
}
export interface ActionBarElement { export interface ActionBarElement {
rows: InlineKeyboardRow[]; rows: InlineKeyboardRow[];
botAppid: string; botAppid: string;
} }
export interface SendActionBarElement {
elementType: ElementType.ACTIONBAR;
elementId: string;
actionBarElement: ActionBarElement;
}
export interface RecommendedMsgElement { export interface RecommendedMsgElement {
rows: InlineKeyboardRow[]; rows: InlineKeyboardRow[];
botAppid: string; botAppid: string;
} }
export interface SendRecommendedMsgElement { export type SendRecommendedMsgElement = SendElementBase<ElementType.RECOMMENDEDMSG> & ElementBase<'recommendedMsgElement'>;
elementType: ElementType.RECOMMENDEDMSG;
elementId: string;
recommendedMsgElement: RecommendedMsgElement;
}
export interface InlineKeyboardButton { export interface InlineKeyboardButton {
id: string; id: string;
@ -171,11 +147,7 @@ export enum NTMsgType {
KMSGTYPEWALLET = 10 KMSGTYPEWALLET = 10
} }
export interface SendTaskTopMsgElement { export type SendTaskTopMsgElement = SendElementBase<ElementType.TASKTOPMSG> & ElementBase<'taskTopMsgElement'>;
elementType: ElementType.TASKTOPMSG;
elementId: string;
taskTopMsgElement: TaskTopMsgElement;
}
export interface TofuRecordElement { export interface TofuRecordElement {
type: number; type: number;
@ -194,11 +166,7 @@ export interface TofuRecordElement {
onscreennotify: boolean; onscreennotify: boolean;
} }
export interface SendTofuRecordElement { export type SendTofuRecordElement = SendElementBase<ElementType.TOFURECORD> & ElementBase<'tofuRecordElement'>;
elementType: ElementType.TOFURECORD;
elementId: string;
tofuRecordElement: TofuRecordElement;
}
export interface FaceBubbleElement { export interface FaceBubbleElement {
faceCount: number; faceCount: number;
@ -216,12 +184,7 @@ export interface FaceBubbleElement {
}; };
} }
export interface SendFaceBubbleElement { export type SendFaceBubbleElement = SendElementBase<ElementType.FACEBUBBLE> & ElementBase<'faceBubbleElement'>;
elementType: ElementType.FACEBUBBLE;
elementId: string;
faceBubbleElement: FaceBubbleElement;
}
export interface AvRecordElement { export interface AvRecordElement {
type: number; type: number;
@ -232,11 +195,7 @@ export interface AvRecordElement {
extraType: number; extraType: number;
} }
export interface SendavRecordElement { export type SendAvRecordElement = SendElementBase<ElementType.AVRECORD> & ElementBase<'avRecordElement'>;
elementType: ElementType.AVRECORD;
elementId: string;
avRecordElement: AvRecordElement;
}
export interface YoloUserInfo { export interface YoloUserInfo {
uid: string; uid: string;
@ -245,24 +204,13 @@ export interface YoloUserInfo {
bizId: string; bizId: string;
} }
export interface SendInlineKeyboardElement { export type SendInlineKeyboardElement = SendElementBase<ElementType.INLINEKEYBOARD> & ElementBase<'inlineKeyboardElement'>;
elementType: ElementType.INLINEKEYBOARD;
elementId: string;
inlineKeyboardElement: {
rows: number;
botAppid: string;
};
}
export interface YoloGameResultElement { export interface YoloGameResultElement {
UserInfo: YoloUserInfo[]; UserInfo: YoloUserInfo[];
} }
export interface SendYoloGameResultElement { export type SendYoloGameResultElement = SendElementBase<ElementType.YOLOGAMERESULT> & ElementBase<'yoloGameResultElement'>;
elementType: ElementType.YOLOGAMERESULT;
yoloGameResultElement: YoloGameResultElement;
}
export interface GiphyElement { export interface GiphyElement {
id: string; id: string;
@ -271,17 +219,9 @@ export interface GiphyElement {
height: number; height: number;
} }
export interface SendGiphyElement { export type SendGiphyElement = SendElementBase<ElementType.GIPHY> & ElementBase<'giphyElement'>;
elementType: ElementType.GIPHY;
elementId: string;
giphyElement: GiphyElement;
}
export interface SendWalletElement { export type SendWalletElement = SendElementBase<ElementType.UNKNOWN> & ElementBase<'walletElement'>;
elementType: ElementType.UNKNOWN;//不做 设置位置
elementId: string;
walletElement: Record<string, never>;
}
export interface CalendarElement { export interface CalendarElement {
summary: string; summary: string;
@ -291,49 +231,16 @@ export interface CalendarElement {
schema: string; schema: string;
} }
export interface SendCalendarElement { export type SendCalendarElement = SendElementBase<ElementType.CALENDAR> & ElementBase<'calendarElement'>;
elementType: ElementType.CALENDAR;
elementId: string;
calendarElement: CalendarElement;
}
export interface SendliveGiftElement { export type SendLiveGiftElement = SendElementBase<ElementType.LIVEGIFT> & ElementBase<'liveGiftElement'>;
elementType: ElementType.LIVEGIFT;
elementId: string;
liveGiftElement: Record<string, never>;
}
export interface SendTextElement { export type SendTextElement = SendElementBase<ElementType.TEXT> & ElementBase<'textElement'>;
elementType: ElementType.TEXT;
elementId: string;
textElement: {
content: string;
atType: number;
atUid: string;
atTinyId: string;
atNtUid: string;
};
}
export interface SendPttElement { export type SendPttElement = SendElementBase<ElementType.PTT> & ElementBase<'pttElement', {
elementType: ElementType.PTT; pttElement: ['fileName', 'filePath', 'md5HexStr', 'fileSize', 'duration', 'formatType', 'voiceType',
elementId: string; 'voiceChangeType', 'canConvert2Text', 'waveAmplitudes', 'fileSubId', 'playState', 'autoConvertText']
pttElement: { }>;
fileName: string;
filePath: string;
md5HexStr: string;
fileSize: number;
duration: number; // 单位是秒
formatType: number;
voiceType: number;
voiceChangeType: number;
canConvert2Text: boolean;
waveAmplitudes: number[];
fileSubId: string;
playState: number;
autoConvertText: number;
};
}
export enum PicType { export enum PicType {
gif = 2000, gif = 2000,
@ -359,11 +266,7 @@ export enum NTMsgAtType {
ATTYPEUNKNOWN = 0 ATTYPEUNKNOWN = 0
} }
export interface SendPicElement { export type SendPicElement = SendElementBase<ElementType.PIC> & ElementBase<'picElement'>;
elementType: ElementType.PIC;
elementId: string;
picElement: PicElement;
}
export interface ReplyElement { export interface ReplyElement {
sourceMsgIdInRecords?: string; sourceMsgIdInRecords?: string;
@ -375,53 +278,27 @@ export interface ReplyElement {
replyMsgClientSeq?: string; replyMsgClientSeq?: string;
} }
export interface SendReplyElement { export type SendReplyElement = SendElementBase<ElementType.REPLY> & ElementBase<'replyElement'>;
elementType: ElementType.REPLY;
elementId: string;
replyElement: ReplyElement;
}
export interface SendFaceElement { export type SendFaceElement = SendElementBase<ElementType.FACE> & ElementBase<'faceElement'>;
elementType: ElementType.FACE;
elementId: string;
faceElement: FaceElement;
}
export interface SendMarketFaceElement { export type SendMarketFaceElement = SendElementBase<ElementType.MFACE> & ElementBase<'marketFaceElement'>;
elementType: ElementType.MFACE;
marketFaceElement: MarketFaceElement;
}
export interface SendStructLongMsgElement { export type SendStructLongMsgElement = SendElementBase<ElementType.STRUCTLONGMSG> & ElementBase<'structLongMsgElement'>;
elementType: ElementType.STRUCTLONGMSG;
elementId: string;
structLongMsgElement: StructLongMsgElement;
}
export interface StructLongMsgElement { export interface StructLongMsgElement {
xmlContent: string; xmlContent: string;
resId: string; resId: string;
} }
export interface SendactionBarElement { export type SendActionBarElement = SendElementBase<ElementType.ACTIONBAR> & ElementBase<'actionBarElement'>;
elementType: ElementType.ACTIONBAR;
elementId: string;
actionBarElement: {
rows: number;
botAppid: string;
};
}
export interface ShareLocationElement { export interface ShareLocationElement {
text: string; text: string;
ext: string; ext: string;
} }
export interface SendShareLocationElement { export type SendShareLocationElement = SendElementBase<ElementType.SHARELOCATION> & ElementBase<'shareLocationElement'>;
elementType: ElementType.SHARELOCATION;
elementId: string;
shareLocationElement?: ShareLocationElement;
}
export interface FileElement { export interface FileElement {
fileMd5?: string; fileMd5?: string;
@ -441,29 +318,13 @@ export interface FileElement {
fileBizId?: number; fileBizId?: number;
} }
export interface SendFileElement { export type SendFileElement = SendElementBase<ElementType.FILE> & ElementBase<'fileElement'>;
elementType: ElementType.FILE;
elementId: string;
fileElement: FileElement;
}
export interface SendVideoElement { export type SendVideoElement = SendElementBase<ElementType.VIDEO> & ElementBase<'videoElement'>;
elementType: ElementType.VIDEO;
elementId: string;
videoElement: VideoElement;
}
export interface SendArkElement { export type SendArkElement = SendElementBase<ElementType.ARK> & ElementBase<'arkElement'>;
elementType: ElementType.ARK;
elementId: string;
arkElement: ArkElement;
}
export interface SendMarkdownElement { export type SendMarkdownElement = SendElementBase<ElementType.MARKDOWN> & ElementBase<'markdownElement'>;
elementType: ElementType.MARKDOWN;
elementId: string;
markdownElement: MarkdownElement;
}
export type SendMessageElement = SendTextElement | SendPttElement | export type SendMessageElement = SendTextElement | SendPttElement |
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
@ -480,7 +341,7 @@ export interface TextElement {
export interface MessageElement { export interface MessageElement {
elementType: ElementType, elementType: ElementType,
elementId: string, elementId: string,
extBufForUI: string,//"0x", extBufForUI?: string, //"0x",
textElement?: TextElement; textElement?: TextElement;
faceElement?: FaceElement, faceElement?: FaceElement,
marketFaceElement?: MarketFaceElement, marketFaceElement?: MarketFaceElement,
@ -509,7 +370,6 @@ export interface MessageElement {
taskTopMsgElement?: TaskTopMsgElement, taskTopMsgElement?: TaskTopMsgElement,
recommendedMsgElement?: RecommendedMsgElement, recommendedMsgElement?: RecommendedMsgElement,
actionBarElement?: ActionBarElement actionBarElement?: ActionBarElement
} }
export enum AtType { export enum AtType {
@ -578,7 +438,7 @@ export interface PttElement {
fileSize: string; // "4261" fileSize: string; // "4261"
fileSubId: string; // "0" fileSubId: string; // "0"
fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV" fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV"
formatType: string; // 1 formatType: number; // 1
invalidState: number; // 0 invalidState: number; // 0
md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6" md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6"
playState: number; // 0 playState: number; // 0
@ -589,6 +449,7 @@ export interface PttElement {
voiceChangeType: number; // 0 voiceChangeType: number; // 0
voiceType: number; // 0 voiceType: number; // 0
waveAmplitudes: number[]; waveAmplitudes: number[];
autoConvertText: number;
} }
export interface ArkElement { export interface ArkElement {
@ -794,7 +655,8 @@ export interface InlineKeyboardElementRowButton {
export interface InlineKeyboardElement { export interface InlineKeyboardElement {
rows: [{ rows: [{
buttons: InlineKeyboardElementRowButton[] buttons: InlineKeyboardElementRowButton[]
}]; }],
botAppid: string;
} }
export interface TipAioOpGrayTipElement { // 这是什么提示来着? export interface TipAioOpGrayTipElement { // 这是什么提示来着?

View File

@ -1,4 +1,6 @@
import { import {
ChatType,
ElementType,
MessageElement, MessageElement,
RawMessage, RawMessage,
SendArkElement, SendArkElement,
@ -28,30 +30,42 @@ import {
PacketMsgVideoElement, PacketMsgVideoElement,
PacketMultiMsgElement PacketMultiMsgElement
} from "@/core/packet/msg/element"; } from "@/core/packet/msg/element";
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message"; import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message";
import { LogWrapper } from "@/common/log"; import {LogWrapper} from "@/common/log";
type SendMessageElementMap = { const SupportedElementTypes = [
textElement: SendTextElement, ElementType.TEXT,
picElement: SendPicElement, ElementType.PIC,
replyElement: SendReplyElement, ElementType.REPLY,
faceElement: SendFaceElement, ElementType.FACE,
marketFaceElement: SendMarketFaceElement, ElementType.MFACE,
videoElement: SendVideoElement, ElementType.VIDEO,
fileElement: SendFileElement, ElementType.FILE,
pttElement: SendPttElement, ElementType.PTT,
arkElement: SendArkElement, ElementType.ARK,
markdownElement: SendMarkdownElement, ElementType.MARKDOWN,
structLongMsgElement: SendStructLongMsgElement ElementType.STRUCTLONGMSG
];
type SendMessageTypeElementMap = {
[ElementType.TEXT]: SendTextElement,
[ElementType.PIC]: SendPicElement,
[ElementType.FILE]: SendFileElement,
[ElementType.PTT]: SendPttElement,
[ElementType.VIDEO]: SendVideoElement,
[ElementType.FACE]: SendFaceElement,
[ElementType.REPLY]: SendReplyElement,
[ElementType.ARK]: SendArkElement,
[ElementType.MFACE]: SendMarketFaceElement,
[ElementType.STRUCTLONGMSG]: SendStructLongMsgElement,
[ElementType.MARKDOWN]: SendMarkdownElement,
}; };
type RawToPacketMsgConverters = { type ElementToPacketMsgConverters = {
[K in keyof SendMessageElementMap]: ( [K in keyof SendMessageTypeElementMap]: (
element: SendMessageElementMap[K], sendElement: MessageElement
msg?: RawMessage, ) => IPacketMsgElement<SendMessageTypeElementMap[K]>;
elementWrapper?: MessageElement, }
) => IPacketMsgElement<SendMessageElementMap[K]> | null;
};
export type rawMsgWithSendMsg = { export type rawMsgWithSendMsg = {
senderUin: number; senderUin: number;
@ -69,6 +83,10 @@ export class PacketMsgConverter {
this.logger = logger; this.logger = logger;
} }
private isValidElementType(type: ElementType): type is keyof ElementToPacketMsgConverters {
return SupportedElementTypes.includes(type);
}
rawMsgWithSendMsgToPacketMsg(msg: rawMsgWithSendMsg): PacketMsg { rawMsgWithSendMsgToPacketMsg(msg: rawMsgWithSendMsg): PacketMsg {
return { return {
senderUid: msg.senderUid ?? '', senderUid: msg.senderUid ?? '',
@ -77,55 +95,64 @@ export class PacketMsgConverter {
groupId: msg.groupId, groupId: msg.groupId,
time: msg.time, time: msg.time,
msg: msg.msg.map((element) => { msg: msg.msg.map((element) => {
const key = (Object.keys(this.rawToPacketMsgConverters) as Array<keyof SendMessageElementMap>).find( if (!this.isValidElementType(element.elementType)) return null;
(k) => (element as any)[k] !== undefined // TODO: return this.rawToPacketMsgConverters[element.elementType](element as MessageElement);
);
if (key) {
const elementData = (element as any)[key]; // TODO:
if (elementData) return this.rawToPacketMsgConverters[key](element as any);
}
return null;
}).filter((e) => e !== null) }).filter((e) => e !== null)
}; };
} }
private rawToPacketMsgConverters: RawToPacketMsgConverters = { rawMsgToPacketMsg(msg: RawMessage): PacketMsg {
textElement: (element: SendTextElement) => { return {
if (element.textElement.atType) { seq: +msg.msgSeq,
return new PacketMsgAtElement(element); groupId: msg.chatType === ChatType.KCHATTYPEGROUP ? +msg.parentMsgPeer.peerUid : undefined,
senderUid: msg.senderUid,
senderUin: +msg.senderUin,
senderName: msg.sendMemberName ?? msg.sendRemarkName ?? msg.sendNickName ?? 'QQ用户',
time: +msg.msgTime,
msg: msg.elements.map((element) => {
if (!this.isValidElementType(element.elementType)) return null;
return this.rawToPacketMsgConverters[element.elementType](element);
}).filter((e) => e !== null)
}
}
private rawToPacketMsgConverters: ElementToPacketMsgConverters = {
[ElementType.TEXT]: (element) => {
if (element.textElement?.atType) {
return new PacketMsgAtElement(element as SendTextElement);
} }
return new PacketMsgTextElement(element); return new PacketMsgTextElement(element as SendTextElement);
}, },
picElement: (element: SendPicElement) => { [ElementType.PIC]: (element) => {
return new PacketMsgPicElement(element); return new PacketMsgPicElement(element as SendPicElement);
}, },
replyElement: (element: SendReplyElement) => { [ElementType.REPLY]: (element) => {
return new PacketMsgReplyElement(element); return new PacketMsgReplyElement(element as SendReplyElement);
}, },
faceElement: (element: SendFaceElement) => { [ElementType.FACE]: (element) => {
return new PacketMsgFaceElement(element); return new PacketMsgFaceElement(element as SendFaceElement);
}, },
marketFaceElement: (element: SendMarketFaceElement) => { [ElementType.MFACE]: (element) => {
return new PacketMsgMarkFaceElement(element); return new PacketMsgMarkFaceElement(element as SendMarketFaceElement);
}, },
videoElement: (element: SendVideoElement) => { [ElementType.VIDEO]: (element) => {
return new PacketMsgVideoElement(element); return new PacketMsgVideoElement(element as SendVideoElement);
}, },
fileElement: (element: SendFileElement) => { [ElementType.FILE]: (element) => {
return new PacketMsgFileElement(element); return new PacketMsgFileElement(element as SendFileElement);
}, },
pttElement: (element: SendPttElement) => { [ElementType.PTT]: (element) => {
return new PacketMsgPttElement(element); return new PacketMsgPttElement(element as SendPttElement);
}, },
arkElement: (element: SendArkElement) => { [ElementType.ARK]: (element) => {
return new PacketMsgLightAppElement(element); return new PacketMsgLightAppElement(element as SendArkElement);
}, },
markdownElement: (element: SendMarkdownElement) => { [ElementType.MARKDOWN]: (element) => {
return new PacketMsgMarkDownElement(element); return new PacketMsgMarkDownElement(element as SendMarkdownElement);
}, },
// TODO: check this logic, move it in arkElement? // TODO: check this logic, move it in arkElement?
structLongMsgElement: (element: SendStructLongMsgElement) => { [ElementType.STRUCTLONGMSG]: (element) => {
return new PacketMultiMsgElement(element); return new PacketMultiMsgElement(element as SendStructLongMsgElement);
} }
}; };
} }

View File

@ -466,6 +466,7 @@ export class OneBotMsgApi {
}, },
}) => ({ }) => ({
elementType: ElementType.MFACE, elementType: ElementType.MFACE,
elementId: '',
marketFaceElement: { marketFaceElement: {
emojiPackageId: emoji_package_id, emojiPackageId: emoji_package_id,
emojiId: emoji_id, emojiId: emoji_id,