114 lines
2.4 KiB
JavaScript
114 lines
2.4 KiB
JavaScript
|
/**
|
||
|
* Expose `HttpContext`.
|
||
|
*/
|
||
|
|
||
|
module.exports = HttpContext;
|
||
|
|
||
|
/**
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
var EventEmitter = require('events').EventEmitter
|
||
|
, debug = require('debug')('http-context')
|
||
|
, util = require('util')
|
||
|
, inherits = util.inherits
|
||
|
, assert = require('assert');
|
||
|
|
||
|
/**
|
||
|
* Create a new `HttpContext` with the given `options`.
|
||
|
*
|
||
|
* @param {Object} options
|
||
|
* @return {HttpContext}
|
||
|
*/
|
||
|
|
||
|
function HttpContext(resource, req, res, next) {
|
||
|
EventEmitter.apply(this, arguments);
|
||
|
|
||
|
this.resource = resource;
|
||
|
this.req = req;
|
||
|
this.res = res;
|
||
|
this.next = next;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Inherit from `EventEmitter`.
|
||
|
*/
|
||
|
|
||
|
inherits(HttpContext, EventEmitter);
|
||
|
|
||
|
/**
|
||
|
* Override the default emitter behavior to support async or sync hooks before and after an event.
|
||
|
*/
|
||
|
|
||
|
HttpContext.prototype.emit = function (ev) {
|
||
|
var ctx = this;
|
||
|
var resource = this.resource;
|
||
|
var origArgs = arguments;
|
||
|
var args = Array.prototype.slice.call(arguments, 0)
|
||
|
var success = arguments[arguments.length - 1];
|
||
|
|
||
|
assert(typeof success === 'function', 'ctx.emit requires a callback');
|
||
|
args.pop();
|
||
|
|
||
|
var evName = ev;
|
||
|
assert(typeof evName === 'string');
|
||
|
args.shift();
|
||
|
|
||
|
var listeners = resource.listeners(evName);
|
||
|
var listener;
|
||
|
|
||
|
// start
|
||
|
next();
|
||
|
|
||
|
function next(err) {
|
||
|
if(err) return fail(err);
|
||
|
|
||
|
try {
|
||
|
if(listener = listeners.shift()) {
|
||
|
var expectsCallback = listener._expects === args.length + 2;
|
||
|
|
||
|
// if a listener expects all the `args`
|
||
|
// plus ctx, and a callback
|
||
|
if(expectsCallback) {
|
||
|
// include ctx (this) and pass next to continue
|
||
|
listener.apply(resource, args.concat([this, next]));
|
||
|
} else {
|
||
|
// dont include the callback
|
||
|
listener.apply(resource, args.concat([this]));
|
||
|
// call next directly
|
||
|
next();
|
||
|
}
|
||
|
} else {
|
||
|
success(done);
|
||
|
}
|
||
|
} catch(e) {
|
||
|
fail(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function fail(err) {
|
||
|
ctx.done(err);
|
||
|
}
|
||
|
|
||
|
function done(err, result) {
|
||
|
if(err) {
|
||
|
return fail(err);
|
||
|
}
|
||
|
|
||
|
ctx.emit.apply(ctx,
|
||
|
['after:' + evName] // after event
|
||
|
.concat(args) // include original arguments/data
|
||
|
.concat([function () { // success callback
|
||
|
ctx.done.call(ctx, err, result);
|
||
|
}])
|
||
|
);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
HttpContext.prototype.done = function (err, result) {
|
||
|
if(err) {
|
||
|
this.next(err);
|
||
|
} else {
|
||
|
this.res.send(result);
|
||
|
}
|
||
|
}
|