Merge pull request #2704 from murgatroid99/node_method_name_conflicts

Ensure that client generated methods don't conflict with other properties
This commit is contained in:
Tim Emiola 2015-08-31 14:22:32 -07:00
commit ed6c55f68d
4 changed files with 95 additions and 52 deletions

View File

@ -164,3 +164,13 @@ exports.ServerCredentials = grpc.ServerCredentials;
* @see module:src/client.makeClientConstructor * @see module:src/client.makeClientConstructor
*/ */
exports.makeGenericClientConstructor = client.makeClientConstructor; exports.makeGenericClientConstructor = client.makeClientConstructor;
/**
* @see module:src/client.getClientChannel
*/
exports.getClientChannel = client.getClientChannel;
/**
* @see module:src/client.waitForClientReady
*/
exports.waitForClientReady = client.waitForClientReady;

View File

@ -285,7 +285,7 @@ function authTest(expected_user, scope, client, done) {
if (credential.createScopedRequired() && scope) { if (credential.createScopedRequired() && scope) {
credential = credential.createScoped(scope); credential = credential.createScoped(scope);
} }
client.updateMetadata = grpc.getGoogleAuthDelegate(credential); client.$updateMetadata = grpc.getGoogleAuthDelegate(credential);
var arg = { var arg = {
response_type: 'COMPRESSABLE', response_type: 'COMPRESSABLE',
response_size: 314159, response_size: 314159,
@ -338,7 +338,7 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) {
if (per_rpc) { if (per_rpc) {
updateMetadata('', {}, makeTestCall); updateMetadata('', {}, makeTestCall);
} else { } else {
client.updateMetadata = updateMetadata; client.$updateMetadata = updateMetadata;
makeTestCall(null, {}); makeTestCall(null, {});
} }
}); });

View File

@ -32,7 +32,7 @@
*/ */
/** /**
* Server module * Client module
* @module * @module
*/ */
@ -270,7 +270,7 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
function makeUnaryRequest(argument, callback, metadata, options) { function makeUnaryRequest(argument, callback, metadata, options) {
/* jshint validthis: true */ /* jshint validthis: true */
var emitter = new EventEmitter(); var emitter = new EventEmitter();
var call = getCall(this.channel, method, options); var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) { if (metadata === null || metadata === undefined) {
metadata = new Metadata(); metadata = new Metadata();
} else { } else {
@ -282,7 +282,7 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
emitter.getPeer = function getPeer() { emitter.getPeer = function getPeer() {
return call.getPeer(); return call.getPeer();
}; };
this.updateMetadata(this.auth_uri, metadata, function(error, metadata) { this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) { if (error) {
call.cancel(); call.cancel();
callback(error); callback(error);
@ -364,14 +364,14 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
*/ */
function makeClientStreamRequest(callback, metadata, options) { function makeClientStreamRequest(callback, metadata, options) {
/* jshint validthis: true */ /* jshint validthis: true */
var call = getCall(this.channel, method, options); var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) { if (metadata === null || metadata === undefined) {
metadata = new Metadata(); metadata = new Metadata();
} else { } else {
metadata = metadata.clone(); metadata = metadata.clone();
} }
var stream = new ClientWritableStream(call, serialize); var stream = new ClientWritableStream(call, serialize);
this.updateMetadata(this.auth_uri, metadata, function(error, metadata) { this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) { if (error) {
call.cancel(); call.cancel();
callback(error); callback(error);
@ -455,14 +455,14 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
*/ */
function makeServerStreamRequest(argument, metadata, options) { function makeServerStreamRequest(argument, metadata, options) {
/* jshint validthis: true */ /* jshint validthis: true */
var call = getCall(this.channel, method, options); var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) { if (metadata === null || metadata === undefined) {
metadata = new Metadata(); metadata = new Metadata();
} else { } else {
metadata = metadata.clone(); metadata = metadata.clone();
} }
var stream = new ClientReadableStream(call, deserialize); var stream = new ClientReadableStream(call, deserialize);
this.updateMetadata(this.auth_uri, metadata, function(error, metadata) { this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) { if (error) {
call.cancel(); call.cancel();
stream.emit('error', error); stream.emit('error', error);
@ -533,14 +533,14 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
*/ */
function makeBidiStreamRequest(metadata, options) { function makeBidiStreamRequest(metadata, options) {
/* jshint validthis: true */ /* jshint validthis: true */
var call = getCall(this.channel, method, options); var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) { if (metadata === null || metadata === undefined) {
metadata = new Metadata(); metadata = new Metadata();
} else { } else {
metadata = metadata.clone(); metadata = metadata.clone();
} }
var stream = new ClientDuplexStream(call, serialize, deserialize); var stream = new ClientDuplexStream(call, serialize, deserialize);
this.updateMetadata(this.auth_uri, metadata, function(error, metadata) { this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) { if (error) {
call.cancel(); call.cancel();
stream.emit('error', error); stream.emit('error', error);
@ -631,45 +631,21 @@ exports.makeClientConstructor = function(methods, serviceName) {
options = {}; options = {};
} }
options['grpc.primary_user_agent'] = 'grpc-node/' + version; options['grpc.primary_user_agent'] = 'grpc-node/' + version;
this.channel = new grpc.Channel(address, credentials, options); /* Private fields use $ as a prefix instead of _ because it is an invalid
* prefix of a method name */
this.$channel = new grpc.Channel(address, credentials, options);
// Remove the optional DNS scheme, trailing port, and trailing backslash // Remove the optional DNS scheme, trailing port, and trailing backslash
address = address.replace(/^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$/, '$2'); address = address.replace(/^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$/, '$2');
this.server_address = address; this.$server_address = address;
this.auth_uri = 'https://' + this.server_address + '/' + serviceName; this.$auth_uri = 'https://' + this.server_address + '/' + serviceName;
this.updateMetadata = updateMetadata; this.$updateMetadata = updateMetadata;
} }
/**
* Wait for the client to be ready. The callback will be called when the
* client has successfully connected to the server, and it will be called
* with an error if the attempt to connect to the server has unrecoverablly
* failed or if the deadline expires. This function will make the channel
* start connecting if it has not already done so.
* @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
* Infinity to wait forever.
* @param {function(Error)} callback The callback to call when done attempting
* to connect.
*/
Client.prototype.$waitForReady = function(deadline, callback) {
var self = this;
var checkState = function(err) {
if (err) {
callback(new Error('Failed to connect before the deadline'));
}
var new_state = self.channel.getConnectivityState(true);
if (new_state === grpc.connectivityState.READY) {
callback();
} else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
callback(new Error('Failed to connect to server'));
} else {
self.channel.watchConnectivityState(new_state, deadline, checkState);
}
};
checkState();
};
_.each(methods, function(attrs, name) { _.each(methods, function(attrs, name) {
var method_type; var method_type;
if (_.startsWith(name, '$')) {
throw new Error('Method names cannot start with $');
}
if (attrs.requestStream) { if (attrs.requestStream) {
if (attrs.responseStream) { if (attrs.responseStream) {
method_type = 'bidi'; method_type = 'bidi';
@ -694,6 +670,44 @@ exports.makeClientConstructor = function(methods, serviceName) {
return Client; return Client;
}; };
/**
* Return the underlying channel object for the specified client
* @param {Client} client
* @return {Channel} The channel
*/
exports.getClientChannel = function(client) {
return client.$channel;
};
/**
* Wait for the client to be ready. The callback will be called when the
* client has successfully connected to the server, and it will be called
* with an error if the attempt to connect to the server has unrecoverablly
* failed or if the deadline expires. This function will make the channel
* start connecting if it has not already done so.
* @param {Client} client The client to wait on
* @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
* Infinity to wait forever.
* @param {function(Error)} callback The callback to call when done attempting
* to connect.
*/
exports.waitForClientReady = function(client, deadline, callback) {
var checkState = function(err) {
if (err) {
callback(new Error('Failed to connect before the deadline'));
}
var new_state = client.$channel.getConnectivityState(true);
if (new_state === grpc.connectivityState.READY) {
callback();
} else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
callback(new Error('Failed to connect to server'));
} else {
client.$channel.watchConnectivityState(new_state, deadline, checkState);
}
};
checkState();
};
/** /**
* Creates a constructor for clients for the given service * Creates a constructor for clients for the given service
* @param {ProtoBuf.Reflect.Service} service The service to generate a client * @param {ProtoBuf.Reflect.Service} service The service to generate a client

View File

@ -133,7 +133,25 @@ describe('Server.prototype.addProtoService', function() {
}); });
}); });
}); });
describe('Client#$waitForReady', function() { describe('Client constructor building', function() {
var illegal_service_attrs = {
$method : {
path: '/illegal/$method',
requestStream: false,
responseStream: false,
requestSerialize: _.identity,
requestDeserialize: _.identity,
responseSerialize: _.identity,
responseDeserialize: _.identity
}
};
it('Should reject method names starting with $', function() {
assert.throws(function() {
grpc.makeGenericClientConstructor(illegal_service_attrs);
}, /\$/);
});
});
describe('waitForClientReady', function() {
var server; var server;
var port; var port;
var Client; var Client;
@ -151,13 +169,13 @@ describe('Client#$waitForReady', function() {
server.forceShutdown(); server.forceShutdown();
}); });
it('should complete when called alone', function(done) { it('should complete when called alone', function(done) {
client.$waitForReady(Infinity, function(error) { grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error); assert.ifError(error);
done(); done();
}); });
}); });
it('should complete when a call is initiated', function(done) { it('should complete when a call is initiated', function(done) {
client.$waitForReady(Infinity, function(error) { grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error); assert.ifError(error);
done(); done();
}); });
@ -166,19 +184,19 @@ describe('Client#$waitForReady', function() {
}); });
it('should complete if called more than once', function(done) { it('should complete if called more than once', function(done) {
done = multiDone(done, 2); done = multiDone(done, 2);
client.$waitForReady(Infinity, function(error) { grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error); assert.ifError(error);
done(); done();
}); });
client.$waitForReady(Infinity, function(error) { grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error); assert.ifError(error);
done(); done();
}); });
}); });
it('should complete if called when already ready', function(done) { it('should complete if called when already ready', function(done) {
client.$waitForReady(Infinity, function(error) { grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error); assert.ifError(error);
client.$waitForReady(Infinity, function(error) { grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error); assert.ifError(error);
done(); done();
}); });
@ -426,7 +444,8 @@ describe('Other conditions', function() {
server.forceShutdown(); server.forceShutdown();
}); });
it('channel.getTarget should be available', function() { it('channel.getTarget should be available', function() {
assert.strictEqual(typeof client.channel.getTarget(), 'string'); assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(),
'string');
}); });
describe('Server recieving bad input', function() { describe('Server recieving bad input', function() {
var misbehavingClient; var misbehavingClient;