src/entry.js
/*jslint indent:2,node:true */
var PromiseCompat = require('es6-promise').Promise;
var Api = require('./api');
var Debug = require('./debug');
var Hub = require('./hub');
var Manager = require('./manager');
var Policy = require('./policy');
var ProxyBinder = require('./proxybinder');
var Resource = require('./resource');
var util = require('./util');
var Bundle = require('./bundle');
var freedomGlobal;
var getGlobal = function () {
'use strict';
// Node.js
if (typeof global !== 'undefined' && global.prototype === undefined) {
freedomGlobal = global;
// Browsers
} else {
setTimeout(function () {
freedomGlobal = this;
}, 0);
}
};
getGlobal();
/**
* Create a new freedom context.
* @param {Object} context Information about the local context.
* @see {util/workerEntry.js}
* @param {String} manifest The manifest to load.
* @param {Object} config Configuration keys set by the user.
* @returns {Promise} A promise for the module defined in the manifest.
*/
var setup = function (context, manifest, config) {
'use strict';
var debug = new Debug(),
hub = new Hub(debug),
resource = new Resource(debug),
api = new Api(debug),
manager = new Manager(hub, resource, api),
binder = new ProxyBinder(manager),
policy,
site_cfg = {
'debug': 'log',
'manifest': manifest,
'moduleContext': (!context || typeof (context.isModule) === "undefined") ?
util.isModuleContext() :
context.isModule
},
link,
Port,
cleanup = function () {
api.cleanup();
manager.destroy();
};
if (config) {
util.mixin(site_cfg, config, true);
}
site_cfg.global = freedomGlobal;
if (context) {
util.mixin(site_cfg, context, true);
}
// Register user-supplied extensions.
// For example the 'core.oauth' provider defines a register function,
// which enables site_cfg.oauth to be registered with it.
context.providers.forEach(function (provider) {
var name;
if (provider.name.indexOf('core.') === 0 &&
typeof provider.register === 'function') {
name = provider.name.substr(5);
// Invert priority and prefer user config over local context for these.
if (config && config[name]) {
provider.register(config[name]);
} else if (site_cfg[name]) {
provider.register(site_cfg[name]);
} else {
provider.register(undefined);
}
}
});
Bundle.register(context.providers, api);
resource.register(context.resolvers || []);
return new PromiseCompat(function (resolve, reject) {
if (site_cfg.moduleContext) {
Port = site_cfg.portType;
link = new Port('Outbound', resource);
manager.setup(link);
// Delay debug messages until delegation to the parent context is setup.
manager.once('delegate', manager.setup.bind(manager, debug));
} else {
manager.setup(debug);
policy = new Policy(manager, resource, site_cfg);
// Define how to load a root module.
var fallbackLogger, getIface;
fallbackLogger = function (message) {
api.getCore('core.console', {
config: site_cfg
}).then(function (provider) {
var logger = new provider.inst();
debug.setLogger(logger);
if (message) {
debug.error(message);
}
});
};
getIface = function (manifest) {
return resource.get(site_cfg.location, manifest).then(
function (canonical_manifest) {
return policy.get([], canonical_manifest);
}
).then(function (instance) {
manager.setup(instance);
return binder.bindDefault(instance, api, instance.manifest);
});
};
// Load appropriate Logger.
if (site_cfg.logger) {
getIface(site_cfg.logger).then(function (iface) {
if (iface.external.api !== 'console') {
fallbackLogger("Unwilling to use logger with unknown API:",
iface.external.api);
} else {
debug.setLogger(iface.external());
}
}, fallbackLogger);
} else {
fallbackLogger();
}
// Load root module.
getIface(site_cfg.manifest).then(function (iface) {
iface.port.once('close', cleanup);
return iface.external;
}, function (err) {
debug.error('Failed to retrieve manifest: ' + err);
throw err;
}).then(resolve, reject);
}
hub.emit('config', site_cfg);
});
};
module.exports = setup;