Skip to content

Commit

Permalink
[refactor] Have the upload method use the same API signature as the…
Browse files Browse the repository at this point in the history
… `request` method.

[refactor] Make the `upload` method use the `request` API instead of duplicating code.
  • Loading branch information
3rd-Eden committed Jan 8, 2013
1 parent 92aef4e commit 3f67393
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 75 deletions.
125 changes: 53 additions & 72 deletions node.js/lib/client/client.js
Expand Up @@ -45,6 +45,7 @@ util.inherits(Client, EventEmitter);
// - remoteUri {String}: Location of the remote API
// - timeout {Number}: Request timeout
// - body {Array|Object}: JSON request body
// - headers {Object}: Headers you want to set
//
Client.prototype.request = function (options, callback) {
options = options || {};
Expand All @@ -67,10 +68,14 @@ Client.prototype.request = function (options, callback) {
if (options.body) {
try { opts.body = JSON.stringify(options.body); }
catch (e) { return callback(e); }
} else if (opts.method !== 'GET') {
} else if (opts.method !== 'GET' && options.body !== false) {
opts.body = '{}';
}

if (options.headers) Object.keys(options.headers).forEach(function each(field) {
opts.headers[field] = options.headers[field];
});

if (proxy) opts.proxy = proxy;

this.emit('debug::request', opts);
Expand Down Expand Up @@ -106,90 +111,66 @@ Client.prototype.request = function (options, callback) {
};

//
// ### function upload (uri, contentType, file, callback, success)
// #### @uri {Array} Locator for the Remote Resource
// #### @contentType {string} Content-Type header to use for the upload.
// #### @file {string} Path of the local file to upload.
// #### @success {function} Continuation to call upon successful transactions
// ### @private function upload (options, callback)
// #### @options {Object}
// #### @callback {function} Continuation to call if errors occur.
// Makes a `POST` request to `this.remoteUri + uri` with the data in `file`
// as the request body. Short circuits to `callback` if the response
// code from Nodejitsu matches `failCodes`.
// Makes a POST request to the remoteUri + uri using the HTTP and any body if
// supplied. It defers the call the private request method.
//
Client.prototype.upload = function (uri, contentType, file, callback, success) {
var self = this,
options,
out,
encoded,
emitter = new EventEmitter(),
proxy = self.options.get('proxy');

encoded = new Buffer(this.options.get('username') + ':' + this.options.get('password')).toString('base64');

fs.stat(file, function (err, stat) {
if (err) {
return callback(err);
}
// Options:
// - uri {Array}: Locator for the remote resource
// - remoteUri {String}: Location of the remote API
// - timeout {Number}: Request timeout
// - file: {String} path to the file you want to upload
//
Client.prototype.upload = function (options, callback) {
options = options || {};

emitter.emit('start', stat);

options = {
method: 'POST',
uri: self.options.get('remoteUri') + '/' + uri.join('/'),
headers: {
'Authorization': 'Basic ' + encoded,
'Content-Type': contentType,
'Content-Length': stat.size
},
timeout: self.options.get('timeout') || 8 * 60 * 1000
};
var progress = new EventEmitter(),
self = this;

if(proxy) {
options.proxy = proxy;
}
fs.stat(options.file, function fstat(err, stat) {
if (err) return callback(err);

out = self._request(options, function (err, response, body) {
if (err) {
return callback(err);
}

var statusCode, result, error;

try {
statusCode = response.statusCode;
result = JSON.parse(body);
}
catch (ex) {
// Ignore Errors
}
if (failCodes[statusCode]) {
error = new Error('Nodejitsu Error (' + statusCode + '): ' + failCodes[statusCode]);
error.result = result;
return callback(error);
}

success(response, result);
});
var size = stat.size;

// Set the correct headers
if (!options.headers) options.headers = {};
options.headers['Content-Length'] = size;
options.headers['Content-Type'] = options.contentType || 'application/octet-stream';

// And other default options to do a successful post
if (!options.method) options.method = 'POST';
options.body = false;

out.on('request', function(request) {
var buffer = 0;
request.on('socket', function(socket) {
var id = setInterval(function() {
// Defer all the error handling to the request method
var req = self.request(options, callback);
if (!req) return;

req.once('request', function requested(request) {
request.once('socket', function data(socket) {
var buffer = 0;

var interval = setInterval(function polling() {
var data = socket._bytesDispatched || (socket.socket && socket.socket._bytesDispatched);
emitter.emit('data', data - buffer);
buffer = data;
if(buffer >= stat.size) {
clearInterval(id);
emitter.emit('end');

if (data) {
progress.emit('data', data - buffer);
buffer = data;
}

if (buffer >= size) {
clearInterval(interval);
progress.emit('end');
}
},100);
}, 100);
});
});

fs.createReadStream(file).pipe(out);
fs.createReadStream(options.file).pipe(req);
});

return emitter;
return progress;
};

var failCodes = {
Expand Down
4 changes: 1 addition & 3 deletions node.js/lib/client/snapshots.js
Expand Up @@ -54,9 +54,7 @@ Snapshots.prototype.create = function (appName, snapshotName, filename, callback
appName = defaultUser.call(this, appName);
var argv = ['apps'].concat(appName.split('/')).concat(['snapshots', snapshotName]);

return this.upload(argv, 'application/octet-stream', filename, callback, function (res, body) {
callback(null, body || res.statusCode);
});
return this.upload({ uri: argv, file: filename }, callback);
};

//
Expand Down

0 comments on commit 3f67393

Please sign in to comment.