Skip to content

Commit

Permalink
logging: use gRPC
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenplusplus committed Mar 21, 2016
1 parent 057c8a0 commit a749f6f
Show file tree
Hide file tree
Showing 11 changed files with 659 additions and 450 deletions.
200 changes: 165 additions & 35 deletions lib/common/grpc-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ var HTTP_ERROR_CODE_MAP = {
* @param {object} config - Configuration object.
* @param {string} config.baseUrl - The base URL to make API requests to.
* @param {string[]} config.scopes - The scopes required for the request.
* @param {string} config.service - The name of the service.
* @param {object=} config.protoServices - Directly provide the required proto
* files. This is useful when a single class requires multiple services.
* @param {object} options - [Configuration object](#/docs/?method=gcloud).
*/
function GrpcService(config, options) {
Expand All @@ -146,19 +149,31 @@ function GrpcService(config, options) {

Service.call(this, config, options);

var service = config.service;
if (config.customEndpoint) {
this.grpcCredentials = grpc.credentials.createInsecure();
}

var apiVersion = config.apiVersion;
var service = this.service = config.service;
var rootDir = googleProtoFiles('..');

if (config.customEndpoint) {
this.grpcCredentials = grpc.credentials.createInsecure();
this.protos = {};

var protoServices = config.protoServices;

if (!protoServices) {
protoServices = {};
protoServices[service] = googleProtoFiles[service][apiVersion];
}

this.protoOpts = config.proto;
this.proto = grpc.load({
root: rootDir,
file: path.relative(rootDir, googleProtoFiles[service][apiVersion])
}).google[service][apiVersion];
for (var protoService in protoServices) {
var protoFilePath = protoServices[protoService];

this.protos[protoService] = grpc.load({
root: rootDir,
file: path.relative(rootDir, protoFilePath)
}).google[service][apiVersion];
}
}

nodeutil.inherits(GrpcService, Service);
Expand All @@ -180,7 +195,13 @@ GrpcService.prototype.request = function(protoOpts, reqOpts, callback) {
}

var self = this;
var proto = this.proto;
var proto;

if (this.protos[protoOpts.service]) {
proto = this.protos[protoOpts.service];
} else {
proto = this.protos[this.service];
}

if (!this.grpcCredentials) {
// We must establish an authClient to give to grpc.
Expand Down Expand Up @@ -229,7 +250,7 @@ GrpcService.prototype.request = function(protoOpts, reqOpts, callback) {
return;
}

callback(null, self.convertBuffers_(camelize(resp)));
callback(null, GrpcService.convertBuffers_(camelize(resp)));
}, null, grpcOpts);
};

Expand All @@ -244,9 +265,9 @@ GrpcService.prototype.request = function(protoOpts, reqOpts, callback) {
* @param {*} data - An object or array to iterate over.
* @return {*} - The converted object.
*/
GrpcService.prototype.convertBuffers_ = function(data) {
GrpcService.convertBuffers_ = function(data) {
if (is.array(data)) {
return data.map(this.convertBuffers_.bind(this));
return data.map(GrpcService.convertBuffers_);
}

if (is.object(data)) {
Expand All @@ -256,10 +277,11 @@ GrpcService.prototype.convertBuffers_ = function(data) {

if (Buffer.isBuffer(value)) {
data[prop] = value.toString('base64');
} else if (this.isBufferLike_(value)) {
data[prop] = new Buffer(this.objToArr_(value)).toString('base64');
} else if (GrpcService.isBufferLike_(value)) {
var arrayValue = GrpcService.objToArr_(value);
data[prop] = new Buffer(arrayValue).toString('base64');
} else {
data[prop] = this.convertBuffers_(value);
data[prop] = GrpcService.convertBuffers_(value);
}
}
}
Expand All @@ -269,28 +291,49 @@ GrpcService.prototype.convertBuffers_ = function(data) {
};

/**
* To authorize requests through gRPC, we must get the raw google-auth-library
* auth client object.
* Convert a raw value to a type-denoted protobuf message-friendly object.
*
* @private
*
* @param {function} callback - The callback function.
* @param {?error} callback.err - An error getting an auth client.
* @param {*} value - The input value.
* @return {*} - The converted value.
*
* @example
* GrpcService.convertValue_('Hi');
* // {
* // stringValue: 'Hello!'
* // }
*/
GrpcService.prototype.getGrpcCredentials_ = function(callback) {
this.authClient.getAuthClient(function(err, authClient) {
if (err) {
callback(err);
return;
}

var credentials = grpc.credentials.combineChannelCredentials(
grpc.credentials.createSsl(),
grpc.credentials.createFromGoogleCredential(authClient)
);
GrpcService.convertValue_ = function(value) {
var convertedValue;

if (is.null(value)) {
convertedValue = {
nullValue: null
};
} else if (is.number(value)) {
convertedValue = {
numberValue: value
};
} else if (is.string(value)) {
convertedValue = {
stringValue: value
};
} else if (is.boolean(value)) {
convertedValue = {
booleanValue: value
};
} else if (is.object(value)) {
convertedValue = GrpcService.objToStruct_(value);
} else if (is.array(value)) {
convertedValue = {
listValue: value.map(GrpcService.convertValue_)
};
} else {
throw new Error('Value of type ' + typeof value + ' not recognized.');
}

callback(null, credentials);
});
return convertedValue;
};

/**
Expand All @@ -307,7 +350,7 @@ GrpcService.prototype.getGrpcCredentials_ = function(callback) {
* @param {*} value - Any value.
* @return {boolean} - Is the object a buffer.
*/
GrpcService.prototype.isBufferLike_ = function(value) {
GrpcService.isBufferLike_ = function(value) {
if (!is.object(value) || is.empty(value)) {
return false;
}
Expand Down Expand Up @@ -342,14 +385,14 @@ GrpcService.prototype.isBufferLike_ = function(value) {
* @return {array} - The converted array.
*
* @example
* grpcService.objToArr_({
* GrpcService.objToArr_({
* 0: 'a',
* 1: 'b',
* 2: 'c'
* });
* // ['a', 'b', 'c']
*/
GrpcService.prototype.objToArr_ = function(obj) {
GrpcService.objToArr_ = function(obj) {
var arr = [];

for (var prop in obj) {
Expand All @@ -361,4 +404,91 @@ GrpcService.prototype.objToArr_ = function(obj) {
return arr;
};

/**
* Convert an object to a struct.
*
* @private
*
* @param {object} obj - An object to convert.
* @return {array} - The converted object.
*
* @example
* GrpcService.objToStruct_({
* greeting: 'Hello!',
* favNumber: 7,
* friendIds: [
* 1004,
* 1006
* ],
* userDetails: {
* termsSigned: true
* }
* });
* // {
* // fields: {
* // greeting: {
* // stringValue: 'Hello!'
* // },
* // favNumber: {
* // numberValue: 7
* // },
* // friendIds: {
* // listValue: [
* // {
* // numberValue: 1004
* // },
* // {
* // numberValue: 1006
* // }
* // ]
* // },
* // userDetails: {
* // fields: {
* // termsSigned: {
* // booleanValue: true
* // }
* // }
* // }
* // }
* // }
*/
GrpcService.objToStruct_ = function(obj) {
var convertedObject = {
fields: {}
};

for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
convertedObject.fields[prop] = GrpcService.convertValue_(obj[prop]);
}
}

return convertedObject;
};

/**
* To authorize requests through gRPC, we must get the raw google-auth-library
* auth client object.
*
* @private
*
* @param {function} callback - The callback function.
* @param {?error} callback.err - An error getting an auth client.
*/
GrpcService.prototype.getGrpcCredentials_ = function(callback) {
this.authClient.getAuthClient(function(err, authClient) {
if (err) {
callback(err);
return;
}

var credentials = grpc.credentials.combineChannelCredentials(
grpc.credentials.createSsl(),
grpc.credentials.createFromGoogleCredential(authClient)
);

callback(null, credentials);
});
};

module.exports = GrpcService;
8 changes: 7 additions & 1 deletion lib/logging/entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
var extend = require('extend');
var is = require('is');

/**
* @type {module:common/grpcService}
* @private
*/
var GrpcService = require('../common/grpc-service.js');

/**
* Create an entry object to define new data to insert into a log.
*
Expand Down Expand Up @@ -132,7 +138,7 @@ Entry.prototype.toJSON = function() {
}

if (is.object(this.data)) {
entry.jsonPayload = this.data;
entry.jsonPayload = GrpcService.objToStruct_(this.data);
} else if (is.string(this.data)) {
entry.textPayload = this.data;
}
Expand Down
Loading

0 comments on commit a749f6f

Please sign in to comment.