webp2p
Version:
The server-less signaling channel for WebRTC
205 lines (154 loc) • 5.04 kB
JavaScript
var inherits = require('inherits');
var Manager = require('./Manager');
var errors = require('../errors');
var Connector_PubNub = require('../connectors/PubNub');
var Connector_xRTML = require('../connectors/xRTML');
/**
* Manage the handshake connectors using several servers
*
* @constructor
* @param {String} json_uri URI of the handshake servers configuration.
*/
function HandshakeManager(rpcBuilder, handshake_servers)
{
Manager.call(this, rpcBuilder);
var self = this;
var handshakeConnectorConstructors = {};
this.registerConnectorConstructor = function(type, constructor)
{
handshakeConnectorConstructors[type] = constructor
};
// Default handshake connectors
this.registerConnectorConstructor('PubNub', Connector_PubNub);
this.registerConnectorConstructor('xRTML', Connector_xRTML);
function createConnector(config)
{
var type = config.type;
var config_init = config.config_init;
var config_mess = config.config_mess;
var max_connections = config.max_connections;
// Check if connector constructor is from a valid handshake server
var connectorConstructor = handshakeConnectorConstructors[type];
if(!connectorConstructor)
throw Error("Invalid handshake server type '" + type + "'");
var connector = new connectorConstructor(config_init, config_mess, max_connections);
self._initConnector(connector);
connector.on('open', function()
{
// Notify our presence to the other peers
connector.send(rpcBuilder.encode('presence'));
});
var _messageUnpacked = connector._messageUnpacked;
connector._messageUnpacked = function(message)
{
if(message.method == 'presence')
{
if(connector.shouldConnect())
self.emit("presence", message.params.from, connector);
}
else
_messageUnpacked.call(connector, message);
};
return connector;
};
var configs = [];
var index = 0;
var configs_infinity = [];
/**
* Get a random handshake connector or test for the next one
* @param {Object} configuration Handshake servers configuration.
*/
function handshake()
{
if(!configs.length)
throw Error('No handshake servers defined')
for(; index < configs.length; index++)
{
var connector = createConnector(configs[index]);
connector.on('close', function()
{
// Handshake connector has been closed, try to get an alternative one
index++;
handshake();
});
// Connector successfully created
return;
};
// All configured handshake servers has been consumed
// Get ready to start again from beginning of handshake servers list
index = 0;
};
this.addConfigs_byObject = function(config)
{
// Check if connector constructor is from a valid handshake server
var connectorConstructor = handshakeConnectorConstructors[config.type];
if(!connectorConstructor)
return console.error("Invalid handshake server config: ", config);
if(connectorConstructor.prototype.max_connections == Number.POSITIVE_INFINITY
&& !config.max_connections)
{
configs_infinity.push(config)
// Start handshaking
createConnector(config);
}
else
{
configs.push(config);
// Start handshaking
if(self.status == 'disconnected')
handshake();
}
};
// Add handshake servers configuration
if(handshake_servers)
this.addConfigs(handshake_servers)
};
inherits(HandshakeManager, Manager);
HandshakeManager.prototype.addConfigs = function(configuration)
{
if(typeof configuration == 'string')
return this.addConfigs_byUri(configuration);
if(configuration instanceof Array)
return this.addConfigs_byArray(configuration);
this.addConfigs_byObject(configuration);
};
HandshakeManager.prototype.addConfigs_byArray = function(configuration)
{
for(var i=0, config; config=configuration[i]; i++)
this.addConfigs_byObject(config);
};
HandshakeManager.prototype.addConfigs_byUri = function(json_uri)
{
var self = this;
function dispatchError(error)
{
self.emit('error', error);
};
// Request the handshake servers configuration file
var http_request = new XMLHttpRequest();
http_request.open('GET', json_uri);
http_request.onload = function(event)
{
if(this.status == 200)
{
var configuration = JSON.parse(http_request.response);
// We got some config entries
if(configuration.length)
self.addConfigs_byArray(configuration)
// Config was empty
else
dispatchError(errors.ERROR_REQUEST_EMPTY)
}
// Request returned an error
else
dispatchError(errors.ERROR_REQUEST_FAILURE)
};
// Connection error
http_request.onerror = function(event)
{
dispatchError(navigator.onLine ? errors.ERROR_NETWORK_UNKNOWN
: errors.ERROR_NETWORK_OFFLINE)
};
http_request.send();
};
module.exports = HandshakeManager;