forked from benschmaus/nodeload
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request benschmaus#7 from gamechanger/tl-refactor
Refactored Program API
- Loading branch information
Showing
5 changed files
with
169 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,142 @@ | ||
var http = require('http'); | ||
|
||
var BUILD_AS_SINGLE_FILE; | ||
if (BUILD_AS_SINGLE_FILE === undefined) { | ||
var Program = require('./program').Program; | ||
} | ||
|
||
var registerHttp = exports.registerHttp = function() { | ||
Program.registerAttrHelper('host', function(hostname, port) { | ||
var settings = {hostname: hostname}; | ||
if (port) { | ||
settings.port = port; | ||
var _ = require('underscore'), | ||
request = require('superagent'), | ||
url = require('url'), | ||
fs = require('fs'), | ||
async = require('async'), | ||
temp = require('temp'), | ||
zlib = require('zlib'), | ||
querystring = require('querystring'), | ||
traverse = require('traverse'); | ||
|
||
_.str = require('underscore.string'); | ||
_.mixin(_.str); | ||
|
||
exports.request = function(options, next) { | ||
var self = this; | ||
options.headers = options.headers || {}; | ||
if (this.attrs.headers) { | ||
_(options.headers).extend(this.attrs.headers); | ||
} | ||
|
||
// Build a static JSON object from the options hash by invoking | ||
// any dynamic value functions. | ||
options = traverse(options).clone(); | ||
traverse(options).forEach(function(value) { | ||
if (_(value).isFunction()) { | ||
this.update(value.call(self, options)); | ||
} | ||
return settings; | ||
}, {hostname: 'localhost', port: 80}); | ||
}); | ||
|
||
if (!this.runData.requests) { | ||
this.runData.requests = []; | ||
} | ||
this.runData.requests.push(options); | ||
|
||
Program.registerInterpreter('request', function(options, optionsFn, cb) { | ||
self = this; | ||
if (optionsFn) { | ||
optionsFn.call(self, options); | ||
options.protocol = 'http'; | ||
options.pathname = options.path; | ||
options.hostname = options.hostname || this.attrs.hostname; | ||
options.port = options.port || this.attrs.port; | ||
var req = request(options.method, url.format(options)).set(options.headers); | ||
|
||
if (options.body) { | ||
var content; | ||
if (options.body.json) { | ||
// This is a total hack to deal with the fact that the API accepts this | ||
// bizarre urlencoded json string within a json object format. I'm sorry. | ||
var isV2 = options.path.indexOf('/v2') > 1, | ||
payload = JSON.stringify(options.body.json); | ||
content = querystring.stringify(isV2? {data: payload} : {json: payload}); | ||
|
||
} else { | ||
content = options.body; // wouldn't it be nice if it worked this way... | ||
} | ||
if (options.data) { | ||
options.headers['Content-Length'] = options.data.length; | ||
req.type('json').send(content); | ||
} | ||
req.end(function(res) { | ||
// Deal with the fact that sometimes, we get text/html as the | ||
// content type... sigh... | ||
if (res.type === 'text/html') { | ||
res.body = JSON.parse(res.text); | ||
} | ||
var req = http.request(options, function(res) { | ||
var finished = function() { | ||
cb({req: req, res: res}); | ||
}; | ||
if (options.cb) { | ||
return options.cb(req, res, finished); | ||
|
||
// Deal with the possibility of receiving errors via 200 | ||
// response and fudge the status code to give us meaningful | ||
// data in our reports. | ||
if (res.status == 200 && res.body.error) { | ||
res.status = 500; | ||
res.res.statusCode = 500; | ||
} | ||
|
||
if (res.status !== 200) { // TODO: Probably get ride of this | ||
console.log("Error: " + res.status); | ||
console.log(res.body); | ||
} | ||
|
||
options.response = res.body; | ||
next(res); | ||
}); | ||
}; | ||
|
||
// Sets the hostname and port (port optional) | ||
exports.host = function(hostname, port, next) { | ||
if (arguments.length === 2) { | ||
next = port; | ||
port = 80; | ||
} | ||
|
||
this.attrs.hostname = hostname; | ||
this.attrs.port = port; | ||
next(); | ||
}; | ||
|
||
exports.headers = function(headers, next) { | ||
this.attrs.headers = this.attrs.headers || {}; | ||
_(this.attrs.headers).extend(headers); | ||
next(); | ||
}; | ||
|
||
|
||
_(['get', 'post', 'put', 'delete']).each(function(verb) { | ||
exports[verb] = function(path, next) { | ||
// Sort out args - we also accept path inserts and an options hash | ||
// The last arg is always the "next" callback | ||
var options = {}; | ||
var pathInserts = []; | ||
_.chain(arguments).rest().initial().each(function(arg) { | ||
if (_(arg).isFunction()) { | ||
pathInserts.push(arg); | ||
} else { | ||
options = arg; | ||
} | ||
finished(); | ||
}); | ||
if (options.data) { | ||
if (typeof options.data === 'object') { | ||
options.data = JSON.stringify(options.data); | ||
} | ||
req.write(options.data); | ||
next = _(arguments).last(); | ||
options.method = verb.toUpperCase(); | ||
|
||
// If there were path inserts, we need to make path a function. | ||
if (pathInserts.length > 0) { | ||
options.path = function() { | ||
var args = [path]; | ||
// Allow path inserts to be functions | ||
args = args.concat(_(pathInserts).map(function(insert) { | ||
if (_(insert).isFunction()) { | ||
return insert(); | ||
} | ||
return insert; | ||
})); | ||
return _.sprintf.apply(this, args); | ||
}; | ||
} else { | ||
options.path = path; | ||
} | ||
req.end(); | ||
}, function(options, optionsFn) { | ||
options.hostname = options.hostname || this.attrs.hostname; | ||
options.port = options.port || this.attrs.port; | ||
return [options, optionsFn]; | ||
}); | ||
exports.request.call(this, options, next); | ||
}; | ||
}); | ||
|
||
Program.registerHelper('get', 'request', function(path, options, optionsFn) { | ||
options = options || {}; | ||
options.method = 'GET'; | ||
options.path = path; | ||
return [options, optionsFn]; | ||
exports.install = function(Program) { | ||
_(['get', 'post', 'put', 'delete']).each(function(method) { | ||
Program.registerInterpreter(method, exports[method], true); | ||
}); | ||
|
||
Program.registerHelper('post', 'request', function(path, data, options, optionsFn) { | ||
options = options || {}; | ||
options.method = 'POST'; | ||
options.path = path; | ||
options.data = data; | ||
return [options, optionsFn]; | ||
_(['headers', 'host']).each(function(method) { | ||
Program.registerInterpreter(method, exports[method], false); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,14 +7,9 @@ | |
"engines": { | ||
"node": ">=0.4" | ||
}, | ||
"contributors": [ | ||
"Benjamin Schmaus <[email protected]>", | ||
"Jonathan Lee <[email protected]>", | ||
"Robert Newson <[email protected]>", | ||
"Michael Mattozzi <[email protected]>" | ||
], | ||
"contributors": ["Benjamin Schmaus <[email protected]>", "Jonathan Lee <[email protected]>", "Robert Newson <[email protected]>", "Michael Mattozzi <[email protected]>"], | ||
"bugs": { | ||
"web" : "https://github.com/benschmaus/nodeload/issues" | ||
"web": "https://github.com/benschmaus/nodeload/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
|
@@ -38,12 +33,16 @@ | |
"expresso": ">=0.7.7" | ||
}, | ||
"dependencies": { | ||
"optparse": "1.0.3" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "https://github.com/benschmaus/nodeload/raw/master/LICENSE" | ||
} | ||
] | ||
"optparse": "1.0.3", | ||
"underscore": "~1.4.3", | ||
"underscore.string": "~2.3.1", | ||
"traverse": "~0.6.3", | ||
"superagent": "~0.12.1", | ||
"temp": "~0.5.0", | ||
"async": "~0.1.22" | ||
}, | ||
"licenses": [{ | ||
"type": "MIT", | ||
"url": "https://github.com/benschmaus/nodeload/raw/master/LICENSE" | ||
}] | ||
} |