mirror of https://github.com/grpc/grpc-node.git
Merge pull request #1097 from murgatroid99/node_general_interface
Node general interface
This commit is contained in:
commit
af3c157d06
8
index.js
8
index.js
|
@ -56,7 +56,7 @@ function loadObject(value) {
|
|||
});
|
||||
return result;
|
||||
} else if (value.className === 'Service') {
|
||||
return client.makeClientConstructor(value);
|
||||
return client.makeProtobufClientConstructor(value);
|
||||
} else if (value.className === 'Message' || value.className === 'Enum') {
|
||||
return value.build();
|
||||
} else {
|
||||
|
@ -119,7 +119,7 @@ exports.load = load;
|
|||
/**
|
||||
* See docs for server.makeServerConstructor
|
||||
*/
|
||||
exports.buildServer = server.makeServerConstructor;
|
||||
exports.buildServer = server.makeProtobufServerConstructor;
|
||||
|
||||
/**
|
||||
* Status name to code number mapping
|
||||
|
@ -141,3 +141,7 @@ exports.Credentials = grpc.Credentials;
|
|||
exports.ServerCredentials = grpc.ServerCredentials;
|
||||
|
||||
exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
|
||||
|
||||
exports.makeGenericClientConstructor = client.makeClientConstructor;
|
||||
|
||||
exports.makeGenericServerConstructor = server.makeServerConstructor;
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
|
||||
var _ = require('underscore');
|
||||
|
||||
var capitalize = require('underscore.string/capitalize');
|
||||
var decapitalize = require('underscore.string/decapitalize');
|
||||
|
||||
var grpc = require('bindings')('grpc.node');
|
||||
|
||||
var common = require('./common.js');
|
||||
|
@ -463,13 +460,18 @@ var requester_makers = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Creates a constructor for clients for the given service
|
||||
* @param {ProtoBuf.Reflect.Service} service The service to generate a client
|
||||
* for
|
||||
* Creates a constructor for a client with the given methods. The methods object
|
||||
* maps method name to an object with the following keys:
|
||||
* path: The path on the server for accessing the method. For example, for
|
||||
* protocol buffers, we use "/service_name/method_name"
|
||||
* requestStream: bool indicating whether the client sends a stream
|
||||
* resonseStream: bool indicating whether the server sends a stream
|
||||
* requestSerialize: function to serialize request objects
|
||||
* responseDeserialize: function to deserialize response objects
|
||||
* @param {Object} methods An object mapping method names to method attributes
|
||||
* @return {function(string, Object)} New client constructor
|
||||
*/
|
||||
function makeClientConstructor(service) {
|
||||
var prefix = '/' + common.fullyQualifiedName(service) + '/';
|
||||
function makeClientConstructor(methods) {
|
||||
/**
|
||||
* Create a client with the given methods
|
||||
* @constructor
|
||||
|
@ -489,30 +491,41 @@ function makeClientConstructor(service) {
|
|||
this.channel = new grpc.Channel(address, options);
|
||||
}
|
||||
|
||||
_.each(service.children, function(method) {
|
||||
_.each(methods, function(attrs, name) {
|
||||
var method_type;
|
||||
if (method.requestStream) {
|
||||
if (method.responseStream) {
|
||||
if (attrs.requestStream) {
|
||||
if (attrs.responseStream) {
|
||||
method_type = 'bidi';
|
||||
} else {
|
||||
method_type = 'client_stream';
|
||||
}
|
||||
} else {
|
||||
if (method.responseStream) {
|
||||
if (attrs.responseStream) {
|
||||
method_type = 'server_stream';
|
||||
} else {
|
||||
method_type = 'unary';
|
||||
}
|
||||
}
|
||||
var serialize = common.serializeCls(method.resolvedRequestType.build());
|
||||
var deserialize = common.deserializeCls(
|
||||
method.resolvedResponseType.build());
|
||||
Client.prototype[decapitalize(method.name)] = requester_makers[method_type](
|
||||
prefix + capitalize(method.name), serialize, deserialize);
|
||||
Client.prototype[decapitalize(method.name)].serialize = serialize;
|
||||
Client.prototype[decapitalize(method.name)].deserialize = deserialize;
|
||||
var serialize = attrs.requestSerialize;
|
||||
var deserialize = attrs.responseDeserialize;
|
||||
Client.prototype[name] = requester_makers[method_type](
|
||||
attrs.path, serialize, deserialize);
|
||||
Client.prototype[name].serialize = serialize;
|
||||
Client.prototype[name].deserialize = deserialize;
|
||||
});
|
||||
|
||||
return Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a constructor for clients for the given service
|
||||
* @param {ProtoBuf.Reflect.Service} service The service to generate a client
|
||||
* for
|
||||
* @return {function(string, Object)} New client constructor
|
||||
*/
|
||||
function makeProtobufClientConstructor(service) {
|
||||
var method_attrs = common.getProtobufServiceAttrs(service);
|
||||
var Client = makeClientConstructor(method_attrs);
|
||||
Client.service = service;
|
||||
|
||||
return Client;
|
||||
|
@ -520,6 +533,8 @@ function makeClientConstructor(service) {
|
|||
|
||||
exports.makeClientConstructor = makeClientConstructor;
|
||||
|
||||
exports.makeProtobufClientConstructor = makeProtobufClientConstructor;
|
||||
|
||||
/**
|
||||
* See docs for client.status
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
var _ = require('underscore');
|
||||
|
||||
var capitalize = require('underscore.string/capitalize');
|
||||
var decapitalize = require('underscore.string/decapitalize');
|
||||
|
||||
/**
|
||||
* Get a function that deserializes a specific type of protobuf.
|
||||
|
@ -109,6 +110,26 @@ function wrapIgnoreNull(func) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map from method names to method attributes for the service.
|
||||
* @param {ProtoBuf.Reflect.Service} service The service to get attributes for
|
||||
* @return {Object} The attributes map
|
||||
*/
|
||||
function getProtobufServiceAttrs(service) {
|
||||
var prefix = '/' + fullyQualifiedName(service) + '/';
|
||||
return _.object(_.map(service.children, function(method) {
|
||||
return [decapitalize(method.name), {
|
||||
path: prefix + capitalize(method.name),
|
||||
requestStream: method.requestStream,
|
||||
responseStream: method.responseStream,
|
||||
requestSerialize: serializeCls(method.resolvedRequestType.build()),
|
||||
requestDeserialize: deserializeCls(method.resolvedRequestType.build()),
|
||||
responseSerialize: serializeCls(method.resolvedResponseType.build()),
|
||||
responseDeserialize: deserializeCls(method.resolvedResponseType.build())
|
||||
}];
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* See docs for deserializeCls
|
||||
*/
|
||||
|
@ -128,3 +149,5 @@ exports.fullyQualifiedName = fullyQualifiedName;
|
|||
* See docs for wrapIgnoreNull
|
||||
*/
|
||||
exports.wrapIgnoreNull = wrapIgnoreNull;
|
||||
|
||||
exports.getProtobufServiceAttrs = getProtobufServiceAttrs;
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
|
||||
var _ = require('underscore');
|
||||
|
||||
var capitalize = require('underscore.string/capitalize');
|
||||
var decapitalize = require('underscore.string/decapitalize');
|
||||
|
||||
var grpc = require('bindings')('grpc.node');
|
||||
|
||||
var common = require('./common');
|
||||
|
@ -532,26 +529,20 @@ Server.prototype.bind = function(port, creds) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Creates a constructor for servers with a service defined by the methods
|
||||
* object. The methods object has string keys and values of this form:
|
||||
* {serialize: function, deserialize: function, client_stream: bool,
|
||||
* server_stream: bool}
|
||||
* @param {Object} methods Method descriptor for each method the server should
|
||||
* expose
|
||||
* @param {string} prefix The prefex to prepend to each method name
|
||||
* @return {function(Object, Object)} New server constructor
|
||||
* Create a constructor for servers with services defined by service_attr_map.
|
||||
* That is an object that maps (namespaced) service names to objects that in
|
||||
* turn map method names to objects with the following keys:
|
||||
* path: The path on the server for accessing the method. For example, for
|
||||
* protocol buffers, we use "/service_name/method_name"
|
||||
* requestStream: bool indicating whether the client sends a stream
|
||||
* resonseStream: bool indicating whether the server sends a stream
|
||||
* requestDeserialize: function to deserialize request objects
|
||||
* responseSerialize: function to serialize response objects
|
||||
* @param {Object} service_attr_map An object mapping service names to method
|
||||
* attribute map objects
|
||||
* @return {function(Object, function, Object=)} New server constructor
|
||||
*/
|
||||
function makeServerConstructor(services) {
|
||||
var qual_names = [];
|
||||
_.each(services, function(service) {
|
||||
_.each(service.children, function(method) {
|
||||
var name = common.fullyQualifiedName(method);
|
||||
if (_.indexOf(qual_names, name) !== -1) {
|
||||
throw new Error('Method ' + name + ' exposed by more than one service');
|
||||
}
|
||||
qual_names.push(name);
|
||||
});
|
||||
});
|
||||
function makeServerConstructor(service_attr_map) {
|
||||
/**
|
||||
* Create a server with the given handlers for all of the methods.
|
||||
* @constructor
|
||||
|
@ -565,41 +556,34 @@ function makeServerConstructor(services) {
|
|||
function SurfaceServer(service_handlers, getMetadata, options) {
|
||||
var server = new Server(getMetadata, options);
|
||||
this.inner_server = server;
|
||||
_.each(services, function(service) {
|
||||
var service_name = common.fullyQualifiedName(service);
|
||||
_.each(service_attr_map, function(service_attrs, service_name) {
|
||||
if (service_handlers[service_name] === undefined) {
|
||||
throw new Error('Handlers for service ' +
|
||||
service_name + ' not provided.');
|
||||
}
|
||||
var prefix = '/' + common.fullyQualifiedName(service) + '/';
|
||||
_.each(service.children, function(method) {
|
||||
_.each(service_attrs, function(attrs, name) {
|
||||
var method_type;
|
||||
if (method.requestStream) {
|
||||
if (method.responseStream) {
|
||||
if (attrs.requestStream) {
|
||||
if (attrs.responseStream) {
|
||||
method_type = 'bidi';
|
||||
} else {
|
||||
method_type = 'client_stream';
|
||||
}
|
||||
} else {
|
||||
if (method.responseStream) {
|
||||
if (attrs.responseStream) {
|
||||
method_type = 'server_stream';
|
||||
} else {
|
||||
method_type = 'unary';
|
||||
}
|
||||
}
|
||||
if (service_handlers[service_name][decapitalize(method.name)] ===
|
||||
undefined) {
|
||||
throw new Error('Method handler for ' +
|
||||
common.fullyQualifiedName(method) + ' not provided.');
|
||||
if (service_handlers[service_name][name] === undefined) {
|
||||
throw new Error('Method handler for ' + attrs.path +
|
||||
' not provided.');
|
||||
}
|
||||
var serialize = common.serializeCls(
|
||||
method.resolvedResponseType.build());
|
||||
var deserialize = common.deserializeCls(
|
||||
method.resolvedRequestType.build());
|
||||
server.register(
|
||||
prefix + capitalize(method.name),
|
||||
service_handlers[service_name][decapitalize(method.name)],
|
||||
serialize, deserialize, method_type);
|
||||
var serialize = attrs.responseSerialize;
|
||||
var deserialize = attrs.requestDeserialize;
|
||||
server.register(attrs.path, service_handlers[service_name][name],
|
||||
serialize, deserialize, method_type);
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
|
@ -635,7 +619,40 @@ function makeServerConstructor(services) {
|
|||
return SurfaceServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a constructor for servers that serve the given services.
|
||||
* @param {Array<ProtoBuf.Reflect.Service>} services The services that the
|
||||
* servers will serve
|
||||
* @return {function(Object, function, Object=)} New server constructor
|
||||
*/
|
||||
function makeProtobufServerConstructor(services) {
|
||||
var qual_names = [];
|
||||
var service_attr_map = {};
|
||||
_.each(services, function(service) {
|
||||
var service_name = common.fullyQualifiedName(service);
|
||||
_.each(service.children, function(method) {
|
||||
var name = common.fullyQualifiedName(method);
|
||||
if (_.indexOf(qual_names, name) !== -1) {
|
||||
throw new Error('Method ' + name + ' exposed by more than one service');
|
||||
}
|
||||
qual_names.push(name);
|
||||
});
|
||||
var method_attrs = common.getProtobufServiceAttrs(service);
|
||||
if (!service_attr_map.hasOwnProperty(service_name)) {
|
||||
service_attr_map[service_name] = {};
|
||||
}
|
||||
service_attr_map[service_name] = _.extend(service_attr_map[service_name],
|
||||
method_attrs);
|
||||
});
|
||||
return makeServerConstructor(service_attr_map);
|
||||
}
|
||||
|
||||
/**
|
||||
* See documentation for makeServerConstructor
|
||||
*/
|
||||
exports.makeServerConstructor = makeServerConstructor;
|
||||
|
||||
/**
|
||||
* See documentation for makeProtobufServerConstructor
|
||||
*/
|
||||
exports.makeProtobufServerConstructor = makeProtobufServerConstructor;
|
||||
|
|
|
@ -45,6 +45,8 @@ var math_proto = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto');
|
|||
|
||||
var mathService = math_proto.lookup('math.Math');
|
||||
|
||||
var capitalize = require('underscore.string/capitalize');
|
||||
|
||||
describe('Surface server constructor', function() {
|
||||
it('Should fail with conflicting method names', function() {
|
||||
assert.throws(function() {
|
||||
|
@ -75,6 +77,55 @@ describe('Surface server constructor', function() {
|
|||
}, /math.Math/);
|
||||
});
|
||||
});
|
||||
describe('Generic client and server', function() {
|
||||
function toString(val) {
|
||||
return val.toString();
|
||||
}
|
||||
function toBuffer(str) {
|
||||
return new Buffer(str);
|
||||
}
|
||||
var string_service_attrs = {
|
||||
'capitalize' : {
|
||||
path: '/string/capitalize',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestSerialize: toBuffer,
|
||||
requestDeserialize: toString,
|
||||
responseSerialize: toBuffer,
|
||||
responseDeserialize: toString
|
||||
}
|
||||
};
|
||||
describe('String client and server', function() {
|
||||
var client;
|
||||
var server;
|
||||
before(function() {
|
||||
var Server = grpc.makeGenericServerConstructor({
|
||||
string: string_service_attrs
|
||||
});
|
||||
server = new Server({
|
||||
string: {
|
||||
capitalize: function(call, callback) {
|
||||
callback(null, capitalize(call.request));
|
||||
}
|
||||
}
|
||||
});
|
||||
var port = server.bind('localhost:0');
|
||||
server.listen();
|
||||
var Client = grpc.makeGenericClientConstructor(string_service_attrs);
|
||||
client = new Client('localhost:' + port);
|
||||
});
|
||||
after(function() {
|
||||
server.shutdown();
|
||||
});
|
||||
it('Should respond with a capitalized string', function(done) {
|
||||
client.capitalize('abc', function(err, response) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(response, 'Abc');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Cancelling surface client', function() {
|
||||
var client;
|
||||
var server;
|
||||
|
@ -89,7 +140,7 @@ describe('Cancelling surface client', function() {
|
|||
}
|
||||
});
|
||||
var port = server.bind('localhost:0');
|
||||
var Client = surface_client.makeClientConstructor(mathService);
|
||||
var Client = surface_client.makeProtobufClientConstructor(mathService);
|
||||
client = new Client('localhost:' + port);
|
||||
});
|
||||
after(function() {
|
||||
|
|
Loading…
Reference in New Issue