From 38a098c77d5d798c9a967f4519633ccbfdd9a24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Thu, 21 Nov 2024 10:36:08 +0800 Subject: [PATCH] refactor: type --- src/common/log.ts | 10 +- src/core/entities/element.ts | 348 +++++++++++++++++++ src/core/entities/index.ts | 3 +- src/core/entities/msg.ts | 531 +++-------------------------- src/core/packet/message/element.ts | 4 +- src/onebot/api/msg.ts | 26 +- src/onebot/types/entity.ts | 134 ++++---- src/onebot/types/message.ts | 191 ++++++----- 8 files changed, 591 insertions(+), 656 deletions(-) create mode 100644 src/core/entities/element.ts diff --git a/src/common/log.ts b/src/common/log.ts index 42741beb..10da3631 100644 --- a/src/common/log.ts +++ b/src/common/log.ts @@ -2,7 +2,7 @@ import winston, { format, transports } from 'winston'; import { truncateString } from '@/common/helper'; import path from 'node:path'; import fs from 'node:fs'; -import { AtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core'; +import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core'; export enum LogLevel { DEBUG = 'debug', @@ -270,12 +270,12 @@ function msgElementToText(element: MessageElement, msg: RawMessage, recursiveLev } function textElementToText(textElement: any): string { - if (textElement.atType === AtType.notAt) { + if (textElement.atType === NTMsgAtType.ATTYPEUNKNOWN) { const originalContentLines = textElement.content.split('\n'); return `${originalContentLines[0]}${originalContentLines.length > 1 ? ' ...' : ''}`; - } else if (textElement.atType === AtType.atAll) { + } else if (textElement.atType === NTMsgAtType.ATTYPEALL) { return `@全体成员`; - } else if (textElement.atType === AtType.atUser) { + } else if (textElement.atType === NTMsgAtType.ATTYPEONE) { return `${textElement.content} (${textElement.atUid})`; } return ''; @@ -290,5 +290,5 @@ function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: ? rawMessageToText(recordMsgOrNull, recursiveLevel + 1) : `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})` - }]`; + }]`; } \ No newline at end of file diff --git a/src/core/entities/element.ts b/src/core/entities/element.ts new file mode 100644 index 00000000..67e9e6e9 --- /dev/null +++ b/src/core/entities/element.ts @@ -0,0 +1,348 @@ +import { ElementType, FaceType, MessageElement, NTGrayTipElementSubTypeV2, PicSubType, PicType, TipAioOpGrayTipElement, TipGroupElement, viedo_type } from "./msg"; + +type ElementFullBase = Omit; + +export interface SendElementBase { + elementType: ET; + elementId: string; + extBufForUI?: string; +} + +type ElementBase< + K extends keyof ElementFullBase, + S extends Partial<{ [P in K]: keyof NonNullable | Array> }> = object +> = { + [P in K]: + S[P] extends Array + ? Pick, U & keyof NonNullable> + : S[P] extends keyof NonNullable + ? Pick, S[P]> + : NonNullable; + }; + +export interface TextElement { + content: string; + atType: number; + atUid: string; + atTinyId: string; + atNtUid: string; +} + +export interface FaceElement { + faceIndex: number; + faceType: FaceType; + faceText?: string; + packId?: string; + stickerId?: string; + sourceType?: number; + stickerType?: number; + resultId?: string; + surpriseId?: string; + randomType?: number; +} + +export interface GrayTipElement { + subElementType: NTGrayTipElementSubTypeV2; + revokeElement: { + operatorRole: string; + operatorUid: string; + operatorNick: string; + operatorRemark: string; + operatorMemRemark?: string; + wording: string; // 自定义的撤回提示语 + }; + aioOpGrayTipElement: TipAioOpGrayTipElement; + groupElement: TipGroupElement; + xmlElement: { + content: string; + templId: string; + }; + jsonGrayTipElement: { + busiId?: number; + jsonStr: string; + }; +} + + +export interface ArkElement { + bytesData: string; + linkInfo: null; + subElementType: null; +} + +export interface MarketFaceElement { + emojiPackageId: number; + faceName: string; + emojiId: string; + key: string; +} + +export interface VideoElement { + filePath: string; + fileName: string; + videoMd5?: string; + thumbMd5?: string; + fileTime?: number; // second + thumbSize?: number; // byte + fileFormat?: viedo_type; // 2表示mp4 参考下面条目 + fileSize?: string; // byte + thumbWidth?: number; + thumbHeight?: number; + busiType?: 0; // + subBusiType?: 0; // 未知 + thumbPath?: Map; + transferStatus?: 0; // 未知 + progress?: 0; // 下载进度? + invalidState?: 0; // 未知 + fileUuid?: string; // 可以用于下载链接? + fileSubId?: string; + fileBizId?: null; + originVideoMd5?: string; + import_rich_media_context?: null; + sourceVideoCodecFormat?: number; +} +export interface PicElement { + md5HexStr?: string; + filePath?: string; + fileSize: number | string;//number + picWidth: number; + picHeight: number; + fileName: string; + sourcePath: string; + original: boolean; + picType: PicType; + picSubType?: PicSubType; + fileUuid: string; + fileSubId: string; + thumbFileSize: number; + summary: string; + thumbPath: Map; + originImageMd5?: string; + originImageUrl?: string; +} +export interface InlineKeyboardButton { + id: string; + label: string; + visitedLabel: string; + unsupportTips: string; + data: string; + specifyRoleIds: string[]; + specifyTinyids: string[]; + style: number; + type: number; + clickLimit: number; + atBotShowChannelList: boolean; + permissionType: number; +} + +// 非element +interface InlineKeyboardRow { + buttons: InlineKeyboardButton[]; +} + +// 非element +interface TofuElementContent { + color: string; + tittle: string; +} + +export interface ActionBarElement { + rows: InlineKeyboardRow[]; + botAppid: string; +} + +export interface RecommendedMsgElement { + rows: InlineKeyboardRow[]; + botAppid: string; +} + +export interface TofuRecordElement { + type: number; + busiid: string; + busiuuid: string; + descriptionContent: string; + contentlist: TofuElementContent[], + background: string; + icon: string; + uinlist: string[], + uidlist: string[], + busiExtra: string; + updateTime: string; + dependedmsgid: string; + msgtime: string; + onscreennotify: boolean; +} + +export interface FileElement { + fileMd5?: string; + fileName: string; + filePath: string; + fileSize: string; + picHeight?: number; + picWidth?: number; + folderId?: string; + picThumbPath?: Map; + file10MMd5?: string; + fileSha?: string; + fileSha3?: string; + fileUuid?: string; + fileSubId?: string; + thumbFileSize?: number; + fileBizId?: number; +} + +export interface ShareLocationElement { + text: string; + ext: string; +} + +export interface StructLongMsgElement { + xmlContent: string; + resId: string; +} + +export interface ReplyElement { + sourceMsgIdInRecords?: string; + replayMsgSeq: string; + replayMsgId: string; + senderUin: string; + senderUidStr?: string; + replyMsgTime?: string; + replyMsgClientSeq?: string; +} + +export interface CalendarElement { + summary: string; + msg: string; + expireTimeMs: string; + schemaType: number; + schema: string; +} + +export interface GiphyElement { + id: string; + isClip: boolean; + width: number; + height: number; +} + +export interface AvRecordElement { + type: number; + time: string; + text: string; + mainType: number; + hasRead: boolean; + extraType: number; +} + +// 非element +interface YoloUserInfo { + uid: string; + result: number; + rank: number; + bizId: string; +} + +export interface YoloGameResultElement { + UserInfo: YoloUserInfo[]; +} + +export interface FaceBubbleElement { + faceCount: number; + faceSummary: string; + faceFlag: number; + content: string; + oldVersionStr: string; + faceType: number; + others: string; + yellowFaceInfo: { + index: number; + buf: string; + compatibleText: string; + text: string; + }; +} + +export interface TaskTopMsgElement { + msgTitle: string; + msgSummary: string; + iconUrl: string; + topMsgType: number; +} + +export interface PttElement { + canConvert2Text: boolean; + duration: number; + fileBizId: null; + fileId: number; + fileName: string; + filePath: string; + fileSize: string; + fileSubId: string; + fileUuid: string; // FileId + formatType: number; // Todo 已定义 但是未替换 + invalidState: number; + md5HexStr: string; + playState: number; + progress: number; //进度 + text: string; + transferStatus: number; + translateStatus: number; + voiceChangeType: number; + voiceType: number; + waveAmplitudes: number[]; + autoConvertText: number; +} + +export type SendRecommendedMsgElement = SendElementBase & ElementBase<'recommendedMsgElement'>; + +export type SendTaskTopMsgElement = SendElementBase & ElementBase<'taskTopMsgElement'>; + +export type SendTofuRecordElement = SendElementBase & ElementBase<'tofuRecordElement'>; + +export type SendFaceBubbleElement = SendElementBase & ElementBase<'faceBubbleElement'>; + +export type SendAvRecordElement = SendElementBase & ElementBase<'avRecordElement'>; + +export type SendInlineKeyboardElement = SendElementBase & ElementBase<'inlineKeyboardElement'>; + +export type SendYoloGameResultElement = SendElementBase & ElementBase<'yoloGameResultElement'>; + +export type SendGiphyElement = SendElementBase & ElementBase<'giphyElement'>; + +export type SendWalletElement = SendElementBase & ElementBase<'walletElement'>; + +export type SendCalendarElement = SendElementBase & ElementBase<'calendarElement'>; + +export type SendLiveGiftElement = SendElementBase & ElementBase<'liveGiftElement'>; + +export type SendTextElement = SendElementBase & ElementBase<'textElement'>; + +export type SendReplyElement = SendElementBase & ElementBase<'replyElement'>; + +export type SendFaceElement = SendElementBase & ElementBase<'faceElement'>; + +export type SendMarketFaceElement = SendElementBase & ElementBase<'marketFaceElement'>; + +export type SendStructLongMsgElement = SendElementBase & ElementBase<'structLongMsgElement'>; + +export type SendPicElement = SendElementBase & ElementBase<'picElement'>; + +export type SendPttElement = SendElementBase & ElementBase<'pttElement', { + pttElement: ['fileName', 'filePath', 'md5HexStr', 'fileSize', 'duration', 'formatType', 'voiceType', + 'voiceChangeType', 'canConvert2Text', 'waveAmplitudes', 'fileSubId', 'playState', 'autoConvertText'] +}>; + +export type SendFileElement = SendElementBase & ElementBase<'fileElement'>; + +export type SendVideoElement = SendElementBase & ElementBase<'videoElement'>; + +export type SendArkElement = SendElementBase & ElementBase<'arkElement'>; + +export type SendMarkdownElement = SendElementBase & ElementBase<'markdownElement'>; + +export type SendShareLocationElement = SendElementBase & ElementBase<'shareLocationElement'>; + +export type SendMessageElement = SendTextElement | SendPttElement | + SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | + SendVideoElement | SendArkElement | SendMarkdownElement | SendShareLocationElement; \ No newline at end of file diff --git a/src/core/entities/index.ts b/src/core/entities/index.ts index 9e947a8d..2471a614 100644 --- a/src/core/entities/index.ts +++ b/src/core/entities/index.ts @@ -5,4 +5,5 @@ export * from './notify'; export * from './cache'; export * from './system'; export * from './webapi'; -export * from './sign'; \ No newline at end of file +export * from './sign'; +export * from './element'; \ No newline at end of file diff --git a/src/core/entities/msg.ts b/src/core/entities/msg.ts index 6519861b..18735521 100644 --- a/src/core/entities/msg.ts +++ b/src/core/entities/msg.ts @@ -1,19 +1,22 @@ import { GroupMemberRole } from '@/core'; +import { ActionBarElement, ArkElement, AvRecordElement, CalendarElement, FaceBubbleElement, FaceElement, FileElement, GiphyElement, GrayTipElement, MarketFaceElement, PicElement, PttElement, RecommendedMsgElement, ReplyElement, ShareLocationElement, StructLongMsgElement, TaskTopMsgElement, TextElement, TofuRecordElement, VideoElement, YoloGameResultElement } from './element'; +// 表示对等方的信息 export interface Peer { - chatType: ChatType; - peerUid: string; // 如果是群聊uid为群号,私聊uid就是加密的字符串 - guildId?: string; + chatType: ChatType; // 聊天类型 + peerUid: string; // 对等方的唯一标识符 + guildId?: string; // 可选的频道ID } +// 表示被踢下线的信息 export interface KickedOffLineInfo { - appId: number; - instanceId: number; - sameDevice: boolean; - tipsDesc: string; - tipsTitle: string; - kickedType: number; - securityKickedType: number; + appId: number; // 应用ID + instanceId: number; // 实例ID + sameDevice: boolean; // 是否为同一设备 + tipsDesc: string; // 提示描述 + tipsTitle: string; // 提示标题 + kickedType: number; // 被踢类型 + securityKickedType: number; // 安全踢出类型 } export interface GetFileListParam { @@ -60,69 +63,6 @@ export enum ElementType { ACTIONBAR = 44 } -type ElementFullBase = Omit; - -type ElementBase< - K extends keyof ElementFullBase, - S extends Partial<{ [P in K]: keyof NonNullable | Array> }> = object -> = { - [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 RecommendedMsgElement { - rows: InlineKeyboardRow[]; - botAppid: string; -} - -export type SendRecommendedMsgElement = SendElementBase & ElementBase<'recommendedMsgElement'>; - -export interface InlineKeyboardButton { - id: string; - label: string; - visitedLabel: string; - unsupportTips: string; - data: string; - specifyRoleIds: string[]; - specifyTinyids: string[]; - style: number; - type: number; - clickLimit: number; - atBotShowChannelList: boolean; - permissionType: number; -} - -export interface InlineKeyboardRow { - buttons: InlineKeyboardButton[]; -} - -export interface TofuElementContent { - color: string; - tittle: string; -} - -export interface TaskTopMsgElement { - msgTitle: string; - msgSummary: string; - iconUrl: string; - topMsgType: number; -} - export enum NTMsgType { KMSGTYPEARKSTRUCT = 11, KMSGTYPEFACEBUBBLE = 24, @@ -147,109 +87,15 @@ export enum NTMsgType { KMSGTYPEWALLET = 10 } -export type SendTaskTopMsgElement = SendElementBase & ElementBase<'taskTopMsgElement'>; - -export interface TofuRecordElement { - type: number; - busiid: string; - busiuuid: string; - descriptionContent: string; - contentlist: TofuElementContent[], - background: string; - icon: string; - uinlist: string[], - uidlist: string[], - busiExtra: string; - updateTime: string; - dependedmsgid: string; - msgtime: string; - onscreennotify: boolean; -} - -export type SendTofuRecordElement = SendElementBase & ElementBase<'tofuRecordElement'>; - -export interface FaceBubbleElement { - faceCount: number; - faceSummary: string; - faceFlag: number; - content: string; - oldVersionStr: string; - faceType: number; - others: string; - yellowFaceInfo: { - index: number; - buf: string; - compatibleText: string; - text: string; - }; -} - -export type SendFaceBubbleElement = SendElementBase & ElementBase<'faceBubbleElement'>; - -export interface AvRecordElement { - type: number; - time: string; - text: string; - mainType: number; - hasRead: boolean; - extraType: number; -} - -export type SendAvRecordElement = SendElementBase & ElementBase<'avRecordElement'>; - -export interface YoloUserInfo { - uid: string; - result: number; - rank: number; - bizId: string; -} - -export type SendInlineKeyboardElement = SendElementBase & ElementBase<'inlineKeyboardElement'>; - -export interface YoloGameResultElement { - UserInfo: YoloUserInfo[]; -} - -export type SendYoloGameResultElement = SendElementBase & ElementBase<'yoloGameResultElement'>; - -export interface GiphyElement { - id: string; - isClip: boolean; - width: number; - height: number; -} - -export type SendGiphyElement = SendElementBase & ElementBase<'giphyElement'>; - -export type SendWalletElement = SendElementBase & ElementBase<'walletElement'>; - -export interface CalendarElement { - summary: string; - msg: string; - expireTimeMs: string; - schemaType: number; - schema: string; -} - -export type SendCalendarElement = SendElementBase & ElementBase<'calendarElement'>; - -export type SendLiveGiftElement = SendElementBase & ElementBase<'liveGiftElement'>; - -export type SendTextElement = SendElementBase & ElementBase<'textElement'>; - -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, jpg = 1000 } export enum PicSubType { - normal = 0, // 普通图片,大图 - face = 1 // 表情包小图 + Normal = 0, // 普通图片 + Face = 1 // 表情包小图 + //...待补全 其余见NT Android } export enum NTMsgAtType { @@ -266,78 +112,6 @@ export enum NTMsgAtType { ATTYPEUNKNOWN = 0 } -export type SendPicElement = SendElementBase & ElementBase<'picElement'>; - -export interface ReplyElement { - sourceMsgIdInRecords?: string; - replayMsgSeq: string; - replayMsgId: string; - senderUin: string; - senderUidStr?: string; - replyMsgTime?: string; - replyMsgClientSeq?: string; -} - -export type SendReplyElement = SendElementBase & ElementBase<'replyElement'>; - -export type SendFaceElement = SendElementBase & ElementBase<'faceElement'>; - -export type SendMarketFaceElement = SendElementBase & ElementBase<'marketFaceElement'>; - -export type SendStructLongMsgElement = SendElementBase & ElementBase<'structLongMsgElement'>; - -export interface StructLongMsgElement { - xmlContent: string; - resId: string; -} - -export type SendActionBarElement = SendElementBase & ElementBase<'actionBarElement'>; - -export interface ShareLocationElement { - text: string; - ext: string; -} - -export type SendShareLocationElement = SendElementBase & ElementBase<'shareLocationElement'>; - -export interface FileElement { - fileMd5?: string; - fileName: string; - filePath: string; - fileSize: string; - picHeight?: number; - picWidth?: number; - folderId?: string; - picThumbPath?: Map; - file10MMd5?: string; - fileSha?: string; - fileSha3?: string; - fileUuid?: string; - fileSubId?: string; - thumbFileSize?: number; - fileBizId?: number; -} - -export type SendFileElement = SendElementBase & ElementBase<'fileElement'>; - -export type SendVideoElement = SendElementBase & ElementBase<'videoElement'>; - -export type SendArkElement = SendElementBase & ElementBase<'arkElement'>; - -export type SendMarkdownElement = SendElementBase & ElementBase<'markdownElement'>; - -export type SendMessageElement = SendTextElement | SendPttElement | - SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | - SendVideoElement | SendArkElement | SendMarkdownElement | SendShareLocationElement; - -export interface TextElement { - content: string; - atType: number; - atUid: string; - atTinyId: string; - atNtUid: string; -} - export interface MessageElement { elementType: ElementType, elementId: string, @@ -372,11 +146,6 @@ export interface MessageElement { actionBarElement?: ActionBarElement } -export enum AtType { - notAt = 0, - atAll = 1, - atUser = 2 -} export enum MsgSourceType { K_DOWN_SOURCETYPE_AIOINNER = 1, K_DOWN_SOURCETYPE_BIGSCREEN = 2, @@ -428,59 +197,9 @@ export enum ChatType { KCHATTYPEWEIYUN = 40, } -export interface PttElement { - canConvert2Text: boolean; - duration: number; // 秒数 - fileBizId: null; - fileId: number; // 0 - fileName: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6.amr" - filePath: string; // "/Users//Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/nt_qq_a6b15c9820595d25a56c1633ce19ad40/nt_data/Ptt/2023-11/Ori/e4d09c784d5a2abcb2f9980bdc7acfe6.amr" - fileSize: string; // "4261" - fileSubId: string; // "0" - fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV" - formatType: number; // 1 - invalidState: number; // 0 - md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6" - playState: number; // 0 - progress: number; // 0 - text: string; // "" - transferStatus: number; // 0 - translateStatus: number; // 0 - voiceChangeType: number; // 0 - voiceType: number; // 0 - waveAmplitudes: number[]; - autoConvertText: number; -} - -export interface ArkElement { - bytesData: string; - linkInfo: null; - subElementType: null; -} - export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn'; export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn'; -export interface PicElement { - md5HexStr?: string; - filePath?: string; - fileSize: number | string;//number - picWidth: number; - picHeight: number; - fileName: string; - sourcePath: string; - original: boolean; - picType: PicType; - picSubType?: PicSubType; - fileUuid: string; - fileSubId: string; - thumbFileSize: number; - summary: string; - thumbPath: Map; - originImageMd5?: string; - originImageUrl?: string; // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn -} - export enum NTGrayTipElementSubTypeV2 { GRAYTIP_ELEMENT_SUBTYPE_AIOOP = 15, GRAYTIP_ELEMENT_SUBTYPE_BLOCK = 14, @@ -502,27 +221,6 @@ export enum NTGrayTipElementSubTypeV2 { GRAYTIP_ELEMENT_SUBTYPE_XMLMSG = 12, } -export interface GrayTipElement { - subElementType: NTGrayTipElementSubTypeV2; - revokeElement: { - operatorRole: string; - operatorUid: string; - operatorNick: string; - operatorRemark: string; - operatorMemRemark?: string; - wording: string; // 自定义的撤回提示语 - }; - aioOpGrayTipElement: TipAioOpGrayTipElement; - groupElement: TipGroupElement; - xmlElement: { - content: string; - templId: string; - }; - jsonGrayTipElement: { - busiId?: number; - jsonStr: string; - }; -} export enum FaceType { normal = 1, // 小黄脸 @@ -533,88 +231,9 @@ export enum FaceType { export enum FaceIndex { dice = 358, - RPS = 359 // 石头剪刀布 + rps = 359 } -export interface FaceElement { - faceIndex: number; - faceType: FaceType; - faceText?: string; - packId?: string; - stickerId?: string; - sourceType?: number; - stickerType?: number; - resultId?: string; - surpriseId?: string; - randomType?: number; -} - -export interface MarketFaceElement { - emojiPackageId: number; - faceName: string; - emojiId: string; - key: string; -} - -export interface VideoElement { - filePath: string; - fileName: string; - videoMd5?: string; - thumbMd5?: string; - fileTime?: number; // second - thumbSize?: number; // byte - fileFormat?: viedo_type; // 2表示mp4 参考下面条目 - fileSize?: string; // byte - thumbWidth?: number; - thumbHeight?: number; - busiType?: 0; // - subBusiType?: 0; // 未知 - thumbPath?: Map; - transferStatus?: 0; // 未知 - progress?: 0; // 下载进度? - invalidState?: 0; // 未知 - fileUuid?: string; // 可以用于下载链接? - fileSubId?: string; - fileBizId?: null; - originVideoMd5?: string; - import_rich_media_context?: null; - sourceVideoCodecFormat?: number; -} - -// export enum busiType{ -// public static final int CREATOR_SHARE_ADV_XWORLD = 21; -// public static final int MINI_APP_MINI_GAME = 11; -// public static final int OFFICIAL_ACCOUNT_ADV = 4; -// public static final int OFFICIAL_ACCOUNT_ADV_GAME = 8; -// public static final int OFFICIAL_ACCOUNT_ADV_SHOP = 9; -// public static final int OFFICIAL_ACCOUNT_ADV_VIP = 7; -// public static final int OFFICIAL_ACCOUNT_LAYER_MASK_ADV = 14; -// public static final int OFFICIAL_ACCOUNT_SPORT = 13; -// public static final int OFFICIAL_ACCOUNT_TIAN_QI = 10; -// public static final int PC_QQTAB_ADV = 18; -// public static final int QIQIAOBAN_SDK = 15; -// public static final int QQ_CPS = 16; -// public static final int QQ_WALLET_CPS = 17; -// public static final int QZONE_FEEDS = 0; -// public static final int QZONE_PHOTO_TAIL = 2; -// public static final int QZONE_VIDEO_LAYER = 1; -// public static final int REWARD_GIFT_ADV = 6; -// public static final int REWARD_GROUPGIFT_ADV = 12; -// public static final int REWARD_PERSONAL_ADV = 5; -// public static final int WEISEE_OFFICIAL_ACCOUNT = 3; -// public static final int X_WORLD_CREATOR_ADV = 20; -// public static final int X_WORLD_QZONE_LAYER = 22; -// public static final int X_WORLD_VIDEO_ADV = 19; - -// } -// export enum CategoryBusiType { -// _KCateBusiTypeDefault = 0, -// _kCateBusiTypeFaceCluster = 1, -// _kCateBusiTypeLabelCluster = 4, -// _kCateBusiTypeMonthCluster = 16, -// _kCateBusiTypePoiCluster = 2, -// _kCateBusiTypeYearCluster = 8, -// } export enum viedo_type { VIDEO_FORMAT_AFS = 7, VIDEO_FORMAT_AVI = 1, @@ -734,96 +353,34 @@ export enum SendStatusType { KSEND_STATUS_SUCCESS_NOSEQ = 3 } +// 原始消息 export interface RawMessage { - parentMsgPeer: Peer; - - parentMsgIdList: string[]; - - /** - * 扩展字段,与 Ob11 msg ID 有关 - */ - - - id?: number; - - guildId: string; - - msgRandom: string; - - msgId: string; - - /** - * 消息时间戳(秒) - */ - msgTime: string; - - msgSeq: string; - - msgType: NTMsgType; - - subMsgType: number; - - senderUid: string; - - /** - * 发送者 QQ 号 - */ - senderUin: string; - - /** - * 群号 / 用户 UID - */ - peerUid: string; - - /** - * 群号 / 用户 QQ 号 - */ - peerUin: string; - - /** - * 好友备注(如果是好友消息) - */ - remark?: string; - - /** - * 群名(如果是群消息) - */ - peerName: string; - - /** - * 发送者昵称(如果是好友消息) - */ - sendNickName: string; - - /** - * 发送者好友备注(如果是群消息并且有发送者好友) - */ - sendRemarkName: string; - - /** - * 发送者群名片(如果是群消息) - */ - sendMemberName?: string; - - chatType: ChatType; - - /** - * 消息状态,别人发的 2 是已撤回,自己发的 2 是已发送 - */ - sendStatus?: SendStatusType; - - /** - * 撤回时间,"0" 是没有撤回 - */ - recallTime: string; - - records: RawMessage[]; - - elements: MessageElement[]; - - sourceType: MsgSourceType; - - isOnlineMsg: boolean; + parentMsgPeer: Peer; // 父消息的Peer + parentMsgIdList: string[];// 父消息 ID 列表 + id?: number;// 扩展字段,与 Ob11 msg ID 有关 + guildId: string;// 频道ID + msgRandom: string;// 消息ID相关 + msgId: string;// 雪花ID + msgTime: string;// 消息时间戳 + msgSeq: string;// 消息序列号 + msgType: NTMsgType;// 消息类型 + subMsgType: number;// 子消息类型 + senderUid: string;// 发送者 UID + senderUin: string;// 发送者 QQ 号 + peerUid: string;// 群号 / 用户 UID + peerUin: string;// 群号 / 用户 QQ 号 + remark?: string;// 备注 + peerName: string;// Peer名称 + sendNickName: string;// 发送者昵称 + sendRemarkName: string;// 发送者好友备注 + sendMemberName?: string;// 发送者群名片(如果是群消息) + chatType: ChatType;// 会话类型 + sendStatus?: SendStatusType;// 消息状态 + recallTime: string;// 撤回时间,"0" 是没有撤回 + records: RawMessage[];// 消息记录 + elements: MessageElement[];// 消息元素 + sourceType: MsgSourceType;// 消息来源类型 + isOnlineMsg: boolean;// 是否为在线消息 } export interface QueryMsgsParams { chatInfo: Peer; diff --git a/src/core/packet/message/element.ts b/src/core/packet/message/element.ts index 8142f1cb..dd66ea37 100644 --- a/src/core/packet/message/element.ts +++ b/src/core/packet/message/element.ts @@ -14,7 +14,7 @@ import { GroupFileExtra } from "@/core/packet/transformer/proto"; import { - AtType, + NTMsgAtType, PicType, SendArkElement, SendFaceElement, @@ -82,7 +82,7 @@ export class PacketMsgAtElement extends PacketMsgTextElement { constructor(element: SendTextElement) { super(element); this.targetUid = element.textElement.atNtUid; - this.atAll = element.textElement.atType === AtType.atAll; + this.atAll = element.textElement.atType === NTMsgAtType.ATTYPEALL; } buildElement(): NapProtoEncodeStructType[] { diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index 90e8141d..bf81e1d6 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -2,7 +2,7 @@ import { FileNapCatOneBotUUID } from '@/common/helper'; import { MessageUnique } from '@/common/message-unique'; import { pathToFileURL } from 'node:url'; import { - AtType, + NTMsgAtType, ChatType, CustomMusicSignPostData, ElementType, @@ -61,7 +61,7 @@ export class OneBotMsgApi { rawToOb11Converters: RawToOb11Converters = { textElement: async element => { - if (element.atType === AtType.notAt) { + if (element.atType === NTMsgAtType.ATTYPEUNKNOWN) { let text = element.content; if (!text.trim()) { return null; @@ -76,7 +76,7 @@ export class OneBotMsgApi { }; } else { let qq: string = 'all'; - if (element.atType !== AtType.atAll) { + if (element.atType !== NTMsgAtType.ATTYPEALL) { const { atNtUid /* content */ } = element; let atQQ = element.atUid; if (!atQQ || atQQ === '0') { @@ -151,9 +151,9 @@ export class OneBotMsgApi { result: element.resultId!, }, }; - } else if (faceIndex === FaceIndex.RPS) { + } else if (faceIndex === FaceIndex.rps) { return { - type: OB11MessageDataType.RPS, + type: OB11MessageDataType.rps, data: { result: element.resultId!, }, @@ -400,7 +400,7 @@ export class OneBotMsgApi { elementId: '', textElement: { content: text, - atType: AtType.notAt, + atType: NTMsgAtType.ATTYPEUNKNOWN, atUid: '', atTinyId: '', atNtUid: '', @@ -408,7 +408,7 @@ export class OneBotMsgApi { }), [OB11MessageDataType.at]: async ({ data: { qq: atQQ } }, context) => { - function at(atUid: string, atNtUid: string, atType: AtType, atName: string): SendTextElement { + function at(atUid: string, atNtUid: string, atType: NTMsgAtType, atName: string): SendTextElement { return { elementType: ElementType.TEXT, elementId: '', @@ -423,15 +423,15 @@ export class OneBotMsgApi { } if (!context.peer || context.peer.chatType == ChatType.KCHATTYPEC2C) return undefined; - if (atQQ === 'all') return at(atQQ, atQQ, AtType.atAll, '全体成员'); + if (atQQ === 'all') return at(atQQ, atQQ, NTMsgAtType.ATTYPEALL, '全体成员'); const atMember = await this.core.apis.GroupApi.getGroupMember(context.peer.peerUid, atQQ); if (atMember) { - return at(atQQ, atMember.uid, AtType.atUser, atMember.nick || atMember.cardName); + return at(atQQ, atMember.uid, NTMsgAtType.ATTYPEONE, atMember.nick || atMember.cardName); } const uid = await this.core.apis.UserApi.getUidByUinV2(`${atQQ}`); if (!uid) throw new Error('Get Uid Error'); const info = await this.core.apis.UserApi.getUserDetailInfo(uid); - return at(atQQ, uid, AtType.atUser, info.nick || ''); + return at(atQQ, uid, NTMsgAtType.ATTYPEONE, info.nick || ''); }, [OB11MessageDataType.reply]: async ({ data: { id } }) => { @@ -558,11 +558,11 @@ export class OneBotMsgApi { }, }), - [OB11MessageDataType.RPS]: async () => ({ + [OB11MessageDataType.rps]: async () => ({ elementType: ElementType.FACE, elementId: '', faceElement: { - faceIndex: FaceIndex.RPS, + faceIndex: FaceIndex.rps, faceText: '[包剪锤]', faceType: 3, packId: '1', @@ -640,7 +640,7 @@ export class OneBotMsgApi { [OB11MessageDataType.poke]: async () => undefined, - [OB11MessageDataType.Location]: async () => ({ + [OB11MessageDataType.location]: async () => ({ elementType: ElementType.SHARELOCATION, elementId: '', shareLocationElement: { diff --git a/src/onebot/types/entity.ts b/src/onebot/types/entity.ts index f64cd08f..3039ba0b 100644 --- a/src/onebot/types/entity.ts +++ b/src/onebot/types/entity.ts @@ -1,91 +1,89 @@ export interface OB11User { [key: string]: any; - user_id: number; - nickname: string; - remark?: string; - sex?: OB11UserSex; - level?: number; - age?: number; - qid?: string; - login_days?: number; - categoryName?: string; - categoryId?: number; + user_id: number; // 用户ID + nickname: string; // 昵称 + remark?: string; // 备注 + sex?: OB11UserSex; // 性别 + level?: number; // 等级 + age?: number; // 年龄 + qid?: string; // QID + login_days?: number; // 登录天数 + categoryName?: string; // 分组名称 + categoryId?: number; // 分组ID 999为特别关心 } export enum OB11UserSex { - male = 'male', - female = 'female', - unknown = 'unknown' + male = 'male', // 男性 + female = 'female', // 女性 + unknown = 'unknown' // 未知 } export enum OB11GroupMemberRole { - owner = 'owner', - admin = 'admin', - member = 'member', + owner = 'owner', // 群主 + admin = 'admin', // 管理员 + member = 'member', // 成员 } export interface OB11GroupMember { - group_id: number; - user_id: number; - nickname: string; - card?: string; - sex?: OB11UserSex; - age?: number; - join_time?: number; - last_sent_time?: number; - level?: string; - qq_level?: number; - role?: OB11GroupMemberRole; - title?: string; - area?: string; - unfriendly?: boolean; - title_expire_time?: number; - card_changeable?: boolean; - // 以下为gocq字段 - shut_up_timestamp?: number; - // 以下为扩展字段 - is_robot?: boolean; - qage?: number; + group_id: number; // 群ID + user_id: number; // 用户ID + nickname: string; // 昵称 + card?: string; // 群名片 + sex?: OB11UserSex; // 性别 + age?: number; // 年龄 + join_time?: number; // 加入时间 + last_sent_time?: number; // 最后发言时间 + level?: string; // 群等级 + qq_level?: number; // QQ等级 + role?: OB11GroupMemberRole; // 群角色 + title?: string; // 头衔 + area?: string; // 地区 + unfriendly?: boolean; // 是否不友好 + title_expire_time?: number; // 头衔过期时间 + card_changeable?: boolean; // 名片是否可修改 + shut_up_timestamp?: number; // 禁言时间戳 + is_robot?: boolean; // 是否机器人 + qage?: number; // QQ年龄 } export interface OB11Group { - group_id: number; - group_name: string; - member_count?: number; - max_member_count?: number; + group_id: number; // 群ID + group_name: string; // 群名称 + member_count?: number; // 成员数量 + max_member_count?: number; // 最大成员数量 } export interface OB11Sender { - user_id: number, - nickname: string, - sex?: OB11UserSex, - age?: number, - card?: string, // 群名片 - level?: string, // 群等级 - role?: OB11GroupMemberRole + user_id: number; // 用户ID + nickname: string; // 昵称 + sex?: OB11UserSex; // 性别 + age?: number; // 年龄 + card?: string; // 群名片 + level?: string; // 群等级 + role?: OB11GroupMemberRole; // 群角色 } export interface OB11GroupFile { - group_id: number, - file_id: string, - file_name: string, - busid: number, - size: number, - upload_time: number, - dead_time: number, - modify_time: number, - download_times: number, - uploader: number, - uploader_name: string + group_id: number; // 群ID + file_id: string; // 文件ID + file_name: string; // 文件名称 + busid: number; // 业务ID + size: number; // 文件大小 + upload_time: number; // 上传时间 + dead_time: number; // 过期时间 + modify_time: number; // 修改时间 + download_times: number; // 下载次数 + uploader: number; // 上传者ID + uploader_name: string; // 上传者名称 } export interface OB11GroupFileFolder { - group_id: number, - folder_id: string, - folder: string, - folder_name: string, - create_time: number, - creator: number, - creator_name: string, - total_file_count: number, -} + group_id: number; // 群ID + folder_id: string; // 文件夹ID + folder: string; // 文件夹路径 + folder_name: string; // 文件夹名称 + create_time: number; // 创建时间 + creator: number; // 创建者ID + creator_name: string; // 创建者名称 + total_file_count: number; // 文件总数 +} \ No newline at end of file diff --git a/src/onebot/types/message.ts b/src/onebot/types/message.ts index fe4e26e4..71a948c3 100644 --- a/src/onebot/types/message.ts +++ b/src/onebot/types/message.ts @@ -2,46 +2,51 @@ import { OB11Sender } from './entity'; import { EventType } from '@/onebot/event/OneBotEvent'; import { CustomMusicSignPostData, IdMusicSignPostData, PicSubType, RawMessage } from '@/core'; +// 消息类型枚举 export enum OB11MessageType { private = 'private', group = 'group' } +// 消息接口定义 export interface OB11Message { temp_source?: number; message_sent_type?: string; target_id?: number; // 自己发送的消息才有此字段 - self_id?: number, - time: number, - message_id: number, - message_seq: number, // 和message_id一样 - real_id: number, - user_id: number | string, // number - group_id?: number | string, // number - message_type: 'private' | 'group', - sub_type?: 'friend' | 'group' | 'normal', - sender: OB11Sender, - message: OB11MessageData[] | string, - message_format: 'array' | 'string', - raw_message: string, - font: number, - post_type?: EventType, - raw?: RawMessage + self_id?: number; + time: number; + message_id: number; + message_seq: number; // 和message_id一样 + real_id: number; + user_id: number | string; // number + group_id?: number | string; // number + message_type: 'private' | 'group'; + sub_type?: 'friend' | 'group' | 'normal'; + sender: OB11Sender; + message: OB11MessageData[] | string; + message_format: 'array' | 'string'; + raw_message: string; + font: number; + post_type?: EventType; + raw?: RawMessage; } +// 合并转发消息接口定义 export interface OB11ForwardMessage extends OB11Message { content: OB11MessageData[] | string; } +// 返回数据接口定义 export interface OB11Return { - status: string - retcode: number - data: DataType - message: string, - echo?: any, // ws调用api才有此字段 - wording?: string, // go-cqhttp字段,错误信息 + status: string; + retcode: number; + data: DataType; + message: string; + echo?: any; // ws调用api才有此字段 + wording?: string; // go-cqhttp字段,错误信息 } +// 消息数据类型枚举 export enum OB11MessageDataType { text = 'text', image = 'image', @@ -60,108 +65,123 @@ export enum OB11MessageDataType { xml = 'xml', poke = 'poke', dice = 'dice', - RPS = 'rps', - miniapp = 'miniapp',//json类 + rps = 'rps', + miniapp = 'miniapp', // json类 contact = 'contact', - Location = 'location' + location = 'location' } +// 商城表情消息接口定义 export interface OB11MessageMFace { type: OB11MessageDataType.mface; data: { - emoji_package_id: number - emoji_id: string - key: string - summary: string + emoji_package_id: number; + emoji_id: string; + key: string; + summary: string; }; } +// 纯文本消息接口定义 export interface OB11MessageText { - type: OB11MessageDataType.text, + type: OB11MessageDataType.text; data: { - text: string, // 纯文本 - } + text: string; // 纯文本 + }; } + +// 联系人消息接口定义 export interface OB11MessageContext { - type: OB11MessageDataType.contact, + type: OB11MessageDataType.contact; data: { - type:"qq"|"group", - id: string, - } + type: "qq" | "group"; + id: string; + }; } + +// 文件消息基础接口定义 export interface OB11MessageFileBase { data: { - file_unique?: string, + file_unique?: string; path?: string; thumb?: string; name?: string; - file: string, + file: string; url?: string; }; } - +// 图片消息接口定义 export interface OB11MessageImage extends OB11MessageFileBase { - type: OB11MessageDataType.image + type: OB11MessageDataType.image; data: OB11MessageFileBase['data'] & { summary?: string; // 图片摘要 - sub_type?: PicSubType - }, + sub_type?: PicSubType; + }; } +// 语音消息接口定义 export interface OB11MessageRecord extends OB11MessageFileBase { type: OB11MessageDataType.voice; } +// 文件消息接口定义 export interface OB11MessageFile extends OB11MessageFileBase { type: OB11MessageDataType.file; } +// 视频消息接口定义 export interface OB11MessageVideo extends OB11MessageFileBase { type: OB11MessageDataType.video; } +// @消息接口定义 export interface OB11MessageAt { type: OB11MessageDataType.at; data: { - qq: string, // `${number}` | 'all' - name?: string + qq: string; // `${number}` | 'all' + name?: string; }; } +// 回复消息接口定义 export interface OB11MessageReply { type: OB11MessageDataType.reply; data: { - id: string + id: string; }; } +// 表情消息接口定义 export interface OB11MessageFace { type: OB11MessageDataType.face; data: { - id: string + id: string; }; } +// 混合消息类型定义 export type OB11MessageMixType = OB11MessageData[] | string | OB11MessageData; +// 合并转发消息节点接口定义 export interface OB11MessageNode { type: OB11MessageDataType.node; data: { - id?: string - user_id?: number | string // number - uin?: number | string // number, compatible with go-cqhttp - nickname: string - name?: string // compatible with go-cqhttp - content: OB11MessageMixType - source?: string, - news?: { text: string }[], - summary?: string, - prompt?: string - time?: string + id?: string; + user_id?: number | string; // number + uin?: number | string; // number, compatible with go-cqhttp + nickname: string; + name?: string; // compatible with go-cqhttp + content: OB11MessageMixType; + source?: string; + news?: { text: string }[]; + summary?: string; + prompt?: string; + time?: string; }; } +// 合并转发消息节点纯文本接口定义 export type OB11MessageNodePlain = OB11MessageNode & { data: { content?: Array; @@ -169,73 +189,84 @@ export type OB11MessageNodePlain = OB11MessageNode & { }; }; +// 音乐消息接口定义 export interface OB11MessageIdMusic { type: OB11MessageDataType.music; data: IdMusicSignPostData; } +// 自定义音乐消息接口定义 export interface OB11MessageCustomMusic { type: OB11MessageDataType.music; data: Omit & { content?: string }; } +// JSON消息接口定义 export interface OB11MessageJson { type: OB11MessageDataType.json; data: { config?: { token: string }, data: string | object }; } +// 骰子消息接口定义 export interface OB11MessageDice { - type: OB11MessageDataType.dice, + type: OB11MessageDataType.dice; data: { - result: number /* intended */ | string /* in fact */ - } + result: number /* intended */ | string /* in fact */; + }; } +// 猜拳消息接口定义 export interface OB11MessageRPS { - type: OB11MessageDataType.RPS, + type: OB11MessageDataType.rps; data: { - result: number | string - } + result: number | string; + }; } +// Markdown消息接口定义 export interface OB11MessageMarkdown { type: OB11MessageDataType.markdown; data: { - content: string + content: string; }; } +// 合并转发消息接口定义 export interface OB11MessageForward { type: OB11MessageDataType.forward; data: { - id: string, - content: OB11Message[] + id: string; + content: OB11Message[]; }; } +// 消息数据类型定义 export type OB11MessageData = OB11MessageText | OB11MessageFace | OB11MessageMFace | OB11MessageAt | OB11MessageReply | OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo | OB11MessageNode | OB11MessageIdMusic | OB11MessageCustomMusic | OB11MessageJson | - OB11MessageDice | OB11MessageRPS | OB11MessageMarkdown | OB11MessageForward | OB11MessageContext + OB11MessageDice | OB11MessageRPS | OB11MessageMarkdown | OB11MessageForward | OB11MessageContext; +// 发送消息接口定义 export interface OB11PostSendMsg { - message_type?: 'private' | 'group' - user_id?: string, - group_id?: string, + message_type?: 'private' | 'group'; + user_id?: string; + group_id?: string; message: OB11MessageMixType; messages?: OB11MessageMixType; // 兼容 go-cqhttp - auto_escape?: boolean | string - source?: string, - news?: { text: string }[], - summary?: string, - prompt?: string - time?: string + auto_escape?: boolean | string; + source?: string; + news?: { text: string }[]; + summary?: string; + prompt?: string; + time?: string; } + +// 上下文接口定义 export interface OB11PostContext { - message_type?: 'private' | 'group' - user_id?: string, - group_id?: string, -} + message_type?: 'private' | 'group'; + user_id?: string; + group_id?: string; +} \ No newline at end of file