loopback/node_modules/route/lib/http-context.js

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);
}
}