From 7ab6a10fc9cd26ab5fc37daad26100b91168ebfa Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Sun, 27 Oct 2024 04:16:15 +0800 Subject: [PATCH] refactor & fix: refactor msg entity & adjust some wrong definition --- src/core/apis/file.ts | 2 +- src/core/entities/msg.ts | 244 +++++++------------------------ src/core/packet/msg/converter.ts | 135 ++++++++++------- src/onebot/api/msg.ts | 1 + 4 files changed, 136 insertions(+), 246 deletions(-) diff --git a/src/core/apis/file.ts b/src/core/apis/file.ts index 5202850a..de41cda5 100644 --- a/src/core/apis/file.ts +++ b/src/core/apis/file.ts @@ -238,7 +238,7 @@ export class NTQQFileApi { fileName: fileName, filePath: path, md5HexStr: md5, - fileSize: fileSize, + fileSize: fileSize.toString(), duration: duration ?? 1, formatType: 1, voiceType: 1, diff --git a/src/core/entities/msg.ts b/src/core/entities/msg.ts index 0c77e3b7..1a4a38ce 100644 --- a/src/core/entities/msg.ts +++ b/src/core/entities/msg.ts @@ -27,94 +27,70 @@ export interface GetFileListParam { export enum ElementType { UNKNOWN = 0, - TEXT = 1, - PIC = 2, - FILE = 3, - PTT = 4, - VIDEO = 5, - FACE = 6, - REPLY = 7, - + GreyTip = 8, // “小灰条”,包括拍一拍 (Poke)、撤回提示等 WALLET = 9, - - /** - * “小灰条”,包括拍一拍 (Poke)、撤回提示等 - */ - GreyTip = 8, - ARK = 10, - MFACE = 11, - LIVEGIFT = 12, - STRUCTLONGMSG = 13, - MARKDOWN = 14, - GIPHY = 15, - MULTIFORWARD = 16, - INLINEKEYBOARD = 17, - INTEXTGIFT = 18, - CALENDAR = 19, - YOLOGAMERESULT = 20, - AVRECORD = 21, - FEED = 22, - TOFURECORD = 23, - ACEBUBBLE = 24, - ACTIVITY = 25, - TOFU = 26, - FACEBUBBLE = 27, - SHARELOCATION = 28, - TASKTOPMSG = 29, - RECOMMENDEDMSG = 43, - ACTIONBAR = 44 } +type ElementFullBase = Omit; + +type ElementBase< + K extends keyof ElementFullBase, + S extends Partial<{ [P in K]: keyof NonNullable | Array> }> = {} +> = { + [P in K]: + S[P] extends Array + ? Pick, U & keyof NonNullable> + : S[P] extends keyof NonNullable + ? Pick, S[P]> + : NonNullable; +}; + +export interface SendElementBase { + elementType: ET; + elementId: string; + extBufForUI?: string; +} + export interface ActionBarElement { rows: InlineKeyboardRow[]; botAppid: string; } -export interface SendActionBarElement { - elementType: ElementType.ACTIONBAR; - elementId: string; - actionBarElement: ActionBarElement; -} - export interface RecommendedMsgElement { rows: InlineKeyboardRow[]; botAppid: string; } -export interface SendRecommendedMsgElement { - elementType: ElementType.RECOMMENDEDMSG; - elementId: string; - recommendedMsgElement: RecommendedMsgElement; -} +export type SendRecommendedMsgElement = SendElementBase & ElementBase<'recommendedMsgElement'>; export interface InlineKeyboardButton { id: string; @@ -171,11 +147,7 @@ export enum NTMsgType { KMSGTYPEWALLET = 10 } -export interface SendTaskTopMsgElement { - elementType: ElementType.TASKTOPMSG; - elementId: string; - taskTopMsgElement: TaskTopMsgElement; -} +export type SendTaskTopMsgElement = SendElementBase & ElementBase<'taskTopMsgElement'>; export interface TofuRecordElement { type: number; @@ -194,11 +166,7 @@ export interface TofuRecordElement { onscreennotify: boolean; } -export interface SendTofuRecordElement { - elementType: ElementType.TOFURECORD; - elementId: string; - tofuRecordElement: TofuRecordElement; -} +export type SendTofuRecordElement = SendElementBase & ElementBase<'tofuRecordElement'>; export interface FaceBubbleElement { faceCount: number; @@ -216,12 +184,7 @@ export interface FaceBubbleElement { }; } -export interface SendFaceBubbleElement { - elementType: ElementType.FACEBUBBLE; - elementId: string; - faceBubbleElement: FaceBubbleElement; - -} +export type SendFaceBubbleElement = SendElementBase & ElementBase<'faceBubbleElement'>; export interface AvRecordElement { type: number; @@ -232,11 +195,7 @@ export interface AvRecordElement { extraType: number; } -export interface SendavRecordElement { - elementType: ElementType.AVRECORD; - elementId: string; - avRecordElement: AvRecordElement; -} +export type SendAvRecordElement = SendElementBase & ElementBase<'avRecordElement'>; export interface YoloUserInfo { uid: string; @@ -245,24 +204,13 @@ export interface YoloUserInfo { bizId: string; } -export interface SendInlineKeyboardElement { - elementType: ElementType.INLINEKEYBOARD; - elementId: string; - inlineKeyboardElement: { - rows: number; - botAppid: string; - }; - -} +export type SendInlineKeyboardElement = SendElementBase & ElementBase<'inlineKeyboardElement'>; export interface YoloGameResultElement { UserInfo: YoloUserInfo[]; } -export interface SendYoloGameResultElement { - elementType: ElementType.YOLOGAMERESULT; - yoloGameResultElement: YoloGameResultElement; -} +export type SendYoloGameResultElement = SendElementBase & ElementBase<'yoloGameResultElement'>; export interface GiphyElement { id: string; @@ -271,17 +219,9 @@ export interface GiphyElement { height: number; } -export interface SendGiphyElement { - elementType: ElementType.GIPHY; - elementId: string; - giphyElement: GiphyElement; -} +export type SendGiphyElement = SendElementBase & ElementBase<'giphyElement'>; -export interface SendWalletElement { - elementType: ElementType.UNKNOWN;//不做 设置位置 - elementId: string; - walletElement: Record; -} +export type SendWalletElement = SendElementBase & ElementBase<'walletElement'>; export interface CalendarElement { summary: string; @@ -291,49 +231,16 @@ export interface CalendarElement { schema: string; } -export interface SendCalendarElement { - elementType: ElementType.CALENDAR; - elementId: string; - calendarElement: CalendarElement; -} +export type SendCalendarElement = SendElementBase & ElementBase<'calendarElement'>; -export interface SendliveGiftElement { - elementType: ElementType.LIVEGIFT; - elementId: string; - liveGiftElement: Record; -} +export type SendLiveGiftElement = SendElementBase & ElementBase<'liveGiftElement'>; -export interface SendTextElement { - elementType: ElementType.TEXT; - elementId: string; - textElement: { - content: string; - atType: number; - atUid: string; - atTinyId: string; - atNtUid: string; - }; -} +export type SendTextElement = SendElementBase & ElementBase<'textElement'>; -export interface SendPttElement { - elementType: ElementType.PTT; - elementId: string; - 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 type SendPttElement = SendElementBase & ElementBase<'pttElement', { + pttElement: ['fileName', 'filePath', 'md5HexStr', 'fileSize', 'duration', 'formatType', 'voiceType', + 'voiceChangeType', 'canConvert2Text', 'waveAmplitudes', 'fileSubId', 'playState', 'autoConvertText'] +}>; export enum PicType { gif = 2000, @@ -359,11 +266,7 @@ export enum NTMsgAtType { ATTYPEUNKNOWN = 0 } -export interface SendPicElement { - elementType: ElementType.PIC; - elementId: string; - picElement: PicElement; -} +export type SendPicElement = SendElementBase & ElementBase<'picElement'>; export interface ReplyElement { sourceMsgIdInRecords?: string; @@ -375,53 +278,27 @@ export interface ReplyElement { replyMsgClientSeq?: string; } -export interface SendReplyElement { - elementType: ElementType.REPLY; - elementId: string; - replyElement: ReplyElement; -} +export type SendReplyElement = SendElementBase & ElementBase<'replyElement'>; -export interface SendFaceElement { - elementType: ElementType.FACE; - elementId: string; - faceElement: FaceElement; -} +export type SendFaceElement = SendElementBase & ElementBase<'faceElement'>; -export interface SendMarketFaceElement { - elementType: ElementType.MFACE; - marketFaceElement: MarketFaceElement; -} +export type SendMarketFaceElement = SendElementBase & ElementBase<'marketFaceElement'>; -export interface SendStructLongMsgElement { - elementType: ElementType.STRUCTLONGMSG; - elementId: string; - structLongMsgElement: StructLongMsgElement; -} +export type SendStructLongMsgElement = SendElementBase & ElementBase<'structLongMsgElement'>; export interface StructLongMsgElement { xmlContent: string; resId: string; } -export interface SendactionBarElement { - elementType: ElementType.ACTIONBAR; - elementId: string; - actionBarElement: { - rows: number; - botAppid: string; - }; -} +export type SendActionBarElement = SendElementBase & ElementBase<'actionBarElement'>; export interface ShareLocationElement { text: string; ext: string; } -export interface SendShareLocationElement { - elementType: ElementType.SHARELOCATION; - elementId: string; - shareLocationElement?: ShareLocationElement; -} +export type SendShareLocationElement = SendElementBase & ElementBase<'shareLocationElement'>; export interface FileElement { fileMd5?: string; @@ -441,29 +318,13 @@ export interface FileElement { fileBizId?: number; } -export interface SendFileElement { - elementType: ElementType.FILE; - elementId: string; - fileElement: FileElement; -} +export type SendFileElement = SendElementBase & ElementBase<'fileElement'>; -export interface SendVideoElement { - elementType: ElementType.VIDEO; - elementId: string; - videoElement: VideoElement; -} +export type SendVideoElement = SendElementBase & ElementBase<'videoElement'>; -export interface SendArkElement { - elementType: ElementType.ARK; - elementId: string; - arkElement: ArkElement; -} +export type SendArkElement = SendElementBase & ElementBase<'arkElement'>; -export interface SendMarkdownElement { - elementType: ElementType.MARKDOWN; - elementId: string; - markdownElement: MarkdownElement; -} +export type SendMarkdownElement = SendElementBase & ElementBase<'markdownElement'>; export type SendMessageElement = SendTextElement | SendPttElement | SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | @@ -480,7 +341,7 @@ export interface TextElement { export interface MessageElement { elementType: ElementType, elementId: string, - extBufForUI: string,//"0x", + extBufForUI?: string, //"0x", textElement?: TextElement; faceElement?: FaceElement, marketFaceElement?: MarketFaceElement, @@ -509,7 +370,6 @@ export interface MessageElement { taskTopMsgElement?: TaskTopMsgElement, recommendedMsgElement?: RecommendedMsgElement, actionBarElement?: ActionBarElement - } export enum AtType { @@ -578,7 +438,7 @@ export interface PttElement { fileSize: string; // "4261" fileSubId: string; // "0" fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV" - formatType: string; // 1 + formatType: number; // 1 invalidState: number; // 0 md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6" playState: number; // 0 @@ -589,6 +449,7 @@ export interface PttElement { voiceChangeType: number; // 0 voiceType: number; // 0 waveAmplitudes: number[]; + autoConvertText: number; } export interface ArkElement { @@ -794,7 +655,8 @@ export interface InlineKeyboardElementRowButton { export interface InlineKeyboardElement { rows: [{ buttons: InlineKeyboardElementRowButton[] - }]; + }], + botAppid: string; } export interface TipAioOpGrayTipElement { // 这是什么提示来着? diff --git a/src/core/packet/msg/converter.ts b/src/core/packet/msg/converter.ts index 8e2091ec..2e4d4562 100644 --- a/src/core/packet/msg/converter.ts +++ b/src/core/packet/msg/converter.ts @@ -1,4 +1,6 @@ import { + ChatType, + ElementType, MessageElement, RawMessage, SendArkElement, @@ -28,30 +30,42 @@ import { PacketMsgVideoElement, PacketMultiMsgElement } from "@/core/packet/msg/element"; -import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message"; -import { LogWrapper } from "@/common/log"; +import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message"; +import {LogWrapper} from "@/common/log"; -type SendMessageElementMap = { - textElement: SendTextElement, - picElement: SendPicElement, - replyElement: SendReplyElement, - faceElement: SendFaceElement, - marketFaceElement: SendMarketFaceElement, - videoElement: SendVideoElement, - fileElement: SendFileElement, - pttElement: SendPttElement, - arkElement: SendArkElement, - markdownElement: SendMarkdownElement, - structLongMsgElement: SendStructLongMsgElement +const SupportedElementTypes = [ + ElementType.TEXT, + ElementType.PIC, + ElementType.REPLY, + ElementType.FACE, + ElementType.MFACE, + ElementType.VIDEO, + ElementType.FILE, + ElementType.PTT, + ElementType.ARK, + ElementType.MARKDOWN, + 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 = { - [K in keyof SendMessageElementMap]: ( - element: SendMessageElementMap[K], - msg?: RawMessage, - elementWrapper?: MessageElement, - ) => IPacketMsgElement | null; -}; +type ElementToPacketMsgConverters = { + [K in keyof SendMessageTypeElementMap]: ( + sendElement: MessageElement + ) => IPacketMsgElement; +} export type rawMsgWithSendMsg = { senderUin: number; @@ -69,6 +83,10 @@ export class PacketMsgConverter { this.logger = logger; } + private isValidElementType(type: ElementType): type is keyof ElementToPacketMsgConverters { + return SupportedElementTypes.includes(type); + } + rawMsgWithSendMsgToPacketMsg(msg: rawMsgWithSendMsg): PacketMsg { return { senderUid: msg.senderUid ?? '', @@ -77,55 +95,64 @@ export class PacketMsgConverter { groupId: msg.groupId, time: msg.time, msg: msg.msg.map((element) => { - const key = (Object.keys(this.rawToPacketMsgConverters) as Array).find( - (k) => (element as any)[k] !== undefined // TODO: - ); - if (key) { - const elementData = (element as any)[key]; // TODO: - if (elementData) return this.rawToPacketMsgConverters[key](element as any); - } - return null; + if (!this.isValidElementType(element.elementType)) return null; + return this.rawToPacketMsgConverters[element.elementType](element as MessageElement); }).filter((e) => e !== null) }; } - private rawToPacketMsgConverters: RawToPacketMsgConverters = { - textElement: (element: SendTextElement) => { - if (element.textElement.atType) { - return new PacketMsgAtElement(element); + rawMsgToPacketMsg(msg: RawMessage): PacketMsg { + return { + seq: +msg.msgSeq, + 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) => { - return new PacketMsgPicElement(element); + [ElementType.PIC]: (element) => { + return new PacketMsgPicElement(element as SendPicElement); }, - replyElement: (element: SendReplyElement) => { - return new PacketMsgReplyElement(element); + [ElementType.REPLY]: (element) => { + return new PacketMsgReplyElement(element as SendReplyElement); }, - faceElement: (element: SendFaceElement) => { - return new PacketMsgFaceElement(element); + [ElementType.FACE]: (element) => { + return new PacketMsgFaceElement(element as SendFaceElement); }, - marketFaceElement: (element: SendMarketFaceElement) => { - return new PacketMsgMarkFaceElement(element); + [ElementType.MFACE]: (element) => { + return new PacketMsgMarkFaceElement(element as SendMarketFaceElement); }, - videoElement: (element: SendVideoElement) => { - return new PacketMsgVideoElement(element); + [ElementType.VIDEO]: (element) => { + return new PacketMsgVideoElement(element as SendVideoElement); }, - fileElement: (element: SendFileElement) => { - return new PacketMsgFileElement(element); + [ElementType.FILE]: (element) => { + return new PacketMsgFileElement(element as SendFileElement); }, - pttElement: (element: SendPttElement) => { - return new PacketMsgPttElement(element); + [ElementType.PTT]: (element) => { + return new PacketMsgPttElement(element as SendPttElement); }, - arkElement: (element: SendArkElement) => { - return new PacketMsgLightAppElement(element); + [ElementType.ARK]: (element) => { + return new PacketMsgLightAppElement(element as SendArkElement); }, - markdownElement: (element: SendMarkdownElement) => { - return new PacketMsgMarkDownElement(element); + [ElementType.MARKDOWN]: (element) => { + return new PacketMsgMarkDownElement(element as SendMarkdownElement); }, // TODO: check this logic, move it in arkElement? - structLongMsgElement: (element: SendStructLongMsgElement) => { - return new PacketMultiMsgElement(element); + [ElementType.STRUCTLONGMSG]: (element) => { + return new PacketMultiMsgElement(element as SendStructLongMsgElement); } }; } diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index b4b008a3..1b4cd02b 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -466,6 +466,7 @@ export class OneBotMsgApi { }, }) => ({ elementType: ElementType.MFACE, + elementId: '', marketFaceElement: { emojiPackageId: emoji_package_id, emojiId: emoji_id,