var loopback = require('../loopback'); var juggler = require('loopback-datasource-juggler'); var remoting = require('strong-remoting'); var cls = require('continuation-local-storage'); module.exports = context; var name = 'loopback'; function context(options) { options = options || {}; var scope = options.name || name; var enableHttpContext = options.enableHttpContext || false; var ns = cls.createNamespace(scope); // Make the namespace globally visible via the process.context property process.context = process.context || {}; process.context[scope] = ns; // Set up loopback.getCurrentContext() loopback.getCurrentContext = function() { return ns; }; chain(juggler); chain(remoting); // Return the middleware return function(req, res, next) { // Bind req/res event emitters to the given namespace ns.bindEmitter(req); ns.bindEmitter(res); // Create namespace for the request context ns.run(function(context) { // Run the code in the context of the namespace if(enableHttpContext) { ns.set('http', {req: req, res: res}); // Set up the transport context } next(); }); }; } /** * Create a chained context * @param {Object} child The child context * @param {Object} parent The parent context * @private * @constructor */ function ChainedContext(child, parent) { this.child = child; this.parent = parent; } /** * Get the value by name from the context. If it doesn't exist in the child * context, try the parent one * @param {String} name Name of the context property * @returns {*} Value of the context property */ ChainedContext.prototype.get = function (name) { var val = this.child && this.child.get(name); if (val === undefined) { return this.parent && this.parent.get(name); } }; ChainedContext.prototype.set = function (name, val) { if (this.child) { return this.child.set(name, val); } else { return this.parent && this.parent.set(name, val); } }; ChainedContext.prototype.reset = function (name, val) { if (this.child) { return this.child.reset(name, val); } else { return this.parent && this.parent.reset(name, val); } }; function chain(child) { if (typeof child.getCurrentContext === 'function') { var childContext = new ChainedContext(child.getCurrentContext(), loopback.getCurrentContext()); child.getCurrentContext = function() { return childContext; }; } else { child.getCurrentContext = loopback.getCurrentContext; } }