From 58c31036d4dbf38f5aca0afe4f1f8169d71fdc54 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 13 Jan 2015 14:21:13 -0800 Subject: [PATCH] Modified math client to more closely resemble generated code --- src/node/surface_client.js | 90 +++++++++++++------ src/node/test/math_client_test.js | 144 +++++++++++++----------------- 2 files changed, 125 insertions(+), 109 deletions(-) diff --git a/src/node/surface_client.js b/src/node/surface_client.js index 9c40b0a3a00..acd22089ce1 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -178,7 +178,7 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { /** * Make a unary request with this method on the given channel with the given * argument, callback, etc. - * @param {client.Channel} channel The channel on which to make the request + * @this {SurfaceClient} Client object. Must have a channel member. * @param {*} argument The argument to the call. Should be serializable with * serialize * @param {function(?Error, value=)} callback The callback to for when the @@ -189,8 +189,8 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { * Defaults to infinite future * @return {EventEmitter} An event emitter for stream related events */ - function makeUnaryRequest(channel, argument, callback, metadata, deadline) { - var stream = client.makeRequest(channel, method, metadata, deadline); + function makeUnaryRequest(argument, callback, metadata, deadline) { + var stream = client.makeRequest(this.channel, method, metadata, deadline); var emitter = new EventEmitter(); forwardEvent(stream, emitter, 'status'); forwardEvent(stream, emitter, 'metadata'); @@ -220,7 +220,7 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) { /** * Make a client stream request with this method on the given channel with the * given callback, etc. - * @param {client.Channel} channel The channel on which to make the request + * @this {SurfaceClient} Client object. Must have a channel member. * @param {function(?Error, value=)} callback The callback to for when the * response is received * @param {array=} metadata Array of metadata key/value pairs to add to the @@ -229,8 +229,8 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) { * Defaults to infinite future * @return {EventEmitter} An event emitter for stream related events */ - function makeClientStreamRequest(channel, callback, metadata, deadline) { - var stream = client.makeRequest(channel, method, metadata, deadline); + function makeClientStreamRequest(callback, metadata, deadline) { + var stream = client.makeRequest(this.channel, method, metadata, deadline); var obj_stream = new ClientWritableObjectStream(stream, serialize, {}); stream.on('data', function forwardData(chunk) { try { @@ -256,7 +256,7 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) { /** * Make a server stream request with this method on the given channel with the * given argument, etc. - * @param {client.Channel} channel The channel on which to make the request + * @this {SurfaceClient} Client object. Must have a channel member. * @param {*} argument The argument to the call. Should be serializable with * serialize * @param {array=} metadata Array of metadata key/value pairs to add to the @@ -265,8 +265,8 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) { * Defaults to infinite future * @return {EventEmitter} An event emitter for stream related events */ - function makeServerStreamRequest(channel, argument, metadata, deadline) { - var stream = client.makeRequest(channel, method, metadata, deadline); + function makeServerStreamRequest(argument, metadata, deadline) { + var stream = client.makeRequest(this.channel, method, metadata, deadline); var obj_stream = new ClientReadableObjectStream(stream, deserialize, {}); stream.write(serialize(argument)); stream.end(); @@ -287,15 +287,15 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) { function makeBidiStreamRequestFunction(method, serialize, deserialize) { /** * Make a bidirectional stream request with this method on the given channel. - * @param {client.Channel} channel The channel on which to make the request + * @this {SurfaceClient} Client object. Must have a channel member. * @param {array=} metadata Array of metadata key/value pairs to add to the * call * @param {(number|Date)=} deadline The deadline for processing this request. * Defaults to infinite future * @return {EventEmitter} An event emitter for stream related events */ - function makeBidiStreamRequest(channel, metadata, deadline) { - var stream = client.makeRequest(channel, method, metadata, deadline); + function makeBidiStreamRequest(metadata, deadline) { + var stream = client.makeRequest(this.channel, method, metadata, deadline); var obj_stream = new ClientBidiObjectStream(stream, serialize, deserialize, @@ -306,29 +306,63 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) { } /** - * See docs for makeUnaryRequestFunction + * Map with short names for each of the requester maker functions. Used in + * makeClientConstructor */ -exports.makeUnaryRequestFunction = makeUnaryRequestFunction; +var requester_makers = { + unary: makeUnaryRequestFunction, + server_stream: makeServerStreamRequestFunction, + client_stream: makeClientStreamRequestFunction, + bidi: makeBidiStreamRequestFunction +} /** - * See docs for makeClientStreamRequestFunction + * Creates a constructor for clients 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 client should expose + * @param {string} prefix The prefix to prepend to each method name + * @return {function(string, Object)} New client constructor */ -exports.makeClientStreamRequestFunction = makeClientStreamRequestFunction; +function makeClientConstructor(methods, prefix) { + /** + * Create a client with the given methods + * @constructor + * @param {string} address The address of the server to connect to + * @param {Object} options Options to pass to the underlying channel + */ + function SurfaceClient(address, options) { + this.channel = new client.Channel(address, options); + } -/** - * See docs for makeServerStreamRequestFunction - */ -exports.makeServerStreamRequestFunction = makeServerStreamRequestFunction; + _.each(methods, function(method, name) { + var method_type; + if (method.client_stream) { + if (method.server_stream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (method.server_stream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + SurfaceClient.prototype[name] = requester_makers[method_type]( + prefix + name, + method.serialize, + method.deserialize); + }); -/** - * See docs for makeBidiStreamRequestFunction - */ -exports.makeBidiStreamRequestFunction = makeBidiStreamRequestFunction; + return SurfaceClient; +} + +exports.makeClientConstructor = makeClientConstructor; -/** - * See docs for client.Channel - */ -exports.Channel = client.Channel; /** * See docs for client.status */ diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js index f3697aca98e..51a3401de40 100644 --- a/src/node/test/math_client_test.js +++ b/src/node/test/math_client_test.js @@ -32,13 +32,14 @@ */ var assert = require('assert'); -var client = require('../surface_client.js'); var ProtoBuf = require('protobufjs'); var port_picker = require('../port_picker'); var builder = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto'); var math = builder.build('math'); +var client = require('../surface_client.js'); +var makeConstructor = client.makeClientConstructor; /** * Get a function that deserializes a specific type of protobuf. * @param {function()} cls The constructor of the message type to deserialize @@ -56,78 +57,60 @@ function deserializeCls(cls) { } /** - * Serialize an object to a buffer - * @param {*} arg The object to serialize - * @return {Buffer} The serialized object + * 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 */ -function serialize(arg) { - return new Buffer(arg.encode().toBuffer()); +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()); + }; } -/** - * Sends a Div request on the channel. - * @param {client.Channel} channel The channel on which to make the request - * @param {DivArg} argument The argument to the call. Should be serializable - * with serialize - * @param {function(?Error, value=)} The callback to for when the response is - * received - * @param {array=} Array of metadata key/value pairs to add to the call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ -var div = client.makeUnaryRequestFunction( - '/Math/Div', - serialize, - deserializeCls(math.DivReply)); - -/** - * Sends a Fib request on the channel. - * @param {client.Channel} channel The channel on which to make the request - * @param {*} argument The argument to the call. Should be serializable with - * serialize - * @param {array=} Array of metadata key/value pairs to add to the call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ -var fib = client.makeServerStreamRequestFunction( - '/Math/Fib', - serialize, - deserializeCls(math.Num)); - -/** - * Sends a Sum request on the channel. - * @param {client.Channel} channel The channel on which to make the request - * @param {function(?Error, value=)} The callback to for when the response is - * received - * @param {array=} Array of metadata key/value pairs to add to the call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ -var sum = client.makeClientStreamRequestFunction( - '/Math/Sum', - serialize, - deserializeCls(math.Num)); - -/** - * Sends a DivMany request on the channel. - * @param {client.Channel} channel The channel on which to make the request - * @param {array=} Array of metadata key/value pairs to add to the call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ -var divMany = client.makeBidiStreamRequestFunction( - '/Math/DivMany', - serialize, - deserializeCls(math.DivReply)); +/* This function call creates a client constructor for clients that expose the + * four specified methods. This specifies how to serialize messages that the + * client sends and deserialize messages that the server sends, and whether the + * client or the server will send a stream of messages, for each method. This + * also specifies a prefix tha twill be added to method names when sending them + * on the wire. This function call and all of the preceding code in this file + * are intended to approximate what the generated code will look like for the + * math client */ +var MathClient = makeConstructor({ + Div: { + serialize: serializeCls(math.DivArgs), + deserialize: deserializeCls(math.DivReply), + client_stream: false, + server_stream: false + }, + Fib: { + serialize: serializeCls(math.FibArgs), + deserialize: deserializeCls(math.Num), + client_stream: false, + server_stream: true + }, + Sum: { + serialize: serializeCls(math.Num), + deserialize: deserializeCls(math.Num), + client_stream: true, + server_stream: false + }, + DivMany: { + serialize: serializeCls(math.DivArgs), + deserialize: deserializeCls(math.DivReply), + client_stream: true, + server_stream: true + } +}, '/Math'); /** * Channel to use to make requests to a running server. */ -var channel; +var math_client; /** * Server to test against @@ -139,7 +122,7 @@ describe('Math client', function() { before(function(done) { port_picker.nextAvailablePort(function(port) { server.bind(port).listen(); - channel = new client.Channel(port); + math_client = new MathClient(port); done(); }); }); @@ -147,11 +130,11 @@ describe('Math client', function() { server.shutdown(); }); it('should handle a single request', function(done) { - var arg = new math.DivArgs({dividend: 7, divisor: 4}); - var call = div(channel, arg, function handleDivResult(err, value) { + var arg = {dividend: 7, divisor: 4}; + var call = math_client.Div(arg, function handleDivResult(err, value) { assert.ifError(err); - assert.equal(value.get('quotient'), 1); - assert.equal(value.get('remainder'), 3); + assert.equal(value.quotient, 1); + assert.equal(value.remainder, 3); }); call.on('status', function checkStatus(status) { assert.strictEqual(status.code, client.status.OK); @@ -159,12 +142,11 @@ describe('Math client', function() { }); }); it('should handle a server streaming request', function(done) { - var arg = new math.FibArgs({limit: 7}); - var call = fib(channel, arg); + var call = math_client.Fib({limit: 7}); var expected_results = [1, 1, 2, 3, 5, 8, 13]; var next_expected = 0; call.on('data', function checkResponse(value) { - assert.equal(value.get('num'), expected_results[next_expected]); + assert.equal(value.num, expected_results[next_expected]); next_expected += 1; }); call.on('status', function checkStatus(status) { @@ -173,12 +155,12 @@ describe('Math client', function() { }); }); it('should handle a client streaming request', function(done) { - var call = sum(channel, function handleSumResult(err, value) { + var call = math_client.Sum(function handleSumResult(err, value) { assert.ifError(err); - assert.equal(value.get('num'), 21); + assert.equal(value.num, 21); }); for (var i = 0; i < 7; i++) { - call.write(new math.Num({'num': i})); + call.write({'num': i}); } call.end(); call.on('status', function checkStatus(status) { @@ -188,17 +170,17 @@ describe('Math client', function() { }); it('should handle a bidirectional streaming request', function(done) { function checkResponse(index, value) { - assert.equal(value.get('quotient'), index); - assert.equal(value.get('remainder'), 1); + assert.equal(value.quotient, index); + assert.equal(value.remainder, 1); } - var call = divMany(channel); + var call = math_client.DivMany(); var response_index = 0; call.on('data', function(value) { checkResponse(response_index, value); response_index += 1; }); for (var i = 0; i < 7; i++) { - call.write(new math.DivArgs({dividend: 2 * i + 1, divisor: 2})); + call.write({dividend: 2 * i + 1, divisor: 2}); } call.end(); call.on('status', function checkStatus(status) {