From 81acd929b771885a0394396c66ce8642b58ff451 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 28 Sep 2017 16:13:07 -0700 Subject: [PATCH] Separate out packages. Upgrade new protobufjs package to Protobuf.js 6.8 --- .gitignore | 3 + packages/grpc-js/index.js | 21 +++ packages/grpc-js/package.json | 23 +++ packages/grpc-native/index.js | 22 +++ packages/grpc-native/package.json | 23 +++ packages/grpc-protobufjs/index.js | 139 ++++++++++++++ packages/grpc-protobufjs/package.json | 22 +++ .../grpc-protobufjs/protobuf_js_5_common.js | 177 ++++++++++++++++++ .../grpc-protobufjs/protobuf_js_6_common.js | 166 ++++++++++++++++ packages/grpc-surface/index.js | 147 +++++++++++++++ packages/grpc-surface/package.json | 21 +++ 11 files changed, 764 insertions(+) create mode 100644 packages/grpc-js/index.js create mode 100644 packages/grpc-js/package.json create mode 100644 packages/grpc-native/index.js create mode 100644 packages/grpc-native/package.json create mode 100644 packages/grpc-protobufjs/index.js create mode 100644 packages/grpc-protobufjs/package.json create mode 100644 packages/grpc-protobufjs/protobuf_js_5_common.js create mode 100644 packages/grpc-protobufjs/protobuf_js_6_common.js create mode 100644 packages/grpc-surface/index.js create mode 100644 packages/grpc-surface/package.json diff --git a/.gitignore b/.gitignore index 58368339..4dc6fc88 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ npm-debug.log yarn-error.log yarn.lock +# Emacs temp files *~ +\#*\# +.\#* packages/grpc-native-core/src/node/ \ No newline at end of file diff --git a/packages/grpc-js/index.js b/packages/grpc-js/index.js new file mode 100644 index 00000000..6079b1b1 --- /dev/null +++ b/packages/grpc-js/index.js @@ -0,0 +1,21 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +module.exports = require('grpc-surface')(require('grpc-js-core')); diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json new file mode 100644 index 00000000..248e8460 --- /dev/null +++ b/packages/grpc-js/package.json @@ -0,0 +1,23 @@ +{ + "name": "grpc-js", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "homepage": "https://grpc.io", + "dependencies": { + "grpc-js-core": "^0.1.0", + "grpc-surface": "^1.0.0" + } +} diff --git a/packages/grpc-native/index.js b/packages/grpc-native/index.js new file mode 100644 index 00000000..86266efe --- /dev/null +++ b/packages/grpc-native/index.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +// TODO(mlumish): This should eventually be grpc-native-core instead of grpc +module.exports = require('grpc-surface')(require('grpc')); diff --git a/packages/grpc-native/package.json b/packages/grpc-native/package.json new file mode 100644 index 00000000..7637603c --- /dev/null +++ b/packages/grpc-native/package.json @@ -0,0 +1,23 @@ +{ + "name": "grpc-native", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "homepage": "https://grpc.io", + "dependencies": { + "grpc": "^1.6.0", + "grpc-surface": "^1.0.0" + } +} diff --git a/packages/grpc-protobufjs/index.js b/packages/grpc-protobufjs/index.js new file mode 100644 index 00000000..5e7ede99 --- /dev/null +++ b/packages/grpc-protobufjs/index.js @@ -0,0 +1,139 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var path = require('path'); + +var _ = require('lodash'); +var ProtoBuf = require('protobufjs'); + +module.exports = function(grpc) { + + let exports = {}; + + const protobuf_js_5_common = require('protobuf_js_5_common')(grpc); + const protobuf_js_6_common = require('protobuf_js_6_common')(grpc); + + /** + * Default options for loading proto files into gRPC + * @alias grpc~defaultLoadOptions + */ + const defaultGrpcOptions = { + convertFieldsToCamelCase: false, + binaryAsBase64: false, + longsAsStrings: true, + enumsAsStrings: true + }; + + /** + * Load a ProtoBuf.js object as a gRPC object. The options object can provide + * the following options: + * - binaryAsBase64: deserialize bytes values as base64 strings instead of + * Buffers. Defaults to false + * - longsAsStrings: deserialize long values as strings instead of objects. + * Defaults to true + * - enumsAsStrings: deserialize enum values as strings instead of numbers. + * Defaults to true + * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6 + * respectively indicate that an object from the corresponding version of + * ProtoBuf.js is provided in the value argument. If the option is 'detect', + * gRPC will guess what the version is based on the structure of the value. + * Defaults to 'detect'. + * @param {Object} value The ProtoBuf.js reflection object to load + * @param {Object=} options Options to apply to the loaded file + * @return {Object} The resulting gRPC object + */ + exports.loadObject = function loadObject(value, options) { + options = _.defaults(options, defaultGrpcOptions); + options = _.defaults(options, {'protobufjsVersion': 'detect'}); + var protobufjsVersion; + if (options.protobufjsVersion === 'detect') { + if (protobuf_js_6_common.isProbablyProtobufJs6(value)) { + protobufjsVersion = 6; + } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) { + protobufjsVersion = 5; + } else { + var error_message = 'Could not detect ProtoBuf.js version. Please ' + + 'specify the version number with the "protobufjs_version" option'; + throw new Error(error_message); + } + } else { + protobufjsVersion = options.protobufjsVersion; + } + switch (protobufjsVersion) { + case 6: return protobuf_js_6_common.loadObject(value, options); + case 5: return protobuf_js_5_common.loadObject(value, options); + default: + throw new Error('Unrecognized protobufjsVersion', protobufjsVersion); + } + }; + + var loadObject = exports.loadObject; + + function applyProtoRoot(filename, root) { + if (_.isString(filename)) { + return filename; + } + filename.root = path.resolve(filename.root) + '/'; + root.resolvePath = function(originPath, importPath, alreadyNormalized) { + return ProtoBuf.util.path.resolve(filename.root, + importPath, + alreadyNormalized); + }; + return filename.file; + } + + /** + * Load a gRPC object from a .proto file. The options object can provide the + * following options: + * - convertFieldsToCamelCase: Load this file with field names in camel case + * instead of their original case + * - binaryAsBase64: deserialize bytes values as base64 strings instead of + * Buffers. Defaults to false + * - longsAsStrings: deserialize long values as strings instead of objects. + * Defaults to true + * - enumsAsStrings: deserialize enum values as strings instead of numbers. + * Defaults to true + * - deprecatedArgumentOrder: Use the beta method argument order for client + * methods, with optional arguments after the callback. Defaults to false. + * This option is only a temporary stopgap measure to smooth an API breakage. + * It is deprecated, and new code should not use it. + * @param {string|{root: string, file: string}} filename The file to load + * @param {string=} format The file format to expect. Must be either 'proto' or + * 'json'. Defaults to 'proto' + * @param {Object=} options Options to apply to the loaded file + * @return {Object} The resulting gRPC object + */ + exports.load = function load(filename, format, options) { + /* Note: format is currently unused, because the API for loading a proto + file or a JSON file is identical in Protobuf.js 6. In the future, there is + still the possibility of adding other formats that would be loaded + differently */ + options = _.defaults(options, defaultGrpcOptions); + options.protobufjs_version = 6; + var root = new ProtoBuf.Root(); + var parse_options = {keepCase: !options.convertFieldsToCamelCase}; + return loadObject(root.loadSync(applyProtoRoot(filename, root), + parse_options), + options); + }; + + return exports; + +}; diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json new file mode 100644 index 00000000..456fdf59 --- /dev/null +++ b/packages/grpc-protobufjs/package.json @@ -0,0 +1,22 @@ +{ + "name": "grpc-protobufjs", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "dependencies": { + "lodash": "^4.17.4", + "protobufjs": "~6.8.0" + } +} diff --git a/packages/grpc-protobufjs/protobuf_js_5_common.js b/packages/grpc-protobufjs/protobuf_js_5_common.js new file mode 100644 index 00000000..141852f6 --- /dev/null +++ b/packages/grpc-protobufjs/protobuf_js_5_common.js @@ -0,0 +1,177 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * @module + * @private + */ + +'use strict'; + +var _ = require('lodash'); + +module.exports = function(grpc) { + + let exports = {}; + + /** + * Get a function that deserializes a specific type of protobuf. + * @param {function()} cls The constructor of the message type to deserialize + * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings + * instead of Buffers. Defaults to false + * @param {bool=} longsAsStrings Deserialize long values as strings instead of + * objects. Defaults to true + * @return {function(Buffer):cls} The deserialization function + */ + exports.deserializeCls = function deserializeCls(cls, options) { + /** + * Deserialize a buffer to a message object + * @param {Buffer} arg_buf The buffer to deserialize + * @return {cls} The resulting object + */ + return function deserialize(arg_buf) { + // Convert to a native object with binary fields as Buffers (first argument) + // and longs as strings (second argument) + return cls.decode(arg_buf).toRaw(options.binaryAsBase64, + options.longsAsStrings); + }; + }; + + var deserializeCls = exports.deserializeCls; + + /** + * Get a function that serializes objects to a buffer by protobuf class. + * @param {function()} Cls The constructor of the message type to serialize + * @return {function(Cls):Buffer} The serialization function + */ + exports.serializeCls = function serializeCls(Cls) { + /** + * Serialize an object to a Buffer + * @param {Object} arg The object to serialize + * @return {Buffer} The serialized object + */ + return function serialize(arg) { + return new Buffer(new Cls(arg).encode().toBuffer()); + }; + }; + + var serializeCls = exports.serializeCls; + + /** + * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. + * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of + * @return {string} The fully qualified name of the value + */ + exports.fullyQualifiedName = function fullyQualifiedName(value) { + if (value === null || value === undefined) { + return ''; + } + var name = value.name; + var parent_name = fullyQualifiedName(value.parent); + if (parent_name !== '') { + name = parent_name + '.' + name; + } + return name; + }; + + var fullyQualifiedName = exports.fullyQualifiedName; + + /** + * Return a map from method names to method attributes for the service. + * @param {ProtoBuf.Reflect.Service} service The service to get attributes for + * @param {Object=} options Options to apply to these attributes + * @return {Object} The attributes map + */ + exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, + options) { + var prefix = '/' + fullyQualifiedName(service) + '/'; + var binaryAsBase64, longsAsStrings; + if (options) { + binaryAsBase64 = options.binaryAsBase64; + longsAsStrings = options.longsAsStrings; + } + /* This slightly awkward construction is used to make sure we only use + lodash@3.10.1-compatible functions. A previous version used + _.fromPairs, which would be cleaner, but was introduced in lodash + version 4 */ + return _.zipObject(_.map(service.children, function(method) { + return _.camelCase(method.name); + }), _.map(service.children, function(method) { + return { + originalName: method.name, + path: prefix + method.name, + requestStream: method.requestStream, + responseStream: method.responseStream, + requestType: method.resolvedRequestType, + responseType: method.resolvedResponseType, + requestSerialize: serializeCls(method.resolvedRequestType.build()), + requestDeserialize: deserializeCls(method.resolvedRequestType.build(), + options), + responseSerialize: serializeCls(method.resolvedResponseType.build()), + responseDeserialize: deserializeCls(method.resolvedResponseType.build(), + options) + }; + })); + }; + + var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; + + /** + * Load a gRPC object from an existing ProtoBuf.Reflect object. + * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. + * @param {Object=} options Options to apply to the loaded object + * @return {Object} The resulting gRPC object + */ + exports.loadObject = function loadObject(value, options) { + var result = {}; + if (!value) { + return value; + } + if (value.hasOwnProperty('ns')) { + return loadObject(value.ns, options); + } + if (value.className === 'Namespace') { + _.each(value.children, function(child) { + result[child.name] = loadObject(child, options); + }); + return result; + } else if (value.className === 'Service') { + return grpc.makeGenericClientConstructor(getProtobufServiceAttrs(value, options), + options); + } else if (value.className === 'Message' || value.className === 'Enum') { + return value.build(); + } else { + return value; + } + }; + + /** + * The primary purpose of this method is to distinguish between reflection + * objects from different versions of ProtoBuf.js. This is just a heuristic, + * checking for properties that are (currently) specific to this version of + * ProtoBuf.js + * @param {Object} obj The object to check + * @return {boolean} Whether the object appears to be a Protobuf.js 5 + * ReflectionObject + */ + exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) { + return _.isArray(obj.children) && (typeof obj.build === 'function'); + }; + + return exports; +}; diff --git a/packages/grpc-protobufjs/protobuf_js_6_common.js b/packages/grpc-protobufjs/protobuf_js_6_common.js new file mode 100644 index 00000000..76241994 --- /dev/null +++ b/packages/grpc-protobufjs/protobuf_js_6_common.js @@ -0,0 +1,166 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * @module + * @private + */ + +'use strict'; + +var _ = require('lodash'); + +module.exports = function(grpc) { + + let exports = {}; + + /** + * Get a function that deserializes a specific type of protobuf. + * @param {function()} cls The constructor of the message type to deserialize + * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings + * instead of Buffers. Defaults to false + * @param {bool=} longsAsStrings Deserialize long values as strings instead of + * objects. Defaults to true + * @return {function(Buffer):cls} The deserialization function + */ + exports.deserializeCls = function deserializeCls(cls, options) { + var conversion_options = { + defaults: true, + bytes: options.binaryAsBase64 ? String : Buffer, + longs: options.longsAsStrings ? String : null, + enums: options.enumsAsStrings ? String : null, + oneofs: true + }; + /** + * Deserialize a buffer to a message object + * @param {Buffer} arg_buf The buffer to deserialize + * @return {cls} The resulting object + */ + return function deserialize(arg_buf) { + return cls.toObject(cls.decode(arg_buf), conversion_options); + }; + }; + + var deserializeCls = exports.deserializeCls; + + /** + * Get a function that serializes objects to a buffer by protobuf class. + * @param {function()} Cls The constructor of the message type to serialize + * @return {function(Cls):Buffer} The serialization function + */ + exports.serializeCls = function serializeCls(cls) { + /** + * Serialize an object to a Buffer + * @param {Object} arg The object to serialize + * @return {Buffer} The serialized object + */ + return function serialize(arg) { + var message = cls.fromObject(arg); + return cls.encode(message).finish(); + }; + }; + + var serializeCls = exports.serializeCls; + + /** + * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. + * @param {ProtoBuf.ReflectionObject} value The value to get the name of + * @return {string} The fully qualified name of the value + */ + exports.fullyQualifiedName = function fullyQualifiedName(value) { + if (value === null || value === undefined) { + return ''; + } + var name = value.name; + var parent_fqn = fullyQualifiedName(value.parent); + if (parent_fqn !== '') { + name = parent_fqn + '.' + name; + } + return name; + }; + + var fullyQualifiedName = exports.fullyQualifiedName; + + /** + * Return a map from method names to method attributes for the service. + * @param {ProtoBuf.Service} service The service to get attributes for + * @param {Object=} options Options to apply to these attributes + * @return {Object} The attributes map + */ + exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, + options) { + var prefix = '/' + fullyQualifiedName(service) + '/'; + service.resolveAll(); + return _.zipObject(_.map(service.methods, function(method) { + return _.camelCase(method.name); + }), _.map(service.methods, function(method) { + return { + originalName: method.name, + path: prefix + method.name, + requestStream: !!method.requestStream, + responseStream: !!method.responseStream, + requestType: method.resolvedRequestType, + responseType: method.resolvedResponseType, + requestSerialize: serializeCls(method.resolvedRequestType), + requestDeserialize: deserializeCls(method.resolvedRequestType, options), + responseSerialize: serializeCls(method.resolvedResponseType), + responseDeserialize: deserializeCls(method.resolvedResponseType, options) + }; + })); + }; + + var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; + + exports.loadObject = function loadObject(value, options) { + var result = {}; + if (!value) { + return value; + } + if (value.hasOwnProperty('methods')) { + // It's a service object + var service_attrs = getProtobufServiceAttrs(value, options); + return grpc..makeGenericClientConstructor(service_attrs); + } + + if (value.hasOwnProperty('nested')) { + // It's a namespace or root object + _.each(value.nested, function(nested, name) { + result[name] = loadObject(nested, options); + }); + return result; + } + + // Otherwise, it's not something we need to change + return value; + }; + + /** + * The primary purpose of this method is to distinguish between reflection + * objects from different versions of ProtoBuf.js. This is just a heuristic, + * checking for properties that are (currently) specific to this version of + * ProtoBuf.js + * @param {Object} obj The object to check + * @return {boolean} Whether the object appears to be a Protobuf.js 6 + * ReflectionObject + */ + exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) { + return (typeof obj.root === 'object') && (typeof obj.resolve === 'function'); + }; + + return exports; +}; diff --git a/packages/grpc-surface/index.js b/packages/grpc-surface/index.js new file mode 100644 index 00000000..6c9cb6a1 --- /dev/null +++ b/packages/grpc-surface/index.js @@ -0,0 +1,147 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +const util = require(util); + +const _ = require('lodash'); + +module.exports = function(grpc) { + + let exports = {}; + + const Client = grpc.Client; + + function getDefaultValues(metadata, options) { + var res = {}; + res.metadata = metadata || new grpc.Metadata(); + res.options = options || {}; + return res; + } + + /** + * Map with wrappers for each type of requester function to make it use the old + * argument order with optional arguments after the callback. + * @access private + */ + var deprecated_request_wrap = { + unary: function(makeUnaryRequest) { + return function makeWrappedUnaryRequest(argument, callback, + metadata, options) { + /* jshint validthis: true */ + var opt_args = getDefaultValues(metadata, metadata); + return makeUnaryRequest.call(this, argument, opt_args.metadata, + opt_args.options, callback); + }; + }, + client_stream: function(makeServerStreamRequest) { + return function makeWrappedClientStreamRequest(callback, metadata, + options) { + /* jshint validthis: true */ + var opt_args = getDefaultValues(metadata, options); + return makeServerStreamRequest.call(this, opt_args.metadata, + opt_args.options, callback); + }; + }, + server_stream: _.identity, + bidi: _.identity + }; + + /** + * Map with short names for each of the requester maker functions. Used in + * makeClientConstructor + * @private + */ + const requester_funcs = { + unary: Client.prototype.makeUnaryRequest, + server_stream: Client.prototype.makeServerStreamRequest, + client_stream: Client.prototype.makeClientStreamRequest, + bidi: Client.prototype.makeBidiStreamRequest + }; + + /** + * Creates a constructor for a client with the given methods, as specified in + * the methods argument. The resulting class will have an instance method for + * each method in the service, which is a partial application of one of the + * [Client]{@link grpc.Client} request methods, depending on `requestSerialize` + * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` + * arguments predefined. + * @memberof grpc + * @alias grpc~makeGenericClientConstructor + * @param {grpc~ServiceDefinition} methods An object mapping method names to + * method attributes + * @param {string} serviceName The fully qualified name of the service + * @param {Object} class_options An options object. + * @return {function} New client constructor, which is a subclass of + * {@link grpc.Client}, and has the same arguments as that constructor. + */ + exports.makeClientConstructor = function(methods, serviceName, + class_options) { + if (!class_options) { + class_options = {}; + } + + function ServiceClient(address, credentials, options) { + Client.call(this, address, credentials, options); + } + + util.inherits(ServiceClient, Client); + + _.each(methods, function(attrs, name) { + var method_type; + // TODO(murgatroid99): Verify that we don't need this anymore + if (_.startsWith(name, '$')) { + throw new Error('Method names cannot start with $'); + } + if (attrs.requestStream) { + if (attrs.responseStream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (attrs.responseStream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + var serialize = attrs.requestSerialize; + var deserialize = attrs.responseDeserialize; + var method_func = _.partial(requester_funcs[method_type], attrs.path, + serialize, deserialize); + if (class_options.deprecatedArgumentOrder) { + ServiceClient.prototype[name] = deprecated_request_wrap(method_func); + } else { + ServiceClient.prototype[name] = method_func; + } + // Associate all provided attributes with the method + _.assign(ServiceClient.prototype[name], attrs); + if (attrs.originalName) { + ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; + } + }); + + ServiceClient.service = methods; + + return ServiceClient; + }; + + return Object.assign(exports, grpc); +}; diff --git a/packages/grpc-surface/package.json b/packages/grpc-surface/package.json new file mode 100644 index 00000000..30aa6a87 --- /dev/null +++ b/packages/grpc-surface/package.json @@ -0,0 +1,21 @@ +{ + "name": "grpc-surface", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "dependencies": { + "lodash": "^4.17.4" + } +}