From d332b199b56a2fc340055d471e9b0082f5cbe6fb 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: Sun, 29 Sep 2024 20:06:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20protobufjs=E7=BB=99=E6=88=91?= =?UTF-8?q?=E4=BC=BC=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- src/core/proto/Message.ts | 69 +++++++++------- src/core/proto/ProfileLike.ts | 146 +++++++++++++--------------------- src/onebot/api/msg.ts | 4 +- src/onebot/api/user.ts | 4 +- src/onebot/index.ts | 6 +- 6 files changed, 102 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 0a9ed2c8..7d591e4e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "devDependencies": { "@babel/preset-typescript": "^7.24.7", "@log4js-node/log4js-api": "^1.0.2", - "@protobuf-ts/plugin": "^2.9.4", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-typescript": "^11.1.6", "@types/cors": "^2.8.17", @@ -34,6 +33,7 @@ }, "dependencies": { "ajv": "^8.13.0", + "@protobuf-ts/plugin": "^2.9.4", "async-mutex": "^0.5.0", "chalk": "^5.3.0", "commander": "^12.1.0", @@ -45,7 +45,6 @@ "image-size": "^1.1.1", "json-schema-to-ts": "^3.1.0", "log4js": "^6.9.1", - "protobufjs": "~7.4.0", "qrcode-terminal": "^0.12.0", "silk-wasm": "^3.6.1", "ws": "^8.18.0" diff --git a/src/core/proto/Message.ts b/src/core/proto/Message.ts index c7d1cbb5..5999e9a1 100644 --- a/src/core/proto/Message.ts +++ b/src/core/proto/Message.ts @@ -1,37 +1,46 @@ -import * as pb from 'protobufjs'; +import { MessageType, BinaryReader } from '@protobuf-ts/runtime'; +export const BodyInner = new MessageType("BodyInner", [ + { no: 1, name: "msgType", kind: "scalar", T: 13 /* uint32 */, opt: true }, + { no: 2, name: "subType", kind: "scalar", T: 13 /* uint32 */, opt: true } +]); -export const BodyInner = new pb.Type("BodyInner") - .add(new pb.Field("msgType", 1, "uint32", "optional")) - .add(new pb.Field("subType", 2, "uint32", "optional")) +export const NoifyData = new MessageType("NoifyData", [ + { no: 1, name: "skip", kind: "scalar", T: 12 /* bytes */, opt: true }, + { no: 2, name: "innerData", kind: "scalar", T: 12 /* bytes */, opt: true } +]); -export const NoifyData = new pb.Type("NoifyData") - .add(new pb.Field("skip", 1, "bytes", "optional")) - .add(new pb.Field("innerData", 2, "bytes", "optional")) +export const MsgHead = new MessageType("MsgHead", [ + { no: 2, name: "bodyInner", kind: "message", T: () => BodyInner, opt: true }, + { no: 3, name: "noifyData", kind: "message", T: () => NoifyData, opt: true } +]); -export const MsgHead = new pb.Type("MsgHead") - .add(BodyInner) - .add(NoifyData) - .add(new pb.Field("bodyInner", 2, "BodyInner", "optional")) - .add(new pb.Field("noifyData", 3, "NoifyData", "optional")); +export const Message = new MessageType("Message", [ + { no: 1, name: "msgHead", kind: "message", T: () => MsgHead } +]); -export const Message = new pb.Type("Message") - .add(MsgHead) - .add(new pb.Field("msgHead", 1, "MsgHead")) +export const SubDetail = new MessageType("SubDetail", [ + { no: 1, name: "msgSeq", kind: "scalar", T: 13 /* uint32 */ }, + { no: 2, name: "msgTime", kind: "scalar", T: 13 /* uint32 */ }, + { no: 6, name: "senderUid", kind: "scalar", T: 9 /* string */ } +]); -export const SubDetail = new pb.Type("SubDetail") - .add(new pb.Field("msgSeq", 1, "uint32")) - .add(new pb.Field("msgTime", 2, "uint32")) - .add(new pb.Field("senderUid", 6, "string")) +export const RecallDetails = new MessageType("RecallDetails", [ + { no: 1, name: "operatorUid", kind: "scalar", T: 9 /* string */ }, + { no: 3, name: "subDetail", kind: "message", T: () => SubDetail } +]); -export const RecallDetails = new pb.Type("RecallDetails") - .add(SubDetail) - .add(new pb.Field("operatorUid", 1, "string")) - .add(new pb.Field("subDetail", 3, "SubDetail")) - -export const RecallGroup = new pb.Type("RecallGroup") - .add(RecallDetails) - .add(new pb.Field("type", 1, "int32")) - .add(new pb.Field("peerUid", 4, "uint32")) - .add(new pb.Field("recallDetails", 11, "RecallDetails")) - .add(new pb.Field("grayTipsSeq", 37, "uint32")) +export const RecallGroup = new MessageType("RecallGroup", [ + { no: 1, name: "type", kind: "scalar", T: 5 /* int32 */ }, + { no: 4, name: "peerUid", kind: "scalar", T: 13 /* uint32 */ }, + { no: 11, name: "recallDetails", kind: "message", T: () => RecallDetails }, + { no: 37, name: "grayTipsSeq", kind: "scalar", T: 13 /* uint32 */ } +]); +export function decodeMessage(buffer: Uint8Array): any { + const reader = new BinaryReader(buffer); + return Message.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) }); +} +export function decodeRecallGroup(buffer: Uint8Array): any { + const reader = new BinaryReader(buffer); + return RecallGroup.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) }); +} \ No newline at end of file diff --git a/src/core/proto/ProfileLike.ts b/src/core/proto/ProfileLike.ts index ba9aadcc..a5792a33 100644 --- a/src/core/proto/ProfileLike.ts +++ b/src/core/proto/ProfileLike.ts @@ -1,95 +1,59 @@ -import * as pb from 'protobufjs'; +import { MessageType, BinaryReader, RepeatType } from '@protobuf-ts/runtime'; -// Proto: from src/core/proto/ProfileLike.proto -// Author: Mlikiowa +export const LikeDetailType = new MessageType("LikeDetailType", [ + { no: 1, name: "txt", kind: "scalar", T: 9 /* string */ }, + { no: 2, name: "uin", kind: "scalar", T: 3 /* int64 */ }, + { no: 3, name: "nickname", kind: "scalar", T: 9 /* string */ } +]); -export interface LikeDetailType { - txt: string; - uin: pb.Long; - nickname: string; -} -export interface LikeMsgType { - times: number; - time: number; - detail: LikeDetailType; +export const LikeMsgType = new MessageType("LikeMsgType", [ + { no: 1, name: "times", kind: "scalar", T: 5 /* int32 */ }, + { no: 2, name: "time", kind: "scalar", T: 5 /* int32 */ }, + { no: 3, name: "detail", kind: "message", T: () => LikeDetailType } +]); + +export const ProfileLikeSubTipType = new MessageType("ProfileLikeSubTipType", [ + { no: 1, name: "msg", kind: "message", T: () => LikeMsgType } +]); + +export const ProfileLikeTipType = new MessageType("ProfileLikeTipType", [ + { no: 1, name: "msgType", kind: "scalar", T: 5 /* int32 */ }, + { no: 2, name: "subType", kind: "scalar", T: 5 /* int32 */ }, + { no: 3, name: "content", kind: "message", T: () => ProfileLikeSubTipType } +]); + +export const SysMessageHeaderType = new MessageType("SysMessageHeaderType", [ + { no: 1, name: "id", kind: "scalar", T: 9 /* string */ }, + { no: 2, name: "timestamp", kind: "scalar", T: 5 /* int32 */ }, + { no: 3, name: "sender", kind: "scalar", T: 9 /* string */ } +]); + +export const SysMessageMsgSpecType = new MessageType("SysMessageMsgSpecType", [ + { no: 1, name: "msgType", kind: "scalar", T: 5 /* int32 */ }, + { no: 2, name: "subType", kind: "scalar", T: 5 /* int32 */ }, + { no: 3, name: "subSubType", kind: "scalar", T: 5 /* int32 */ }, + { no: 4, name: "msgSeq", kind: "scalar", T: 5 /* int32 */ }, + { no: 5, name: "time", kind: "scalar", T: 5 /* int32 */ }, + { no: 6, name: "msgId", kind: "scalar", T: 3 /* int64 */ }, + { no: 7, name: "other", kind: "scalar", T: 5 /* int32 */ } +]); + +export const SysMessageBodyWrapperType = new MessageType("SysMessageBodyWrapperType", [ + { no: 1, name: "wrappedBody", kind: "scalar", T: 12 /* bytes */ } +]); + +export const SysMessageType = new MessageType("SysMessageType", [ + { no: 1, name: "header", kind: "message", T: () => SysMessageHeaderType, repeat: RepeatType.PACKED }, + { no: 2, name: "msgSpec", kind: "message", T: () => SysMessageMsgSpecType, repeat: RepeatType.PACKED }, + { no: 3, name: "bodyWrapper", kind: "message", T: () => SysMessageBodyWrapperType } +]); + +export function decodeProfileLikeTip(buffer: Uint8Array): any { + const reader = new BinaryReader(buffer); + return ProfileLikeTipType.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) }); } -export interface profileLikeSubTipType { - msg: LikeMsgType; -} - -export interface ProfileLikeTipType { - msgType: number; - subType: number; - content: profileLikeSubTipType; -} -export interface SysMessageHeaderType { - id: string; - timestamp: number; - sender: string; -} - -export interface SysMessageMsgSpecType { - msgType: number; - subType: number; - subSubType: number; - msgSeq: number; - time: number; - msgId: pb.Long; - other: number; -} -export interface SysMessageBodyWrapperType { - wrappedBody: Uint8Array; -} -export interface SysMessageType { - header: SysMessageHeaderType[]; - msgSpec: SysMessageMsgSpecType[]; - bodyWrapper: SysMessageBodyWrapperType; -} - -export const SysMessageHeader = new pb.Type("SysMessageHeader") - .add(new pb.Field("PeerNumber", 1, "uint32")) - .add(new pb.Field("PeerString", 2, "string")) - .add(new pb.Field("Uin", 5, "uint32")) - .add(new pb.Field("Uid", 6, "string", "optional")); - -export const SysMessageMsgSpec = new pb.Type("SysMessageMsgSpec") - .add(new pb.Field("msgType", 1, "uint32")) - .add(new pb.Field("subType", 2, "uint32")) - .add(new pb.Field("subSubType", 3, "uint32")) - .add(new pb.Field("msgSeq", 5, "uint32")) - .add(new pb.Field("time", 6, "uint32")) - .add(new pb.Field("msgId", 12, "uint64")) - .add(new pb.Field("other", 13, "uint32")); - -export const SysMessageBodyWrapper = new pb.Type("SysMessageBodyWrapper") - .add(new pb.Field("wrappedBody", 2, "bytes")); - -export const SysMessage = new pb.Type("SysMessage") - .add(SysMessageHeader) - .add(SysMessageMsgSpec) - .add(SysMessageBodyWrapper) - .add(new pb.Field("header", 1, "SysMessageHeader", "repeated")) - .add(new pb.Field("msgSpec", 2, "SysMessageMsgSpec", "repeated")) - .add(new pb.Field("bodyWrapper", 3, "SysMessageBodyWrapper")); - -export const likeDetail = new pb.Type("likeDetail") - .add(new pb.Field("txt", 1, "string")) - .add(new pb.Field("uin", 3, "int64")) - .add(new pb.Field("nickname", 5, "string")); - -export const likeMsg = new pb.Type("likeMsg") - .add(likeDetail) - .add(new pb.Field("times", 1, "int32")) - .add(new pb.Field("time", 2, "int32")) - .add(new pb.Field("detail", 3, "likeDetail")); - -export const profileLikeSubTip = new pb.Type("profileLikeSubTip") - .add(likeMsg) - .add(new pb.Field("msg", 14, "likeMsg")) - -export const profileLikeTip = new pb.Type("profileLikeTip") - .add(profileLikeSubTip) - .add(new pb.Field("msgType", 1, "int32")) - .add(new pb.Field("subType", 2, "int32")) - .add(new pb.Field("content", 203, "profileLikeSubTip")); +export function decodeSysMessage(buffer: Uint8Array): any { + const reader = new BinaryReader(buffer); + return SysMessageType.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) }); +} \ No newline at end of file diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index 630ae294..61279f9c 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -34,7 +34,7 @@ import { RequestUtil } from '@/common/request'; import fs from 'node:fs'; import fsPromise from 'node:fs/promises'; import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent'; -import { SysMessage, SysMessageType } from '@/core/proto/ProfileLike'; +import { decodeSysMessage } from '@/core/proto/ProfileLike'; type RawToOb11Converters = { [Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: ( @@ -841,7 +841,7 @@ export class OneBotMsgApi { return { path, fileName: inputdata.name ?? fileName }; } async parseSysMessage(msg: number[]) { - const sysMsg = SysMessage.decode(Uint8Array.from(msg)) as unknown as SysMessageType; + const sysMsg = decodeSysMessage(Uint8Array.from(msg)); if (sysMsg.msgSpec.length === 0) { return; } diff --git a/src/onebot/api/user.ts b/src/onebot/api/user.ts index a84fcaa5..716a5803 100644 --- a/src/onebot/api/user.ts +++ b/src/onebot/api/user.ts @@ -1,5 +1,5 @@ import { NapCatCore } from '@/core'; -import { profileLikeTip, ProfileLikeTipType } from '@/core/proto/ProfileLike'; +import { decodeProfileLikeTip } from '@/core/proto/ProfileLike'; import { NapCatOneBot11Adapter } from '@/onebot'; import { OB11ProfileLikeEvent } from '../event/notice/OB11ProfileLikeEvent'; @@ -13,7 +13,7 @@ export class OneBotUserApi { this.core = core; } async parseLikeEvent(wrappedBody: Uint8Array): Promise { - const likeTip = profileLikeTip.decode(Uint8Array.from(wrappedBody)) as unknown as ProfileLikeTipType; + const likeTip = decodeProfileLikeTip(Uint8Array.from(wrappedBody)); if (likeTip?.msgType !== 0 || likeTip?.subType !== 203) return; this.core.context.logger.logDebug("收到点赞通知消息"); const likeMsg = likeTip.content.msg; diff --git a/src/onebot/index.ts b/src/onebot/index.ts index b8cb81e9..9c86c843 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -45,7 +45,7 @@ import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecal import { LRUCache } from '@/common/lru-cache'; import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener'; import { Native } from '@/native'; -import { Message, RecallGroup } from '@/core/proto/Message'; +import { decodeMessage, decodeRecallGroup, Message, RecallGroup } from '@/core/proto/Message'; //OneBot实现类 export class NapCatOneBot11Adapter { @@ -82,7 +82,7 @@ export class NapCatOneBot11Adapter { this.nativeCore = new Native(context.pathWrapper.binaryPath); this.nativeCore.registerRecallCallback(async (hex: string) => { try { - let data = Message.decode(Buffer.from(hex, 'hex')) as any; + let data = decodeMessage(Buffer.from(hex, 'hex')) as any; //data.MsgHead.BodyInner.MsgType SubType let bodyInner = data.msgHead?.bodyInner; //context.logger.log("[appNative] Parse MsgType:" + bodyInner.msgType + " / SubType:" + bodyInner.subType); @@ -91,7 +91,7 @@ export class NapCatOneBot11Adapter { //跳过 4字节 群号 + 不知道的1字节 +2字节 长度 let uid = RecallData.readUint32BE(); const buffer = Buffer.from(RecallData.toString('hex').slice(14), 'hex'); - let seq: number = (RecallGroup.decode(buffer) as any).recallDetails.subDetail.msgSeq; + let seq: number = decodeRecallGroup(buffer).recallDetails.subDetail.msgSeq; let peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: uid.toString() }; context.logger.log("[Native] 群消息撤回 Peer: " + uid.toString() + " / MsgSeq:" + seq); let msgs = await core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, seq.toString());