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