- /**
- * The list of <a href="#method_joinRoom"><code>joinRoom()</code> method</a> socket connection failure states.
- * @attribute SOCKET_ERROR
- * @param {Number} CONNECTION_FAILED <small>Value <code>0</code></small>
- * The value of the failure state when <code>joinRoom()</code> socket connection failed to establish with
- * the Signaling server at the first attempt.
- * @param {Number} RECONNECTION_FAILED <small>Value <code>-1</code></small>
- * The value of the failure state when <code>joinRoom()</code> socket connection failed to establish
- * the Signaling server after the first attempt.
- * @param {Number} CONNECTION_ABORTED <small>Value <code>-2</code></small>
- * The value of the failure state when <code>joinRoom()</code> socket connection will not attempt
- * to reconnect after the failure of the first attempt in <code>CONNECTION_FAILED</code> as there
- * are no more ports or transports to attempt for reconnection.
- * @param {Number} RECONNECTION_ABORTED <small>Value <code>-3</code></small>
- * The value of the failure state when <code>joinRoom()</code> socket connection will not attempt
- * to reconnect after the failure of several attempts in <code>RECONNECTION_FAILED</code> as there
- * are no more ports or transports to attempt for reconnection.
- * @param {Number} RECONNECTION_ATTEMPT <small>Value <code>-4</code></small>
- * The value of the failure state when <code>joinRoom()</code> socket connection is attempting
- * to reconnect with a new port or transport after the failure of attempts in
- * <code>CONNECTION_FAILED</code> or <code>RECONNECTED_FAILED</code>.
- * @type JSON
- * @readOnly
- * @for Skylink
- * @since 0.5.6
- */
- Skylink.prototype.SOCKET_ERROR = {
- CONNECTION_FAILED: 0,
- RECONNECTION_FAILED: -1,
- CONNECTION_ABORTED: -2,
- RECONNECTION_ABORTED: -3,
- RECONNECTION_ATTEMPT: -4
- };
-
- /**
- * The list of <a href="#method_joinRoom"><code>joinRoom()</code> method</a> socket connection reconnection states.
- * @attribute SOCKET_FALLBACK
- * @param {String} NON_FALLBACK <small>Value <code>"nonfallback"</code></small>
- * The value of the reconnection state when <code>joinRoom()</code> socket connection is at its initial state
- * without transitioning to any new socket port or transports yet.
- * @param {String} FALLBACK_PORT <small>Value <code>"fallbackPortNonSSL"</code></small>
- * The value of the reconnection state when <code>joinRoom()</code> socket connection is reconnecting with
- * another new HTTP port using WebSocket transports to attempt to establish connection with Signaling server.
- * @param {String} FALLBACK_PORT_SSL <small>Value <code>"fallbackPortSSL"</code></small>
- * The value of the reconnection state when <code>joinRoom()</code> socket connection is reconnecting with
- * another new HTTPS port using WebSocket transports to attempt to establish connection with Signaling server.
- * @param {String} LONG_POLLING <small>Value <code>"fallbackLongPollingNonSSL"</code></small>
- * The value of the reconnection state when <code>joinRoom()</code> socket connection is reconnecting with
- * another new HTTP port using Polling transports to attempt to establish connection with Signaling server.
- * @param {String} LONG_POLLING <small>Value <code>"fallbackLongPollingSSL"</code></small>
- * The value of the reconnection state when <code>joinRoom()</code> socket connection is reconnecting with
- * another new HTTPS port using Polling transports to attempt to establish connection with Signaling server.
- * @type JSON
- * @readOnly
- * @for Skylink
- * @since 0.5.6
- */
- Skylink.prototype.SOCKET_FALLBACK = {
- NON_FALLBACK: 'nonfallback',
- FALLBACK_PORT: 'fallbackPortNonSSL',
- FALLBACK_SSL_PORT: 'fallbackPortSSL',
- LONG_POLLING: 'fallbackLongPollingNonSSL',
- LONG_POLLING_SSL: 'fallbackLongPollingSSL'
- };
-
- /**
- * Stores the current socket connection information.
- * @attribute _socketSession
- * @type JSON
- * @private
- * @for Skylink
- * @since 0.6.13
- */
- Skylink.prototype._socketSession = {};
-
- /**
- * Stores the queued socket messages.
- * This is to prevent too many sent over less than a second interval that might cause dropped messages
- * or jams to the Signaling connection.
- * @attribute _socketMessageQueue
- * @type Array
- * @private
- * @for Skylink
- * @since 0.5.8
- */
- Skylink.prototype._socketMessageQueue = [];
-
- /**
- * Stores the <code>setTimeout</code> to sent queued socket messages.
- * @attribute _socketMessageTimeout
- * @type Object
- * @private
- * @for Skylink
- * @since 0.5.8
- */
- Skylink.prototype._socketMessageTimeout = null;
-
- /**
- * Stores the list of socket ports to use to connect to the Signaling.
- * These ports are defined by default which is commonly used currently by the Signaling.
- * Should re-evaluate this sometime.
- * @attribute _socketPorts
- * @param {Array} http: The list of HTTP socket ports.
- * @param {Array} https: The list of HTTPS socket ports.
- * @type JSON
- * @private
- * @for Skylink
- * @since 0.5.8
- */
- Skylink.prototype._socketPorts = {
- 'http:': [80, 3000],
- 'https:': [443, 3443]
- };
-
- /**
- * Stores the flag that indicates if socket connection to the Signaling has opened.
- * @attribute _channelOpen
- * @type Boolean
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._channelOpen = false;
-
- /**
- * Stores the Signaling server url.
- * @attribute _signalingServer
- * @type String
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._signalingServer = null;
-
- /**
- * Stores the Signaling server protocol.
- * @attribute _signalingServerProtocol
- * @type String
- * @private
- * @for Skylink
- * @since 0.5.4
- */
- Skylink.prototype._signalingServerProtocol = window.location.protocol;
-
- /**
- * Stores the Signaling server port.
- * @attribute _signalingServerPort
- * @type Number
- * @private
- * @for Skylink
- * @since 0.5.4
- */
- Skylink.prototype._signalingServerPort = null;
-
- /**
- * Stores the Signaling socket connection object.
- * @attribute _socket
- * @type io
- * @private
- * @for Skylink
- * @since 0.1.0
- */
- Skylink.prototype._socket = null;
-
- /**
- * Stores the socket connection timeout when establishing connection to the Signaling.
- * @attribute _socketTimeout
- * @type Number
- * @private
- * @for Skylink
- * @since 0.5.4
- */
- Skylink.prototype._socketTimeout = 0;
-
- /**
- * Stores the flag that indicates if XDomainRequest is used for IE 8/9.
- * @attribute _socketUseXDR
- * @type Boolean
- * @private
- * @for Skylink
- * @since 0.5.4
- */
- Skylink.prototype._socketUseXDR = false;
-
- /**
- * Function that sends a socket message over the socket connection to the Signaling.
- * @method _sendChannelMessage
- * @private
- * @for Skylink
- * @since 0.5.8
- */
- Skylink.prototype._sendChannelMessage = function(message) {
- var self = this;
- var interval = 1000;
- var throughput = 16;
-
- if (!self._channelOpen) {
- return;
- }
-
- var messageString = JSON.stringify(message);
-
- var sendLater = function(){
- if (self._socketMessageQueue.length > 0){
-
- if (self._socketMessageQueue.length<throughput){
-
- log.debug([(message.target ? message.target : 'server'), null, null,
- 'Sending delayed message' + ((!message.target) ? 's' : '') + ' ->'], {
- type: self._SIG_MESSAGE_TYPE.GROUP,
- lists: self._socketMessageQueue.slice(0,self._socketMessageQueue.length),
- mid: self._user.sid,
- rid: self._room.id
- });
-
- // fix for self._socket undefined errors in firefox
- if (self._socket) {
- self._socket.send({
- type: self._SIG_MESSAGE_TYPE.GROUP,
- lists: self._socketMessageQueue.splice(0,self._socketMessageQueue.length),
- mid: self._user.sid,
- rid: self._room.id
- });
- } else {
- log.error([(message.target ? message.target : 'server'), null, null,
- 'Dropping delayed message' + ((!message.target) ? 's' : '') +
- ' as socket object is no longer defined ->'], {
- type: self._SIG_MESSAGE_TYPE.GROUP,
- lists: self._socketMessageQueue.slice(0,self._socketMessageQueue.length),
- mid: self._user.sid,
- rid: self._room.id
- });
- }
-
- clearTimeout(self._socketMessageTimeout);
- self._socketMessageTimeout = null;
-
- }
- else{
-
- log.debug([(message.target ? message.target : 'server'), null, null,
- 'Sending delayed message' + ((!message.target) ? 's' : '') + ' ->'], {
- type: self._SIG_MESSAGE_TYPE.GROUP,
- lists: self._socketMessageQueue.slice(0,throughput),
- mid: self._user.sid,
- rid: self._room.id
- });
-
- // fix for self._socket undefined errors in firefox
- if (self._socket) {
- self._socket.send({
- type: self._SIG_MESSAGE_TYPE.GROUP,
- lists: self._socketMessageQueue.splice(0,throughput),
- mid: self._user.sid,
- rid: self._room.id
- });
- } else {
- log.error([(message.target ? message.target : 'server'), null, null,
- 'Dropping delayed message' + ((!message.target) ? 's' : '') +
- ' as socket object is no longer defined ->'], {
- type: self._SIG_MESSAGE_TYPE.GROUP,
- lists: self._socketMessageQueue.slice(0,throughput),
- mid: self._user.sid,
- rid: self._room.id
- });
- }
-
- clearTimeout(self._socketMessageTimeout);
- self._socketMessageTimeout = null;
- self._socketMessageTimeout = setTimeout(sendLater,interval);
-
- }
- self._timestamp.now = Date.now() || function() { return +new Date(); };
- }
- };
-
- //Delay when messages are sent too rapidly
- if ((Date.now() || function() { return +new Date(); }) - self._timestamp.now < interval &&
- self._groupMessageList.indexOf(message.type) > -1) {
-
- log.warn([(message.target ? message.target : 'server'), null, null,
- 'Messages fired too rapidly. Delaying.'], {
- interval: 1000,
- throughput: 16,
- message: message
- });
-
- self._socketMessageQueue.push(messageString);
-
- if (!self._socketMessageTimeout){
- self._socketMessageTimeout = setTimeout(sendLater,
- interval - ((Date.now() || function() { return +new Date(); })-self._timestamp.now));
- }
- return;
- }
-
- log.debug([(message.target ? message.target : 'server'), null, null,
- 'Sending to peer' + ((!message.target) ? 's' : '') + ' ->'], message);
-
- //Normal case when messages are sent not so rapidly
- self._socket.send(messageString);
- self._timestamp.now = Date.now() || function() { return +new Date(); };
-
- };
-
- /**
- * Function that creates and opens a socket connection to the Signaling.
- * @method _createSocket
- * @private
- * @for Skylink
- * @since 0.5.10
- */
- Skylink.prototype._createSocket = function (type) {
- var self = this;
-
- var options = {
- forceNew: true,
- //'sync disconnect on unload' : true,
- reconnection: false
- };
-
- var ports = self._socketPorts[self._signalingServerProtocol];
-
- var connectionType = null;
-
- // just beginning
- if (self._signalingServerPort === null) {
- self._signalingServerPort = ports[0];
- connectionType = self.SOCKET_FALLBACK.NON_FALLBACK;
-
- // reached the end of the last port for the protocol type
- } else if ( ports.indexOf(self._signalingServerPort) === ports.length - 1 ) {
-
- // re-refresh to long-polling port
- if (type === 'WebSocket') {
- type = 'Polling';
- self._signalingServerPort = ports[0];
-
- } else if (type === 'Polling') {
- options.reconnection = true;
- options.reconnectionAttempts = 4;
- options.reconectionDelayMax = 1000;
- }
-
- // move to the next port
- } else {
- self._signalingServerPort = ports[ ports.indexOf(self._signalingServerPort) + 1 ];
- }
-
- var url = self._signalingServerProtocol + '//' + self._signalingServer + ':' + self._signalingServerPort;
- //'http://ec2-52-8-93-170.us-west-1.compute.amazonaws.com:6001';
-
- if (type === 'WebSocket') {
- options.transports = ['websocket'];
- } else if (type === 'Polling') {
- options.transports = ['xhr-polling', 'jsonp-polling', 'polling'];
- }
-
- // if socket instance already exists, exit
- if (self._socket) {
- self._socket.removeAllListeners('connect_error');
- self._socket.removeAllListeners('reconnect_attempt');
- self._socket.removeAllListeners('reconnect_error');
- self._socket.removeAllListeners('reconnect_failed');
- self._socket.removeAllListeners('connect');
- self._socket.removeAllListeners('reconnect');
- self._socket.removeAllListeners('error');
- self._socket.removeAllListeners('disconnect');
- self._socket.removeAllListeners('message');
- self._socket.disconnect();
- self._socket = null;
- }
-
- self._channelOpen = false;
-
- log.log('Opening channel with signaling server url:', {
- url: url,
- useXDR: self._socketUseXDR,
- options: options
- });
-
- self._socketSession = {
- type: type,
- options: options,
- url: url
- };
-
- self._socket = io.connect(url, options);
-
- if (connectionType === null) {
- connectionType = self._signalingServerProtocol === 'http:' ?
- (type === 'Polling' ? self.SOCKET_FALLBACK.LONG_POLLING :
- self.SOCKET_FALLBACK.FALLBACK_PORT) :
- (type === 'Polling' ? self.SOCKET_FALLBACK.LONG_POLLING_SSL :
- self.SOCKET_FALLBACK.FALLBACK_SSL_PORT);
- }
-
- self._socket.on('connect_error', function (error) {
- self._channelOpen = false;
-
- self._trigger('socketError', self.SOCKET_ERROR.CONNECTION_FAILED,
- error, connectionType);
-
- self._trigger('channelRetry', connectionType, 1);
-
- if (options.reconnection === false) {
- self._createSocket(type);
- }
- });
-
- self._socket.on('reconnect_attempt', function (attempt) {
- self._channelOpen = false;
- self._trigger('socketError', self.SOCKET_ERROR.RECONNECTION_ATTEMPT,
- attempt, connectionType);
-
- self._trigger('channelRetry', connectionType, attempt);
- });
-
- self._socket.on('reconnect_error', function (error) {
- self._channelOpen = false;
- self._trigger('socketError', self.SOCKET_ERROR.RECONNECTION_FAILED,
- error, connectionType);
- });
-
- self._socket.on('reconnect_failed', function (error) {
- self._channelOpen = false;
- self._trigger('socketError', self.SOCKET_ERROR.RECONNECTION_ABORTED,
- error, connectionType);
- });
-
- self._socket.on('connect', function () {
- if (!self._channelOpen) {
- self._channelOpen = true;
- self._trigger('channelOpen');
- log.log([null, 'Socket', null, 'Channel opened']);
- }
- });
-
- self._socket.on('reconnect', function () {
- if (!self._channelOpen) {
- self._channelOpen = true;
- self._trigger('channelOpen');
- log.log([null, 'Socket', null, 'Channel opened']);
- }
- });
-
- self._socket.on('error', function(error) {
- self._channelOpen = false;
- self._trigger('channelError', error);
- log.error([null, 'Socket', null, 'Exception occurred:'], error);
- });
-
- self._socket.on('disconnect', function() {
- self._channelOpen = false;
- self._trigger('channelClose');
- log.log([null, 'Socket', null, 'Channel closed']);
-
- if (self._inRoom) {
- self.leaveRoom(false);
- self._trigger('sessionDisconnect', self._user.sid, self.getPeerInfo());
- }
- });
-
- self._socket.on('message', function(message) {
- log.log([null, 'Socket', null, 'Received message']);
- self._processSigMessage(message);
- });
- };
-
- /**
- * Function that starts the socket connection to the Signaling.
- * This starts creating the socket connection and called at first not when requiring to fallback.
- * @method _openChannel
- * @private
- * @for Skylink
- * @since 0.5.5
- */
- Skylink.prototype._openChannel = function() {
- var self = this;
- if (self._channelOpen) {
- log.error([null, 'Socket', null, 'Unable to instantiate a new channel connection ' +
- 'as there is already an ongoing channel connection']);
- return;
- }
-
- if (self._readyState !== self.READY_STATE_CHANGE.COMPLETED) {
- log.error([null, 'Socket', null, 'Unable to instantiate a new channel connection ' +
- 'as readyState is not ready']);
- return;
- }
-
- // set if forceSSL
- if (self._forceSSL) {
- self._signalingServerProtocol = 'https:';
- } else {
- self._signalingServerProtocol = window.location.protocol;
- }
-
- var socketType = 'WebSocket';
-
- // For IE < 9 that doesn't support WebSocket
- if (!window.WebSocket) {
- socketType = 'Polling';
- }
-
- self._signalingServerPort = null;
-
- // Begin with a websocket connection
- self._createSocket(socketType);
- };
-
- /**
- * Function that stops the socket connection to the Signaling.
- * @method _closeChannel
- * @private
- * @for Skylink
- * @since 0.5.5
- */
- Skylink.prototype._closeChannel = function() {
- if (!this._channelOpen) {
- return;
- }
- if (this._socket) {
- this._socket.removeAllListeners('connect_error');
- this._socket.removeAllListeners('reconnect_attempt');
- this._socket.removeAllListeners('reconnect_error');
- this._socket.removeAllListeners('reconnect_failed');
- this._socket.removeAllListeners('connect');
- this._socket.removeAllListeners('reconnect');
- this._socket.removeAllListeners('error');
- this._socket.removeAllListeners('disconnect');
- this._socket.removeAllListeners('message');
- this._socket.disconnect();
- this._socket = null;
- }
- this._channelOpen = false;
- this._trigger('channelClose');
- };
-