App-SocialCalc-Multiplayer
view release on metacpan or search on metacpan
socialcalc/third-party/Socket.IO-node/lib/socket.io/client.js view on Meta::CPAN
var urlparse = require('url').parse
, OutgoingMessage = require('http').OutgoingMessage
, Stream = require('net').Stream
, options = require('./utils').options
, encode = require('./utils').encode
, decode = require('./utils').decode
, merge = require('./utils').merge
, util = require(process.binding('natives').util ? 'util' : 'sys');
var Client = module.exports = function(listener, req, res, options, head){
process.EventEmitter.call(this);
this.listener = listener;
this.options(merge({
timeout: 8000,
heartbeatInterval: 10000,
closeTimeout: 0
}, this.getOptions ? this.getOptions() : {}), options);
this.connections = 0;
this._open = false;
this._heartbeats = 0;
this.connected = false;
this.upgradeHead = head;
this._onConnect(req, res);
};
util.inherits(Client, process.EventEmitter);
Client.prototype.send = function(message){
if (!this._open || !(this.connection.readyState === 'open' || this.connection.readyState === 'writeOnly')){
return this._queue(message);
}
this._write(encode(message));
return this;
};
Client.prototype.broadcast = function(message){
if (!('sessionId' in this)) return this;
this.listener.broadcast(message, this.sessionId);
return this;
};
Client.prototype._onMessage = function(data){
var messages = decode(data);
if (messages === false) return this.listener.options.log('Bad message received from client ' + this.sessionId);
for (var i = 0, l = messages.length, frame; i < l; i++){
frame = messages[i].substr(0, 3);
switch (frame){
case '~h~':
return this._onHeartbeat(messages[i].substr(3));
case '~j~':
try {
messages[i] = JSON.parse(messages[i].substr(3));
} catch(e) {
messages[i] = {};
}
break;
}
this.emit('message', messages[i]);
this.listener._onClientMessage(messages[i], this);
}
};
Client.prototype._onConnect = function(req, res){
var self = this
, attachConnection = !this.connection;
this.request = req;
this.response = res;
this.connection = req.connection;
if(!attachConnection) attachConnection = !attachConnection && this.connection.eventsAttached === undefined;
this.connection.eventsAttached = true;
if (attachConnection){
function destroyConnection(){
self._onClose();
self.connection && self.connection.destroy()
};
this.connection.addListener('end', destroyConnection);
this.connection.addListener('timeout', destroyConnection);
this.connection.addListener('error', destroyConnection);
}
if (req){
function destroyRequest(){
req.destroy && req.destroy();
};
req.addListener('error', destroyRequest);
req.addListener('timeout', destroyRequest);
if (res){
function destroyResponse(){
res.destroy && res.destroy();
}
res.addListener('error', destroyResponse);
res.addListener('timeout', destroyResponse);
}
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
}
};
Client.prototype._payload = function(){
var payload = [];
this.connections++;
this.connected = true;
this._open = true;
if (!this.handshaked){
this._generateSessionId();
payload.push(this.sessionId);
this.handshaked = true;
}
payload = payload.concat(this._writeQueue || []);
this._writeQueue = [];
if (payload.length) this._write(encode(payload));
if (this.connections === 1) this.listener._onClientConnect(this);
if (this.options.timeout) this._heartbeat();
};
Client.prototype._heartbeat = function(){
var self = this;
this._heartbeatInterval = setTimeout(function(){
self.send('~h~' + ++self._heartbeats);
self._heartbeatTimeout = setTimeout(function(){
self._onClose();
}, self.options.timeout);
}, self.options.heartbeatInterval);
};
Client.prototype._onHeartbeat = function(h){
if (h == this._heartbeats){
clearTimeout(this._heartbeatTimeout);
this._heartbeat();
}
};
Client.prototype._onClose = function(skipDisconnect){
if (!this._open) return this;
var self = this;
if (this._heartbeatInterval) clearTimeout(this._heartbeatInterval);
if (this._heartbeatTimeout) clearTimeout(this._heartbeatTimeout);
this._open = false;
this.request = null;
this.response = null;
if (skipDisconnect !== false){
if (this.handshaked){
this._disconnectTimeout = setTimeout(function(){
self._onDisconnect();
}, this.options.closeTimeout);
} else
this._onDisconnect();
}
};
Client.prototype._onDisconnect = function(){
if (this._open) this._onClose(true);
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
this._writeQueue = [];
this.connected = false;
if (this.handshaked){
this.emit('disconnect');
this.listener._onClientDisconnect(this);
this.handshaked = false;
}
};
Client.prototype._queue = function(message){
this._writeQueue = this._writeQueue || [];
this._writeQueue.push(message);
return this;
};
Client.prototype._generateSessionId = function(){
this.sessionId = Math.random().toString().substr(2);
return this;
};
Client.prototype._verifyOrigin = function(origin){
var origins = this.listener.options.origins;
if (origins.indexOf('*:*') !== -1) {
return true;
}
if (origin) {
try {
var parts = urlparse(origin);
return origins.indexOf(parts.host + ':' + parts.port) !== -1 ||
origins.indexOf(parts.host + ':*') !== -1 ||
origins.indexOf('*:' + parts.port) !== -1;
} catch (ex) {}
}
return false;
};
for (var i in options) Client.prototype[i] = options[i];
( run in 0.484 second using v1.01-cache-2.11-cpan-39bf76dae61 )