Skip to content

docs. #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2014
Merged

docs. #108

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 120 additions & 34 deletions lib/common/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,56 @@
* limitations under the License.
*/

/**
* @module common/connection
*/

'use strict';

var fs = require('fs');
var GAPIToken = require('gapitoken');
var req = require('request');
var pkg = require('../../package.json');

/** @type {module:common/util} */
var util = require('./util');

/** @const {string} Base URL for outgoing requests. */
var METADATA_TOKEN_URL =
'http://metadata/computeMetadata/v1/instance/service-accounts/default/' +
'token';
var USER_AGENT = 'gcloud-node/' + pkg.version;

/** @const {object} gcloud-node's package.json file. */
var PKG = require('../../package.json');

/** @const {string} User agent. */
var USER_AGENT = 'gcloud-node/' + PKG.version;

/**
* Token represents an access token
* @param {string} accessToken Access token.
* @param {string} expiry Expiration datetime.
* Token represents an access token.
*
* @constructor
* @param {string} accessToken - Access token.
* @param {date} expiry - Expiration datetime.
*
* @example
* ```js
* var token = new Token(ACCESS_TOKEN, EXPIRY);
* ```
*/
function Token(accessToken, expiry) {
this.accessToken = accessToken;
this.expiry = expiry;
}

/**
* Returns true if token is expired.
* @return {Boolean}
* Is this token expired?
*
* @return {boolean}
*
* @example
* ```js
* token.isExpired();
* ```
*/
Token.prototype.isExpired = function() {
if (!this.accessToken || !this.expiry) {
Expand All @@ -48,8 +72,22 @@ Token.prototype.isExpired = function() {
return new Date().getTime() - this.expiry.getTime() > 0;
};

module.exports.Token = Token;

/**
* @param {Object} opts Options.
* Create a connection object.
*
* @param {object} opts - Configuration options.
* @param {array} opts.scopes - Scopes required for access.
*
* @example
* ```js
* var SCOPES = [
* 'https://www.googleapis.com/auth/datastore',
* 'https://www.googleapis.com/auth/userinfo.email'
* ];
* var conn = new Connection({ scopes: SCOPES });
* ```
*/
function Connection(opts) {
this.opts = opts || {};
Expand All @@ -63,13 +101,19 @@ function Connection(opts) {
}

/**
* Retrieves a token to authorize the requests.
* @param {Function} callback Callback.
* Retrieve a token to authorize requests.
*
* @todo Connect should be context aware, it should not require an email and
* key, if it's running on Google Compute Engine.
*
* @param {function} callback - The callback function.
*
* @example
* ```js
* conn.connect(function(err) {});
* ```
*/
Connection.prototype.connect = function(callback) {
// TODO(jbd): Connect should be context aware,
// should not require an email and key, if it's
// running on Google Compute Engine.
var that = this;
this.isConnecting = true;
// retrieves an access token
Expand All @@ -83,8 +127,14 @@ Connection.prototype.connect = function(callback) {
};

/**
* Fetches a new access token.
* @param {Function} callback Callback function.
* Fetch a new access token.
*
* @param {function} callback - The callback function.
*
* @example
* ```js
* conn.fetchToken(function(err) {});
* ```
*/
Connection.prototype.fetchToken = function(callback) {
var that = this;
Expand Down Expand Up @@ -121,6 +171,18 @@ Connection.prototype.fetchToken = function(callback) {
this.fetchServiceAccountToken_(callback);
};

/**
* Fetch a service account token.
*
* @private
*
* @param {function} callback - The callback function.
*
* @example
* ```js
* conn.fetchServiceAccountToken_(function(err) {});
* ```
*/
Connection.prototype.fetchServiceAccountToken_ = function(callback) {
var gapi = new GAPIToken({
iss: this.credentials.client_email,
Expand All @@ -141,15 +203,21 @@ Connection.prototype.fetchServiceAccountToken_ = function(callback) {
};

/**
* Makes an authorized request if the current connection token is
* still valid. Tries to reconnect and makes a request otherwise.
* @param {Object} Request options.
* @param {Function=} callback
* Make an authorized request if the current connection token is still valid. If
* it's not, try to reconnect.
*
* @param {object} requestOptions - Request options.
* @param {function=} callback - The callback function.
*
* @example
* ```js
* conn.req({}, function(err) {});
* ```
*/
Connection.prototype.req = function(reqOpts, callback) {
Connection.prototype.req = function(requestOptions, callback) {
var that = this;
callback = callback || util.noop;
this.createAuthorizedReq(reqOpts, function(err, authorizedReq) {
this.createAuthorizedReq(requestOptions, function(err, authorizedReq) {
if (err) {
callback(err);
return;
Expand All @@ -158,6 +226,17 @@ Connection.prototype.req = function(reqOpts, callback) {
});
};

/**
* Create an authorized request.
*
* @param {object} requestOptions - Request options.
* @param {function} callback - The callback function.
*
* @example
* ```js
* conn.createAuthorizedReq({}, function(err) {});
* ```
*/
Connection.prototype.createAuthorizedReq = function(reqOpts, callback) {
var that = this;
// Add user agent.
Expand Down Expand Up @@ -201,26 +280,33 @@ Connection.prototype.createAuthorizedReq = function(reqOpts, callback) {
Connection.prototype.requester = req;

/**
* Returns true if connection is inited with a valid token
* that is not expired.
* @return {Boolean} The status of the connection.
* Get the status of the connection.
*
* `true`: connection is inited with a valid token that is not expired.
*
* @return {boolean}
*
* @example
* ```js
* conn.isConnected();
* ```
*/
Connection.prototype.isConnected = function() {
return this.token && !this.token.isExpired();
};

/**
* Adds authorization header to the specified request.
* @param {Object} reqOpts Request options.
* @return {Object} Authorized request options.
* Add authorization header to the specified request.
*
* @todo Clone the request object.
*
* @param {object} requestOptions - Request options.
* @return {object} Authorized request options.
*/
Connection.prototype.authorizeReq = function(reqOpts) {
// TODO(jbd): Clone the request object.
reqOpts.headers = reqOpts.headers || {};
reqOpts.headers.Authorization = 'Bearer ' + this.token.accessToken;
return reqOpts;
Connection.prototype.authorizeReq = function(requestOptions) {
requestOptions.headers = requestOptions.headers || {};
requestOptions.headers.Authorization = 'Bearer ' + this.token.accessToken;
return requestOptions;
};

module.exports.Token = Token;

module.exports.Connection = Connection;
97 changes: 86 additions & 11 deletions lib/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,20 @@

/*jshint strict:false, noarg:false */

/**
* @module common/util
*/

var util = require('util');

/**
* Extend a base object with properties from another.
*
* @param {object} from - The base object.
* @param {object} to - The object to extend with.
* @return {object}
* ```
*/
function extend(from, to) {
if (from === null || typeof from !== 'object') {
return from;
Expand All @@ -39,25 +51,78 @@ function extend(from, to) {

module.exports.extend = extend;

module.exports.arrayize = function(input) {
/**
* Wrap an array around a non-Array object. If given an Array, it is returned.
*
* @param {*} input - Non-array object to wrap.
* @return {array}
*
* @example
* ```js
* arrayize(2);
* // [ 2 ]
*
* arrayize(['Hi']);
* // [ 'Hi' ]
* ```
*/
function arrayize(input) {
if (!Array.isArray(input)) {
return [input];
}
return input;
};
}

module.exports.format = function(templ, args) {
Object.keys(args).forEach(function(k) {
templ = templ.replace('{' + k + '}', args[k]);
module.exports.arrayize = arrayize;

/**
* Format a string with values from the provided object.
*
* @param {string} template - String with {} denoted keys. (See example)
* @param {object} args - Key/value pairs matching the holes in the template.
* @return {string}
*
* @example
* ```js
* format('This is a {language} ({abbr}) codebase.', {
* language: 'JavaScript',
* abbr: 'JS'
* });
* // 'This is a JavaScript (JS) codebase.'
* ```
*/
function format(template, args) {
return template.replace(/{([^}]*)}/g, function(match, key) {
return args[key] || match;
});
return templ;
};
}

var noop = function() {};
module.exports.format = format;

/**
* No op.
*
* @example
* ```js
* function doSomething(callback) {
* callback = callback || noop;
* }
* ```
*/
function noop() {}

module.exports.noop = noop;

function ApiError (errorBody) {
/**
* Extend the native Error object.
*
* @constructor
*
* @private
*
* @param {object} errorBody - Error object.
*/
function ApiError(errorBody) {
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.errors = errorBody.errors;
Expand All @@ -67,7 +132,15 @@ function ApiError (errorBody) {

util.inherits(ApiError, Error);

module.exports.handleResp = function(err, resp, body, callback) {
/**
* Uniformly process an API response.
*
* @param {*} err - Error value.
* @param {*} resp - Response value.
* @param {*} body - Body value.
* @param {function} callback - The callback function.
*/
function handleResp(err, resp, body, callback) {
callback = callback || noop;
if (err) {
callback(err);
Expand All @@ -87,4 +160,6 @@ module.exports.handleResp = function(err, resp, body, callback) {
return;
}
callback(null, body, resp);
};
}

module.exports.handleResp = handleResp;
Loading