App-SocialCalc-Multiplayer
view release on metacpan or search on metacpan
socialcalc/third-party/Socket.IO-node/support/socket.io-client/lib/socket.js view on Meta::CPAN
/**
* socket.io-node-client
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
(function(){
var io = this.io;
/**
* Create a new `Socket.IO client` which can establish a persisted
* connection with a Socket.IO enabled server.
*
* Options:
* - `secure` Use secure connections, defaulting to false.
* - `document` Reference to the document object to retrieve and set cookies, defaulting to document.
* - `port` The port where the Socket.IO server listening on, defaulting to location.port.
* - `resource` The path or namespace on the server where the Socket.IO requests are intercepted, defaulting to 'socket.io'.
* - `transports` A ordered list with the available transports, defaulting to all transports.
* - `transportOption` A {Object} containing the options for each transport. The key of the object should reflect
* name of the transport and the value a {Object} with the options.
* - `connectTimeout` The duration in milliseconds that a transport has to establish a working connection, defaulting to 5000.
* - `tryTransportsOnConnectTimeout` Should we attempt other transport methods when the connectTimeout occurs, defaulting to true.
* - `reconnect` Should reconnection happen automatically, defaulting to true.
* - `reconnectionDelay` The delay in milliseconds before we attempt to establish a working connection. This value will
* increase automatically using a exponential back off algorithm. Defaulting to 500.
* - `maxReconnectionAttempts` Number of attempts we should make before seizing the reconnect operation, defaulting to 10.
* - `rememberTransport` Should the successfully connected transport be remembered in a cookie, defaulting to true.
*
* Examples:
*
* Create client with the default settings.
*
* var socket = new io.Socket();
* socket.connect();
* socket.on('message', function(msg){
* console.log('Received message: ' + msg );
* });
* socket.on('connect', function(){
* socket.send('Hello from client');
* });
*
* Create a connection with server on a different port and host.
*
* var socket = new io.Socket('http://example.com',{port:1337});
*
* @constructor
* @exports Socket as io.Socket
* @param {String} [host] The host where the Socket.IO server is located, it defaults to the host that runs the page.
* @param {Objects} [options] The options that will configure the Socket.IO client.
* @property {String} host The supplied host arguments or the host that page runs.
* @property {Object} options The passed options combined with the defaults.
* @property {Boolean} connected Whether the socket is connected or not.
* @property {Boolean} connecting Whether the socket is connecting or not.
* @property {Boolean} reconnecting Whether the socket is reconnecting or not.
* @property {Object} transport The selected transport instance.
* @api public
*/
var Socket = io.Socket = function(host, options){
this.host = host || document.domain;
this.options = {
secure: false,
document: document,
port: document.location.port || 80,
resource: 'socket.io',
transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'],
transportOptions: {
'xhr-polling': {
timeout: 25000 // based on polling duration default
},
'jsonp-polling': {
timeout: 25000
}
},
connectTimeout: 5000,
tryTransportsOnConnectTimeout: true,
reconnect: true,
reconnectionDelay: 500,
maxReconnectionAttempts: 10,
rememberTransport: true
};
io.util.merge(this.options, options);
this.connected = false;
this.connecting = false;
this.reconnecting = false;
this.events = {};
this.transport = this.getTransport();
if (!this.transport && 'console' in window) console.error('No transport available');
};
/**
* Find an available transport based on the options supplied in the constructor. For example if the
* `rememberTransport` option was set we will only connect with the previous successfully connected transport.
* The supplied transports can be overruled if the `override` argument is supplied.
*
* Example:
*
* Override the existing transports.
*
* var socket = new io.Socket();
* socket.getTransport(['jsonp-polling','websocket']);
* // returns the json-polling transport because it's availabe in all browsers.
*
* @param {Array} [override] A ordered list with transports that should be used instead of the options.transports.
* @returns {Null|Transport} The available transport.
* @api private
*/
Socket.prototype.getTransport = function(override){
var transports = override || this.options.transports, match;
if (this.options.rememberTransport && !override){
match = this.options.document.cookie.match('(?:^|;)\\s*socketio=([^;]*)');
if (match){
this.rememberedTransport = true;
transports = [decodeURIComponent(match[1])];
}
}
for (var i = 0, transport; transport = transports[i]; i++){
if (io.Transport[transport]
&& io.Transport[transport].check()
&& (!this.isXDomain() || io.Transport[transport].xdomainCheck())){
return new io.Transport[transport](this, this.options.transportOptions[transport] || {});
}
}
return null;
};
/**
* Establish a new connection with the Socket.IO server. This is done using the selected transport by the
* getTransport method. If the `connectTimeout` and the `tryTransportsOnConnectTimeout` options are set
* the client will keep trying to connect to the server using a different transports when the timeout occurs.
*
* Example:
*
* Create a Socket.IO client with a connect callback (We assume we have the WebSocket transport avaliable).
*
* var socket = new io.Socket();
* socket.connect(function(transport){
* console.log("Connected to server using the " + socket.transport.type + " transport.");
* });
* // => "Connected to server using the WebSocket transport."
*
* @param {Function} [fn] Callback.
* @returns {io.Socket}
* @api public
*/
Socket.prototype.connect = function(fn){
if (this.transport && !this.connected){
if (this.connecting) this.disconnect(true);
this.connecting = true;
this.emit('connecting', [this.transport.type]);
this.transport.connect();
if (this.options.connectTimeout){
var self = this;
this.connectTimeoutTimer = setTimeout(function(){
if (!self.connected){
self.disconnect(true);
if (self.options.tryTransportsOnConnectTimeout && !self.rememberedTransport){
if(!self.remainingTransports) self.remainingTransports = self.options.transports.slice(0);
var transports = self.remainingTransports;
while(transports.length > 0 && transports.splice(0,1)[0] != self.transport.type){}
if(transports.length){
self.transport = self.getTransport(transports);
self.connect();
}
}
if(!self.remainingTransports || self.remainingTransports.length == 0) self.emit('connect_failed');
}
if(self.remainingTransports && self.remainingTransports.length == 0) delete self.remainingTransports;
}, this.options.connectTimeout);
}
}
if (fn && typeof fn == 'function') this.once('connect',fn);
return this;
};
/**
* Sends the data to the Socket.IO server. If there isn't a connection to the server
* the data will be forwarded to the queue.
*
* @param {Mixed} data The data that needs to be send to the Socket.IO server.
* @returns {io.Socket}
* @api public
*/
Socket.prototype.send = function(data){
if (!this.transport || !this.transport.connected) return this.queue(data);
this.transport.send(data);
return this;
};
/**
* Disconnect the established connect.
*
* @param {Boolean} [soft] A soft disconnect will keep the reconnect settings enabled.
* @returns {io.Socket}
* @api public
*/
Socket.prototype.disconnect = function(soft){
if (this.connectTimeoutTimer) clearTimeout(this.connectTimeoutTimer);
if (!soft) this.options.reconnect = false;
this.transport.disconnect();
return this;
};
/**
* Adds a new eventListener for the given event.
*
* Example:
*
* var socket = new io.Socket();
* socket.on("connect", function(transport){
* console.log("Connected to server using the " + socket.transport.type + " transport.");
* });
* // => "Connected to server using the WebSocket transport."
*
* @param {String} name The name of the event.
* @param {Function} fn The function that is called once the event is emitted.
* @returns {io.Socket}
* @api public
*/
Socket.prototype.on = function(name, fn){
if (!(name in this.events)) this.events[name] = [];
this.events[name].push(fn);
return this;
};
/**
* Adds a one time listener, the listener will be removed after the event is emitted.
*
* Example:
*
* var socket = new io.Socket();
* socket.once("custom:event", function(){
* console.log("I should only log once.");
* });
* socket.emit("custom:event");
* socket.emit("custom:event");
* // => "I should only log once."
*
* @param {String} name The name of the event.
* @param {Function} fn The function that is called once the event is emitted.
* @returns {io.Socket}
* @api public
*/
Socket.prototype.once = function(name, fn){
var self = this
, once = function(){
self.removeEvent(name, once);
fn.apply(self, arguments);
};
once.ref = fn;
self.on(name, once);
return this;
};
/**
* Emit a event to all listeners.
*
* Example:
socialcalc/third-party/Socket.IO-node/support/socket.io-client/lib/socket.js view on Meta::CPAN
* by calling this method so we can set the `connected` and `connecting` properties and emit
* the connection event.
*
* @api private
*/
Socket.prototype.onConnect = function(){
this.connected = true;
this.connecting = false;
this.doQueue();
if (this.options.rememberTransport) this.options.document.cookie = 'socketio=' + encodeURIComponent(this.transport.type);
this.emit('connect');
};
/**
* When the transport receives new messages from the Socket.IO server it notifies us by calling
* this method with the decoded `data` it received.
*
* @param data The message from the Socket.IO server.
* @api private
*/
Socket.prototype.onMessage = function(data){
this.emit('message', [data]);
};
/**
* When the transport is disconnected from the Socket.IO server it notifies us by calling
* this method. If we where connected and the `reconnect` is set we will attempt to reconnect.
*
* @api private
*/
Socket.prototype.onDisconnect = function(){
var wasConnected = this.connected;
this.connected = false;
this.connecting = false;
this.queueStack = [];
if (wasConnected){
this.emit('disconnect');
if (this.options.reconnect && !this.reconnecting) this.onReconnect();
}
};
/**
* The reconnection is done using an exponential back off algorithm to prevent
* the server from being flooded with connection requests. When the transport
* is disconnected we wait until the `reconnectionDelay` finishes. We multiply
* the `reconnectionDelay` (if the previous `reconnectionDelay` was 500 it will
* be updated to 1000 and than 2000>4000>8000>16000 etc.) and tell the current
* transport to connect again. When we run out of `reconnectionAttempts` we will
* do one final attempt and loop over all enabled transport methods to see if
* other transports might work. If everything fails we emit the `reconnect_failed`
* event.
*
* @api private
*/
Socket.prototype.onReconnect = function(){
this.reconnecting = true;
this.reconnectionAttempts = 0;
this.reconnectionDelay = this.options.reconnectionDelay;
var self = this
, tryTransportsOnConnectTimeout = this.options.tryTransportsOnConnectTimeout
, rememberTransport = this.options.rememberTransport;
function reset(){
if(self.connected) self.emit('reconnect',[self.transport.type,self.reconnectionAttempts]);
self.removeEvent('connect_failed', maybeReconnect).removeEvent('connect', maybeReconnect);
self.reconnecting = false;
delete self.reconnectionAttempts;
delete self.reconnectionDelay;
delete self.reconnectionTimer;
delete self.redoTransports;
self.options.tryTransportsOnConnectTimeout = tryTransportsOnConnectTimeout;
self.options.rememberTransport = rememberTransport;
return;
};
function maybeReconnect(){
if (!self.reconnecting) return;
if (!self.connected){
if (self.connecting && self.reconnecting) return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
if (self.reconnectionAttempts++ >= self.options.maxReconnectionAttempts){
if (!self.redoTransports){
self.on('connect_failed', maybeReconnect);
self.options.tryTransportsOnConnectTimeout = true;
self.transport = self.getTransport(self.options.transports); // override with all enabled transports
self.redoTransports = true;
self.connect();
} else {
self.emit('reconnect_failed');
reset();
}
} else {
self.reconnectionDelay *= 2; // exponential back off
self.connect();
self.emit('reconnecting', [self.reconnectionDelay,self.reconnectionAttempts]);
self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
}
} else {
reset();
}
};
this.options.tryTransportsOnConnectTimeout = false;
this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
this.on('connect', maybeReconnect);
};
/**
* API compatiblity
*/
Socket.prototype.fire = Socket.prototype.emit;
Socket.prototype.addListener = Socket.prototype.addEvent = Socket.prototype.addEventListener = Socket.prototype.on;
Socket.prototype.removeListener = Socket.prototype.removeEventListener = Socket.prototype.removeEvent;
})();
( run in 1.331 second using v1.01-cache-2.11-cpan-39bf76dae61 )