UNPKG

@balderdash/sails-edge

Version:

API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)

188 lines (152 loc) 5.77 kB
var async = require('async'); var _ = require('lodash'); var util = require('util'); var __Configuration = require('./configuration'); var __initializeHooks = require('./private/loadHooks'); module.exports = function(sails) { var Configuration = __Configuration(sails); var initializeHooks = __initializeHooks(sails); /** * Expose loader start point. * (idempotent) * * @api public */ return function load(configOverride, cb) { if (sails._exiting) { return cb(new Error('\n*********\nCannot load or lift an app after it has already been lowered. \nYou can make a new app instance with:\nvar SailsApp = require(\'sails\').Sails;\nvar sails = new SailsApp();\n\nAnd then you can do:\nsails.load([opts,] cb)\n\n')); } // configOverride is optional if (_.isFunction(configOverride)) { cb = configOverride; configOverride = {}; } // Ensure override is an object and clone it (or make an empty object if it's not) configOverride = configOverride || {}; sails.config = _.cloneDeep(configOverride); // If host is explicitly specified, set `explicitHost` // (otherwise when host is omitted, Express will accept all connections via INADDR_ANY) if (configOverride.host) { configOverride.explicitHost = configOverride.host; } // Optionally expose services, models, sails, _, async, etc. as globals as soon as the // user config loads. sails.on('hook:userconfig:loaded', sails.exposeGlobals); async.auto({ // Apply core defaults and hook-agnostic configuration, // esp. overrides including command-line options, environment variables, // and options that were passed in programmatically. config: [Configuration.load], // Load hooks into memory, with their middleware and routes hooks: ['config', loadHooks], // Populate the "registry" // Houses "middleware-esque" functions bound by various hooks and/or Sails core itself. // (i.e. `function (req, res [,next]) {}`) // // (Basically, that means we grab an exposed `middleware` object, // full of functions, from each hook, then make it available as // `sails.middleware.[HOOK_ID]`.) // // TODO: finish refactoring to change "middleware" nomenclature // to avoid confusion with the more specific (and more common) // usage of the term. registry: ['hooks', function populateRegistry(cb) { sails.log.verbose('Instantiating registry...'); // Iterate through hooks and absorb the middleware therein // Save a reference to registry and expose it on // the Sails instance. sails.middleware = sails.registry = // Namespace functions by their source hook's identity _.reduce(sails.hooks, function(registry, hook, identity) { registry[identity] = hook.middleware; return registry; }, {}); sails.emit('middleware:registered'); cb(); } ], // Load the router and bind routes in `sails.config.routes` router: ['registry', sails.router.load] }, ready__(cb)); // Makes `app.load()` chainable return sails; }; /** * Load hooks in parallel * let them work out dependencies themselves, * taking advantage of events fired from the sails object * * @api private */ function loadHooks(cb) { sails.hooks = { }; // If config.hooks is disabled, skip hook loading altogether if (sails.config.hooks === false) { return cb(); } async.series([ function(cb) { loadHookDefinitions(sails.hooks, cb); }, function(cb) { initializeHooks(sails.hooks, cb); } ], function(err) { if (err) return cb(err); // Inform any listeners that the initial, built-in hooks // are finished loading sails.emit('hooks:builtIn:ready'); sails.log.verbose('Built-in hooks are ready.'); return cb(); }); } /** * Load built-in hook definitions from `sails.config.hooks` * and put them back into `hooks` (probably `sails.hooks`) * * @api private */ function loadHookDefinitions(hooks, cb) { // Mix in user-configured hook definitions _.extend(hooks, sails.config.hooks); // Make sure these changes to the hooks object get applied // to sails.config.hooks to keep logic consistent // (I think we can get away w/o this, but leaving as a stub) // sails.config.hooks = hooks; // If user configured `loadHooks`, only include those. if (sails.config.loadHooks) { if (!_.isArray(sails.config.loadHooks)) { return cb('Invalid `loadHooks` config. ' + 'Please specify an array of string hook names.\n' + 'You specified ::' + util.inspect(sails.config.loadHooks)); } _.each(hooks, function(def, hookName) { if (!_.contains(sails.config.loadHooks, hookName)) { hooks[hookName] = false; } }); sails.log.verbose('Deliberate partial load-- will only initialize hooks ::', sails.config.loadHooks); } return cb(); } /** * Returns function which is fired when Sails is ready to go * * @api private */ function ready__(cb) { return function(err) { if (err) { return cb && cb(err); } sails.log.verbose('All hooks were loaded successfully.'); // If userconfig hook is turned off, still load globals. if (sails.config.hooks && sails.config.hooks.userconfig === false || (sails.config.loadHooks && sails.config.loadHooks.indexOf('userconfig') == -1)) { sails.exposeGlobals(); } cb && cb(null, sails); }; } };