From 08254e4d2e552abff4893098466ae2cf2ab919ed Mon Sep 17 00:00:00 2001 From: "A. Tate Barber" Date: Sun, 22 Nov 2020 17:29:14 -0600 Subject: [PATCH] Add functions for loading and parsing binary-encoded file decriptor sets Fixes #1627 --- packages/proto-loader/src/index.ts | 43 +++++++++++++++++++ .../proto-loader/test/descriptor_type_test.ts | 5 +++ packages/proto-loader/test_protos/rpc.desc | 11 +++++ packages/proto-loader/test_protos/rpc.proto | 13 ++++++ 4 files changed, 72 insertions(+) create mode 100644 packages/proto-loader/test_protos/rpc.desc create mode 100644 packages/proto-loader/test_protos/rpc.proto diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index ffef89d3..c2f203c4 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -30,6 +30,17 @@ declare module 'protobufjs' { descriptor.IDescriptorProto; } + interface RootConstructor { + new (options?: Options): Root; + fromDescriptor( + descriptorSet: + | descriptor.IFileDescriptorSet + | Protobuf.Reader + | Uint8Array + ): Root; + fromJSON(json: Protobuf.INamespace, root?: Root): Root; + } + interface Root { toDescriptor( protoVersion: string @@ -368,6 +379,38 @@ export function loadSync( return createPackageDefinition(root, options!); } +export async function loadFileDescriptorSet( + descriptorSet: Protobuf.Message & + descriptor.IFileDescriptorSet, + options?: Options +): Promise { + options = options || {}; + const root = (Protobuf.Root as Protobuf.RootConstructor).fromDescriptor( + descriptorSet + ); + root.resolveAll(); + return createPackageDefinition(root, options); +} + +export function loadFileDescriptorSetFile( + filename: string, + options?: Options +): Promise { + return new Promise((resolve, reject) => { + fs.readFile(filename, (err, data) => { + if (err) { + return reject(err); + } + + const descriptorSet = descriptor.FileDescriptorSet.decode( + data + ) as Protobuf.Message & + descriptor.IFileDescriptorSet; + return resolve(loadFileDescriptorSet(descriptorSet, options)); + }); + }); +} + // Load Google's well-known proto files that aren't exposed by Protobuf.js. // Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 348c5c8e..57eb9ab0 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -99,4 +99,9 @@ describe('Descriptor types', () => { // This will throw if the well known protos are not available. proto_loader.loadSync(`${TEST_PROTO_DIR}/well_known.proto`); }); + + it('Can load binary-encoded proto file descriptor sets', () => { + // This will throw if the well known protos are not available. + proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc`); + }); }); diff --git a/packages/proto-loader/test_protos/rpc.desc b/packages/proto-loader/test_protos/rpc.desc new file mode 100644 index 00000000..9c6f1261 --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.desc @@ -0,0 +1,11 @@ + +˜ +test_protos/rpc.proto" + MyRequest +path ( Rpath"$ + +MyResponse +status (Rstatus20 + MyService# +MyMethod +.MyRequest .MyResponsebproto3 \ No newline at end of file diff --git a/packages/proto-loader/test_protos/rpc.proto b/packages/proto-loader/test_protos/rpc.proto new file mode 100644 index 00000000..a9841c06 --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +service MyService { + rpc MyMethod (MyRequest) returns (MyResponse); +} + +message MyRequest { + string path = 1; +} + +message MyResponse { + int32 status = 2; +}