src/proxybinder.js
/*jslint indent:2, node:true */
var PromiseCompat = require('es6-promise').Promise;
var ApiInterface = require('./proxy/apiInterface');
var EventInterface = require('./proxy/eventInterface');
var Consumer = require('./consumer');
var Provider = require('./provider');
/**
* A Proxy Binder manages the external interface, and creates one of
* the different types of objects exposed by freedom either as a global
* within a worker / module context, or returned by an external call to
* create a freedom runtime.
* @Class ProxyBinder
* @param {Manager} manager The manager for the active runtime.
*/
var ProxyBinder = function (manager) {
'use strict';
this.manager = manager;
};
/**
* Create a proxy for a freedom port, and return it once loaded.
* @method getExternal
* @param {Port} port The port for the proxy to communicate with.
* @param {String} name The name of the proxy.
* @param {Object} [definition] The definition of the API to expose.
* @param {String} definition.name The name of the API.
* @param {Object} definition.definition The definition of the API.
* @param {Boolean} definition.provides Whether this is a consumer or provider.
* @returns {Promise} A promise for the active proxy interface.
*/
ProxyBinder.prototype.getExternal = function (port, name, definition) {
'use strict';
var proxy, api;
return new PromiseCompat(function (resolve, reject) {
if (definition) {
api = definition.name;
if (definition.provides) {
proxy = new Provider(definition.definition, this.manager.debug);
} else {
proxy = new Consumer(ApiInterface.bind({},
definition.definition),
this.manager.debug);
}
} else {
proxy = new Consumer(EventInterface, this.manager.debug);
}
proxy.once('start', function () {
var iface = proxy.getProxyInterface();
if (api) {
iface.api = api;
}
resolve({
port: proxy,
external: iface
});
});
this.manager.createLink(port, name, proxy);
}.bind(this));
};
/**
* Bind the default proxy for a freedom port.
* @method bindDefault
* @param {Port} port The port for the proxy to communicate with.
* @param {Api} api The API loader with API definitions.
* @param {Object} manifest The manifest of the module to expose.
* @param {Boolean} internal Whether the interface is for inside the module.
* @returns {Promise} A promise for a proxy interface.
* @private
*/
ProxyBinder.prototype.bindDefault = function (port, api, manifest, internal) {
'use strict';
var metadata = {
name: manifest.name,
icon: manifest.icon,
description: manifest.description
}, def;
if (manifest['default']) {
def = api.get(manifest['default']);
if (!def && manifest.api && manifest.api[manifest['default']]) {
def = {
name: manifest['default'],
definition: manifest.api[manifest['default']]
};
}
if (internal && manifest.provides &&
manifest.provides.indexOf(manifest['default']) !== false) {
def.provides = true;
} else if (internal) {
api.debug.warn("default API not provided, " +
"are you missing a provides key in your manifest?");
}
}
return this.getExternal(port, 'default', def).then(
function (metadata, info) {
info.external.manifest = metadata;
return info;
}.bind(this, metadata)
);
};
/**
* Get the definition for a proxy given a requested API and the manifest of
* the module.
* @method getAPI
* @param {Object} manifest The manifest for the proxy.
* @param {Api} apiProvider The registry of known APIs.
* @param {String} api The Requested API.
* @returns {Object} definition The definition to use for calls to getExternal.
*/
ProxyBinder.prototype.getAPI = function (manifest, apiProvider, api) {
'use strict';
if (manifest.api && manifest.api[api]) {
return {
name: api,
definition: manifest.api[api]
};
} else if (manifest['default']) {
var def = apiProvider.get(manifest['default']);
if (!def && manifest.api && manifest.api[manifest['default']]) {
return {
name: manifest['default'],
definition: manifest.api[manifest['default']]
};
}
return def;
} else {
return false;
}
};
module.exports = ProxyBinder;