proto-loader: Pass file descriptors around instead of caching them separately

This commit is contained in:
murgatroid99 2019-11-01 10:34:35 -07:00
parent 82a33fea27
commit 0fe10fd1fb
2 changed files with 28 additions and 37 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@grpc/proto-loader", "name": "@grpc/proto-loader",
"version": "0.5.2", "version": "0.5.3",
"author": "Google Inc.", "author": "Google Inc.",
"contributors": [ "contributors": [
{ {

View File

@ -149,8 +149,8 @@ function createSerializer(cls: Protobuf.Type): Serialize<object> {
} }
function createMethodDefinition( function createMethodDefinition(
method: Protobuf.Method, serviceName: string, method: Protobuf.Method, serviceName: string, options: Options,
options: Options): MethodDefinition<object, object> { fileDescriptors: Buffer[]): MethodDefinition<object, object> {
/* This is only ever called after the corresponding root.resolveAll(), so we /* This is only ever called after the corresponding root.resolveAll(), so we
* can assume that the resolved request and response types are non-null */ * can assume that the resolved request and response types are non-null */
const requestType: Protobuf.Type = method.resolvedRequestType!; const requestType: Protobuf.Type = method.resolvedRequestType!;
@ -165,56 +165,42 @@ function createMethodDefinition(
responseDeserialize: createDeserializer(responseType, options), responseDeserialize: createDeserializer(responseType, options),
// TODO(murgatroid99): Find a better way to handle this // TODO(murgatroid99): Find a better way to handle this
originalName: camelCase(method.name), originalName: camelCase(method.name),
requestType: createMessageDefinition(requestType), requestType: createMessageDefinition(requestType, fileDescriptors),
responseType: createMessageDefinition(responseType) responseType: createMessageDefinition(responseType, fileDescriptors)
}; };
} }
function createServiceDefinition( function createServiceDefinition(
service: Protobuf.Service, name: string, service: Protobuf.Service, name: string, options: Options,
options: Options): ServiceDefinition { fileDescriptors: Buffer[]): ServiceDefinition {
const def: ServiceDefinition = {}; const def: ServiceDefinition = {};
for (const method of service.methodsArray) { for (const method of service.methodsArray) {
def[method.name] = createMethodDefinition(method, name, options); def[method.name] =
createMethodDefinition(method, name, options, fileDescriptors);
} }
return def; return def;
} }
const fileDescriptorCache: Map<Protobuf.Root, Buffer[]> = function createMessageDefinition(
new Map<Protobuf.Root, Buffer[]>(); message: Protobuf.Type, fileDescriptors: Buffer[]): MessageTypeDefinition {
function getFileDescriptors(root: Protobuf.Root): Buffer[] {
if (fileDescriptorCache.has(root)) {
return fileDescriptorCache.get(root)!;
} else {
const descriptorList: descriptor.IFileDescriptorProto[] =
root.toDescriptor('proto3').file;
const bufferList: Buffer[] = descriptorList.map(
value =>
Buffer.from(descriptor.FileDescriptorProto.encode(value).finish()));
fileDescriptorCache.set(root, bufferList);
return bufferList;
}
}
function createMessageDefinition(message: Protobuf.Type):
MessageTypeDefinition {
const messageDescriptor: protobuf.Message<descriptor.IDescriptorProto> = const messageDescriptor: protobuf.Message<descriptor.IDescriptorProto> =
message.toDescriptor('proto3'); message.toDescriptor('proto3');
return { return {
format: 'Protocol Buffer 3 DescriptorProto', format: 'Protocol Buffer 3 DescriptorProto',
type: type:
messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions), messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions),
fileDescriptorProtos: getFileDescriptors(message.root) fileDescriptorProtos: fileDescriptors
}; };
} }
function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition { function createEnumDefinition(
enumType: Protobuf.Enum, fileDescriptors: Buffer[]): EnumTypeDefinition {
const enumDescriptor: protobuf.Message<descriptor.IEnumDescriptorProto> = const enumDescriptor: protobuf.Message<descriptor.IEnumDescriptorProto> =
enumType.toDescriptor('proto3'); enumType.toDescriptor('proto3');
return { return {
format: 'Protocol Buffer 3 EnumDescriptorProto', format: 'Protocol Buffer 3 EnumDescriptorProto',
type: enumDescriptor.$type.toObject(enumDescriptor, descriptorOptions), type: enumDescriptor.$type.toObject(enumDescriptor, descriptorOptions),
fileDescriptorProtos: getFileDescriptors(enumType.root) fileDescriptorProtos: fileDescriptors
}; };
} }
@ -226,14 +212,14 @@ function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition {
* EnumTypeDefinition; * EnumTypeDefinition;
*/ */
function createDefinition( function createDefinition(
obj: HandledReflectionObject, name: string, obj: HandledReflectionObject, name: string, options: Options,
options: Options): AnyDefinition { fileDescriptors: Buffer[]): AnyDefinition {
if (obj instanceof Protobuf.Service) { if (obj instanceof Protobuf.Service) {
return createServiceDefinition(obj, name, options); return createServiceDefinition(obj, name, options, fileDescriptors);
} else if (obj instanceof Protobuf.Type) { } else if (obj instanceof Protobuf.Type) {
return createMessageDefinition(obj); return createMessageDefinition(obj, fileDescriptors);
} else if (obj instanceof Protobuf.Enum) { } else if (obj instanceof Protobuf.Enum) {
return createEnumDefinition(obj); return createEnumDefinition(obj, fileDescriptors);
} else { } else {
throw new Error('Type mismatch in reflection object handling'); throw new Error('Type mismatch in reflection object handling');
} }
@ -243,8 +229,13 @@ function createPackageDefinition(
root: Protobuf.Root, options: Options): PackageDefinition { root: Protobuf.Root, options: Options): PackageDefinition {
const def: PackageDefinition = {}; const def: PackageDefinition = {};
root.resolveAll(); root.resolveAll();
const descriptorList: descriptor.IFileDescriptorProto[] =
root.toDescriptor('proto3').file;
const bufferList: Buffer[] = descriptorList.map(
value =>
Buffer.from(descriptor.FileDescriptorProto.encode(value).finish()));
for (const [name, obj] of getAllHandledReflectionObjects(root, '')) { for (const [name, obj] of getAllHandledReflectionObjects(root, '')) {
def[name] = createDefinition(obj, name, options); def[name] = createDefinition(obj, name, options, bufferList);
} }
return def; return def;
} }
@ -293,7 +284,7 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) {
* @param options.includeDirs Paths to search for imported `.proto` files. * @param options.includeDirs Paths to search for imported `.proto` files.
*/ */
export function load( export function load(
filename: string | string[], options?: Options): Promise<PackageDefinition> { filename: string|string[], options?: Options): Promise<PackageDefinition> {
const root: Protobuf.Root = new Protobuf.Root(); const root: Protobuf.Root = new Protobuf.Root();
options = options || {}; options = options || {};
if (!!options.includeDirs) { if (!!options.includeDirs) {
@ -310,7 +301,7 @@ export function load(
} }
export function loadSync( export function loadSync(
filename: string | string[], options?: Options): PackageDefinition { filename: string|string[], options?: Options): PackageDefinition {
const root: Protobuf.Root = new Protobuf.Root(); const root: Protobuf.Root = new Protobuf.Root();
options = options || {}; options = options || {};
if (!!options.includeDirs) { if (!!options.includeDirs) {