纯前端如何解析cyber record

164 阅读1分钟

首先要知道cyber record文件的结构是什么样,网上有很多介绍的,大概就是header + n*(chunk) + indexes 这里indexes存储了topic的FileDescriptorProto,所以无需依赖额外的proto文件就能解析。 python 包用的是DescriptorPool类来存储,protobufjs没有这个类,所以用FileDescriptorSet来代替, 话不多说,我TM直接亮代码。

const arrayBuffer = fileReader.result as ArrayBuffer;
      const dataView = new DataView(arrayBuffer);
      const headerlength = dataView.getBigInt64(8, true);
      const headerBuf = arrayBuffer.slice(16, 16 + Number(headerlength));
      const header = Header.decode(new Uint8Array(headerBuf));
      const indexesBuf = arrayBuffer.slice(Number(header.indexPosition) + 16);
      const index = Index.decode(new Uint8Array(indexesBuf));
      index.indexes.forEach((item) => {
        if (item.type !== 4) {
          return;
        }
        const fileDescriptorSet = FileDescriptorSet.decode(new Uint8Array());
        const proto_desc = ProtoDesc.decode(
          item.channelCache?.protoDesc ?? new Uint8Array()
        );
        if (proto_desc.desc.length) {
          let stack = [proto_desc];
          while (stack.length) {
            const protpdesc = stack.shift();
            const protodesc = FileDescriptorProto.decode(protpdesc.desc);
            if (
              !fileDescriptorSet.file.some((it) => it.name === protodesc.name)
            ) {
              fileDescriptorSet.file.push(protodesc);
            }
            stack = [...stack, ...protpdesc.dependencies];
          }
        }
        const root = protobufjs.Root.fromDescriptor(fileDescriptorSet).lookup(
          item.channelCache?.messageType
        );
        decoderMap.set(item.channelCache?.name, root);
      });
      index.indexes.forEach((item) => {
        if (item.type === 2) {
          const position = Number(item.position);
          const bodySize = dataView.getBigInt64(position + 8, true);
          const bodyBuf = arrayBuffer.slice(
            position + 16,
            position + 16 + Number(bodySize)
          );
          const message = ChunkBody.decode(new Uint8Array(bodyBuf));
          message.messages.forEach((msg) => {
            const decoder = decoderMap.get(msg.channelName);
            decoder.decode(msg.content)
          })
        }
      });

以上代码实现是原创,要copy的记得打赏 想起了和某位领域"专家"的对话,我说用到了protobuf的反射机制,他说js没有反射机制,专家就是专家。