Socket
Socket
Sign inDemoInstall

socket.io

Package Overview
Dependencies
Maintainers
0
Versions
157
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

socket.io - npm Package Compare versions

Comparing version 0.7.2 to 0.7.3

lib/stores/redis.js

15

History.md
0.7.3 / 2011-06-30
==================
* Exposed handshake data to clients.
* Refactored dispatcher interface.
* Changed; Moved id generation method into the manager.
* Added sub-namespace authorization. [3rd-Eden]
* Changed; normalized SocketNamespace local eventing [dvv]
* Changed; Use packet.reason or default to 'packet' [3rd-Eden]
* Changed console.error to console.log.
* Fixed; bind both servers at the same time do that the test never times out.
* Added 304 support.
* Removed `Transport#name` for abstract interface.
* Changed; lazily require http and https module only when needed. [3rd-Eden]
0.7.2 / 2011-06-22

@@ -3,0 +18,0 @@ ==================

2

lib/logger.js

@@ -77,3 +77,3 @@

console.error.apply(
console.log.apply(
console

@@ -80,0 +80,0 @@ , [this.colors

@@ -82,4 +82,8 @@

, 'browser client etag': false
, 'browser client handler': false
, 'client store expiration': 15
};
this.initStore();
// reset listeners

@@ -221,2 +225,261 @@ this.oldListeners = server.listeners('request');

/**
* Initializes everything related to the message dispatcher.
*
* @api private
*/
Manager.prototype.initStore = function () {
this.handshaken = {};
this.connected = {};
this.open = {};
this.closed = {};
this.closedA = [];
this.rooms = {};
this.roomClients = {};
var self = this;
this.store.subscribe('handshake', function (id, data) {
self.onHandshake(id, data);
});
this.store.subscribe('connect', function (id) {
self.onConnect(id);
});
this.store.subscribe('open', function (id) {
self.onOpen(id);
});
this.store.subscribe('join', function (id, room) {
self.onJoin(id, room);
});
this.store.subscribe('leave', function (id, room) {
self.onLeave(id, room);
});
this.store.subscribe('close', function (id) {
self.onClose(id);
});
this.store.subscribe('dispatch', function (room, packet, volatile, exceptions) {
self.onDispatch(room, packet, volatile, exceptions);
});
this.store.subscribe('disconnect', function (id) {
self.onDisconnect(id);
});
};
/**
* Called when a client handshakes.
*
* @param text
*/
Manager.prototype.onHandshake = function (id, data) {
this.handshaken[id] = data;
};
/**
* Called when a client connects (ie: transport first opens)
*
* @api private
*/
Manager.prototype.onConnect = function (id) {
this.connected[id] = true;
};
/**
* Called when a client opens a request in a different node.
*
* @api private
*/
Manager.prototype.onOpen = function (id) {
this.open[id] = true;
// if we were buffering messages for the client, clear them
if (this.closed[id]) {
var self = this;
this.closedA.splice(this.closedA.indexOf(id), 1);
this.store.unsubscribe('dispatch:' + id, function () {
delete self.closed[id];
});
}
// clear the current transport
if (this.transports[id]) {
this.transports[id].discard();
this.transports[id] = null;
}
};
/**
* Called when a message is sent to a namespace and/or room.
*
* @api private
*/
Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) {
// go through the users who have pending buffers
for (var i = 0, l = this.closedA.length; i < l; i++) {
if (this.roomClients[this.closedA[i]][room]) {
if (!~exceptions.indexOf(this.closedA[i])) {
this.closed[this.closedA[i]].push(packet);
}
}
}
// go through room clients
if (this.rooms[room]) {
for (var i = 0, l = this.rooms[room].length; i < l; i++) {
var id = this.rooms[room][i];
if (!~exceptions.indexOf(id)) {
if (this.transports[id] && this.transports[id].open) {
this.transports[id].onDispatch(packet, volatile);
} else if (!volatile) {
this.onClientDispatch(id, packet);
}
}
}
}
};
/**
* Called when a client joins a nsp / room.
*
* @api private
*/
Manager.prototype.onJoin = function (id, name) {
if (!this.roomClients[id]) {
this.roomClients[id] = [];
}
if (!this.rooms[name]) {
this.rooms[name] = [];
}
this.rooms[name].push(id);
this.roomClients[id][name] = true;
};
/**
* Called when a client leaves a nsp / room.
*
* @param private
*/
Manager.prototype.onLeave = function (id, room) {
if (this.rooms[room]) {
this.rooms[room].splice(this.rooms[room].indexOf(id), 1);
delete this.roomClients[id][room];
}
};
/**
* Called when a client closes a request in different node.
*
* @api private
*/
Manager.prototype.onClose = function (id) {
this.closed[id] = [];
this.closedA.push(id);
var self = this;
this.store.subscribe('dispatch:' + id, function (packet, volatile) {
if (!volatile) {
self.onClientDispatch(id, packet);
}
});
};
/**
* Dispatches a message for a closed client.
*
* @api private
*/
Manager.prototype.onClientDispatch = function (id, packet) {
this.closed[id].push(packet);
};
/**
* Receives a message for a client.
*
* @api private
*/
Manager.prototype.onClientMessage = function (id, packet) {
if (this.namespaces[packet.endpoint]) {
this.namespaces[packet.endpoint].handlePacket(id, packet);
}
};
/**
* Fired when a client disconnects (not triggered).
*
* @api private
*/
Manager.prototype.onClientDisconnect = function (id, reason) {
for (var name in this.namespaces) {
if (this.roomClients[id][name]) {
this.namespaces[name].handleDisconnect(id, reason);
}
}
};
/**
* Called when a client disconnects.
*
* @param text
*/
Manager.prototype.onDisconnect = function (id, local) {
delete this.handshaken[id];
if (this.open[id]) {
delete this.open[id];
}
if (this.connected[id]) {
delete this.connected[id];
}
if (this.transports[id]) {
this.transports[id].discard();
delete this.transports[id];
}
if (this.closed[id]) {
delete this.closed[id];
this.closedA.splice(this.closedA.indexOf(id), 1);
}
if (this.roomClients[id]) {
for (var room in this.roomClients[id]) {
this.rooms[room].splice(this.rooms.indexOf(id), 1);
}
}
this.store.destroyClient(id, this.get('client store expiration'));
this.store.unsubscribe('dispatch:' + id);
if (local) {
this.store.unsubscribe('message:' + id);
this.store.unsubscribe('disconnect:' + id);
}
};
/**
* Handles an HTTP request.

@@ -307,8 +570,11 @@ *

var socket = req.socket
, newTransport = false
, store = this.store
, self = this;
if (undefined != data.query.disconnect) {
self.log.debug('handling disconnection url');
self.store.disconnect(data.id, true);
if (this.transports[data.id] && this.transports[data.id].open) {
this.transports[data.id].onForcedDisconnect();
} else {
this.store.publish('disconnect-force:' + data.id);
}
return;

@@ -323,39 +589,45 @@ }

var transport = new transports[data.transport](this, data);
transport.pause();
transport.request = req;
var transport = new transports[data.transport](this, data, req);
if (!transport.open) {
this.log.debug('transport not writeable, not subscribing');
return;
}
if (this.handshaken[data.id]) {
if (transport.open) {
if (this.closed[data.id] && this.closed[data.id].length) {
transport.payload(this.closed[data.id]);
this.closed[data.id] = [];
}
this.store.isHandshaken(data.id, function (err, handshaken) {
if (err || !handshaken) {
if (err) console.error(err);
transport.error('client not handshaken', 'reconnect');
return;
this.onOpen(data.id);
this.store.publish('open', data.id);
this.transports[data.id] = transport;
}
self.store.client(data.id).count(function (err, count) {
transport.resume();
if (!this.connected[data.id]) {
this.onConnect(data.id);
this.store.publish('connect', data.id);
if (count == 1) {
// initialize the socket for all namespaces
for (var i in self.namespaces) {
var socket = self.namespaces[i].socket(data.id, true);
// initialize the socket for all namespaces
for (var i in this.namespaces) {
var socket = this.namespaces[i].socket(data.id, true);
// echo back connect packet and fire connection event
if (i === '') {
self.namespaces[i].handlePacket(data.id, { type: 'connect' });
}
// echo back connect packet and fire connection event
if (i === '') {
this.namespaces[i].handlePacket(data.id, { type: 'connect' });
}
}
// handle packets for the client (all namespaces)
self.store.on('message:' + data.id, function (packet) {
self.handlePacket(data.id, packet);
});
}
});
});
this.store.subscribe('message:' + data.id, function (packet) {
self.onClientMessage(data.id, packet);
});
this.store.subscribe('disconnect:' + data.id, function (reason) {
self.onClientDisconnect(data.id, reason);
});
}
} else {
if (transport.open) {
transport.error('client not handshaken', 'reconnect');
}
transport.discard();
}
};

@@ -370,17 +642,20 @@

Manager.static = {
cache:{}
, paths: {
'/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf'
, '/static/flashsocket/WebSocketMainInsecure.swf': client.dist + '/WebSocketMainInsecure.swf'
, '/socket.io.js': client.dist + '/socket.io.js'
, '/socket.io.js.min': client.dist + '/socket.io.min.js'
}
, contentType: {
'js': 'application/javascript'
, 'swf': 'application/x-shockwave-flash'
}
, encoding:{
'js': 'utf8'
, 'swf': 'binary'
}
cache: {}
, paths: {
'/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf'
, '/static/flashsocket/WebSocketMainInsecure.swf':
client.dist + '/WebSocketMainInsecure.swf'
, '/socket.io.js': client.dist + '/socket.io.js'
, '/socket.io.js.min': client.dist + '/socket.io.min.js'
}
, mime: {
'js': {
contentType: 'application/javascript'
, encoding: 'utf8'
}
, 'swf': {
contentType: 'application/x-shockwave-flash'
, encoding: 'binary'
}
}
};

@@ -397,3 +672,4 @@

, extension = data.path.split('.').pop()
, file = data.path + (this.enabled('browser client minification') && extension == 'js' ? '.min' : '')
, file = data.path + (this.enabled('browser client minification')
&& extension == 'js' ? '.min' : '')
, location = static.paths[file]

@@ -404,5 +680,23 @@ , cache = static.cache[file];

/**
* Writes a response, safely
*
* @api private
*/
function write (status, headers, content, encoding) {
try {
res.writeHead(status, headers || null);
res.end(content || '', encoding || null);
} catch (e) {}
}
function serve () {
var headers = {
'Content-Type': static.contentType[extension]
if (req.headers['if-none-match'] === cache.Etag) {
return write(304);
}
var mime = static.mime[extension]
, headers = {
'Content-Type': mime.contentType
, 'Content-Length': cache.length

@@ -415,5 +709,3 @@ };

res.writeHead(200, headers);
res.end(cache.content, cache.encoding);
write(200, headers, cache.content, mime.encoding);
self.log.debug('served static ' + data.path);

@@ -427,6 +719,4 @@ }

if (err) {
res.writeHead(500);
res.end('Error serving socket.io client.');
self.log.warn('Can\'t cache socket.io client, ' + err.message);
write(500, null, 'Error serving static ' + data.path);
self.log.warn('Can\'t cache '+ data.path +', ' + err.message);
return;

@@ -439,3 +729,2 @@ }

, Etag: client.version
, encoding: static.encoding[extension]
};

@@ -451,2 +740,13 @@

/**
* Generates a session id.
*
* @api private
*/
Manager.prototype.generateId = function () {
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
};
/**
* Handles a handshake request.

@@ -480,30 +780,32 @@ *

this.authorize(data, function (err, authorized) {
var handshakeData = this.handshakeData(data);
this.authorize(handshakeData, function (err, authorized, newData) {
if (err) return error(err);
self.log.info('handshake ' + (authorized ? 'authorized' : 'unauthorized'));
if (authorized) {
self.store.handshake(data, function (err, id) {
if (err) return error(err);
var id = self.generateId()
, hs = [
id
, self.get('heartbeat timeout') || ''
, self.get('close timeout') || ''
, self.transports(data).join(',')
].join(':');
var hs = [
id
, self.get('heartbeat timeout') || ''
, self.get('close timeout') || ''
, self.transports(data).join(',')
].join(':');
if (data.query.jsonp) {
hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';
res.writeHead(200, { 'Content-Type': 'application/javascript' });
} else {
res.writeHead(200);
}
if (data.query.jsonp) {
hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';
res.writeHead(200, { 'Content-Type': 'application/javascript' });
} else {
res.writeHead(200);
}
res.end(hs);
res.end(hs);
self.log.info('handshaken', id);
});
self.onHandshake(id, newData || handshakeData);
self.store.publish('handshake', id, newData || handshakeData);
self.log.info('handshake authorized', id);
} else {
writeErr(403, 'handshake unauthorized');
self.log.info('handshake unauthorized');
}

@@ -514,2 +816,22 @@ })

/**
* Gets normalized handshake data
*
* @api private
*/
Manager.prototype.handshakeData = function (data) {
var connectionAddress = null;
if (data.request.connection.address) {
connectionAddress = data.request.connection.address();
}
return {
headers: data.headers
, address: connectionAddress
, time: (new Date).toString()
, xdomain: !!data.request.headers.origin
, secure: data.request.connection.secure
};
};
/**
* Verifies the origin of a request.

@@ -516,0 +838,0 @@ *

@@ -1,2 +0,1 @@

/**

@@ -27,2 +26,3 @@ * Module dependencies.

this.sockets = {};
this.auth = false;
this.setFlags();

@@ -38,2 +38,29 @@ };

/**
* Copies emit since we override it
*
* @api private
*/
SocketNamespace.prototype.$emit = EventEmitter.prototype.emit;
/**
* Retrieves all clients as Socket instances as an array.
*
* @api public
*/
SocketNamespace.prototype.clients = function (room) {
var room = this.name + (room !== undefined ?
(this.name !== '' ? '/' : '') + room : '');
if (!this.manager.rooms[room]) {
return [];
}
return this.manager.rooms[room].map(function (id) {
return this.socket(id);
}, this);
};
/**
* Access logger interface.

@@ -131,17 +158,5 @@ *

store.clients(this.flags.endpoint, function (clients) {
clients.forEach(function (id) {
if (~exceptions.indexOf(id)) {
log.debug('ignoring packet to ', id);
return;
}
this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions);
this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions);
if (volatile) {
store.publish('volatile:' + id, packet);
} else {
store.client(id).publish(packet);
}
});
});
this.setFlags();

@@ -173,3 +188,3 @@

if (name == 'connection' || name == 'newListener') {
return EventEmitter.prototype.emit.apply(this, arguments);
return this.$emit.apply(this, arguments);
}

@@ -200,2 +215,49 @@

/**
* Sets authorization for this namespace
*
* @api public
*/
SocketNamespace.prototype.authorization = function (fn) {
this.auth = fn;
return this;
};
/**
* Called when a socket disconnects entirely.
*
* @api private
*/
SocketNamespace.prototype.handleDisconnect = function (sid, reason) {
if (this.sockets[sid] && this.sockets[sid].readable) {
this.sockets[sid].onDisconnect(reason);
}
};
/**
* Performs authentication.
*
* @param Object client request data
* @api private
*/
SocketNamespace.prototype.authorize = function (data, fn) {
if (this.auth) {
var self = this;
this.auth.call(this, data, function (err, authorized) {
self.log.debug('client ' +
(authorized ? '' : 'un') + 'authorized for ' + self.name);
fn(err, authorized);
});
} else {
this.log.debug('client authorized for ' + this.name);
fn(null, true);
}
return this;
};
/**
* Handles a packet.

@@ -220,9 +282,38 @@ *

function error (err) {
self.log.warn('handshake error ' + err + ' for ' + self.name);
socket.packet({ type: 'error', reason: err });
};
function connect () {
self.manager.onJoin(sessid, self.name);
self.store.publish('join', sessid, self.name);
// packet echo
socket.packet({ type: 'connect' });
// emit connection event
self.emit('connection', socket);
};
switch (packet.type) {
case 'connect':
this.store.join(sessid, this.name, function () {
// packet echo
socket.packet({ type: 'connect' });
self.emit('connection', socket);
});
if (packet.endpoint == '') {
connect();
} else {
var manager = this.manager
, handshakeData = manager.handshaken[sessid];
this.authorize(handshakeData, function (err, authorized, newData) {
if (err) return error(err);
if (authorized) {
manager.onHandshake(sessid, newData || handshakeData);
self.store.publish('handshake', sessid, newData || handshakeData);
connect();
} else {
error('unauthorized');
}
});
}
break;

@@ -248,3 +339,6 @@

case 'disconnect':
socket.emit('disconnect');
this.manager.onLeave(sessid, this.name);
this.store.publish('leave', sessid, this.name);
socket.emit('disconnect', packet.reason || 'packet');
break;

@@ -251,0 +345,0 @@

@@ -12,5 +12,3 @@

var http = require('http')
, https = require('https')
, client = require('socket.io-client');
var client = require('socket.io-client');

@@ -21,3 +19,3 @@ /**

exports.version = '0.7.2';
exports.version = '0.7.3';

@@ -58,5 +56,5 @@ /**

if (options && options.key)
server = https.createServer(options, server);
server = require('https').createServer(options);
else
server = http.createServer();
server = require('http').createServer();

@@ -109,2 +107,18 @@ // default response

/**
* Memory Store constructor.
*
* @api public
*/
exports.MemoryStore = require('./stores/memory');
/**
* Redis Store constructor.
*
* @api public
*/
exports.RedisStore = require('./stores/redis');
/**
* Parser.

@@ -111,0 +125,0 @@ *

@@ -56,10 +56,4 @@

this.setFlags();
if (readable) {
var self = this;
this.store.once('disconnect:' + id, function (reason) {
self.onDisconnect(reason);
});
}
this.readable = readable;
this.store = this.manager.store.client(this.id);
};

@@ -74,3 +68,3 @@

/**
* Accessor shortcut for the store.
* Accessor shortcut for the handshake data
*

@@ -80,4 +74,4 @@ * @api private

Socket.prototype.__defineGetter__('store', function () {
return this.manager.store;
Socket.prototype.__defineGetter__('handshake', function () {
return this.manager.handshaken[this.id];
});

@@ -173,4 +167,13 @@

Socket.prototype.join = function (name, fn) {
var nsp = this.namespace.name;
this.store.join(this.id, (nsp === '' ? '' : (nsp + '/')) + name, fn);
var nsp = this.namespace.name
, name = (nsp === '' ? '' : (nsp + '/')) + name;
this.manager.onJoin(this.id, name);
this.manager.store.publish('join', this.id, name);
if (fn) {
this.log.warn('Client#join callback is deprecated');
fn();
}
return this;

@@ -186,4 +189,13 @@ };

Socket.prototype.leave = function (name, fn) {
var nsp = this.namespace.name;
this.store.leave(this.id, (nsp === '' ? '' : (nsp + '/')) + name, fn);
var nsp = this.namespace.name
, name = (nsp === '' ? '' : (nsp + '/')) + name;
this.manager.onLeave(this.id, name);
this.manager.store.publish('leave', this.id, name);
if (fn) {
this.log.warn('Client#leave callback is deprecated');
fn();
}
return this;

@@ -206,7 +218,3 @@ };

if (this.flags.volatile) {
this.store.publish('volatile:' + this.id, packet);
} else {
this.store.client(this.id).publish(packet);
}
this.dispatch(packet, this.flags.volatile);
}

@@ -220,2 +228,20 @@

/**
* Dispatches a packet
*
* @api private
*/
Socket.prototype.dispatch = function (packet, volatile) {
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
this.manager.transports[this.id].onDispatch(packet, volatile);
} else {
if (!volatile) {
this.manager.onClientDispatch(this.id, packet, volatile);
}
this.manager.store.publish('dispatch:' + this.id, packet, volatile);
}
};
/**
* Stores data for the client.

@@ -227,3 +253,3 @@ *

Socket.prototype.set = function (key, value, fn) {
this.store.client(this.id).set(key, value, fn);
this.store.set(key, value, fn);
return this;

@@ -239,3 +265,3 @@ };

Socket.prototype.get = function (key, fn) {
this.store.client(this.id).get(key, fn);
this.store.get(key, fn);
return this;

@@ -245,2 +271,24 @@ };

/**
* Checks data for the client
*
* @api public
*/
Socket.prototype.has = function (key, fn) {
this.store.has(key, fn);
return this;
};
/**
* Deletes data for the client
*
* @api public
*/
Socket.prototype.del = function (key, fn) {
this.store.del(key, fn);
return this;
};
/**
* Kicks client

@@ -254,3 +302,14 @@ *

this.log.info('booting client');
this.store.disconnect(this.id, true);
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
this.manager.transports[this.id].onForcedDisconnect();
} else {
if (this.manager.open[this.id]) {
// if the connection is open in a different node
this.manager.store.publish('disconnect-force:' + this.id);
} else {
this.manager.onClientDisconnect(this.id);
this.manager.store.publish('disconnect:' + this.id);
}
}
}

@@ -257,0 +316,0 @@

@@ -9,12 +9,12 @@

/**
* Module dependencies.
* Expose the constructor.
*/
var EventEmitter = process.EventEmitter;
exports = module.exports = Store;
/**
* Expose the constructor.
* Module dependencies.
*/
exports = module.exports = Store;
var EventEmitter = process.EventEmitter;

@@ -27,6 +27,9 @@ /**

function Store () {};
function Store (options) {
this.options = options;
this.clients = {};
};
/**
* Inherits from EventEmitter
* Inherit from EventEmitter.
*/

@@ -37,12 +40,54 @@

/**
* Log accessor.
* Initializes a client store
*
* @param {String} id
* @api public
*/
Store.prototype.__defineGetter__('log', function () {
return this.manager.log;
});
Store.prototype.client = function (id) {
if (!this.clients[id]) {
this.clients[id] = new (this.constructor.Client)(this, id);
}
return this.clients[id];
};
/**
* Destroys a client
*
* @api {String} sid
* @param {Number} number of seconds to expire client data
* @api private
*/
Store.prototype.destroyClient = function (id, expiration) {
if (this.clients[id]) {
this.clients[id].destroy(expiration);
delete this.clients[id];
}
return this;
};
/**
* Destroys the store
*
* @param {Number} number of seconds to expire client data
* @api private
*/
Store.prototype.destroy = function (clientExpiration) {
var keys = Object.keys(this.clients)
, count = keys.length;
for (var i = 0, l = count; i < l; i++) {
this.destroyClient(keys[i], clientExpiration);
}
this.clients = {};
return this;
};
/**
* Client.

@@ -56,4 +101,2 @@ *

this.id = id;
this.buffer = [];
this.dict = {};
};

@@ -13,3 +13,3 @@

var crypto = require('crypto')
, Store = require('../store')
, Store = require('../store');

@@ -30,5 +30,3 @@ /**

function Memory (opts) {
this.handshaken = [];
this.clientsMap = {};
this.rooms = {};
Store.call(this, opts);
};

@@ -43,88 +41,19 @@

/**
* Handshake a client.
* Publishes a message.
*
* @param {Object} client request object
* @param {Function} callback
* @api public
*/
Memory.prototype.handshake = function (data, fn) {
var id = this.generateId();
this.handshaken.push(id);
fn(null, id);
return this;
};
/**
* Checks if a client is handshaken.
*
* @api public
*/
Memory.prototype.isHandshaken = function (id, fn) {
fn(null, ~this.handshaken.indexOf(id));
return this;
};
/**
* Generates a random id.
*
* @api private
*/
Memory.prototype.generateId = function () {
var rand = String(Math.random() * Math.random() * Date.now());
return crypto.createHash('md5').update(rand).digest('hex');
};
Memory.prototype.publish = function () { };
/**
* Retrieves a client store instance.
* Subscribes to a channel
*
* @api public
*/
Memory.prototype.client = function (id) {
if (!this.clientsMap[id]) {
this.clientsMap[id] = new Memory.Client(this, id);
this.log.debug('initializing client store for', id);
}
return this.clientsMap[id];
};
/**
* Called when a client disconnects.
*
* @api public
*/
Memory.prototype.disconnect = function (id, force, reason) {
if (~this.handshaken.indexOf(id)) {
this.log.debug('destroying dispatcher for', id);
this.handshaken.splice(this.handshaken.indexOf(id), 1);
this.clientsMap[id].destroy();
this.clientsMap[id] = null;
if (force)
this.publish('disconnect-force:' + id, reason);
this.publish('disconnect:' + id, reason);
}
return this;
};
/**
* Relays a heartbeat message.
*
* @api private
*/
Memory.prototype.heartbeat = function (id) {
return this.publish('heartbeat-clear:' + id);
};
Memory.prototype.subscribe = function () { };
/**
* Relays a packet
* Unsubscribes
*

@@ -134,100 +63,5 @@ * @api private

Memory.prototype.message = function (id, packet) {
return this.publish('message:' + id, packet);
};
Memory.prototype.unsubscribe = function () { };
/**
* Returns client ids in a particular room
*
* @api public
*/
Memory.prototype.clients = function (room, fn) {
if ('function' == typeof room) {
fn = room;
room = '';
}
fn && fn(this.rooms[room] || []);
};
/**
* Joins a user to a room
*
* @api private
*/
Memory.prototype.join = function (sid, room, fn) {
if (!this.rooms[room]) {
this.rooms[room] = [];
}
this.client(sid).rooms[room] = this.rooms[room].length;
this.rooms[room].push(sid);
fn && fn();
return this;
};
/**
* Removes a user from a room
*
* @api private
*/
Memory.prototype.leave = function (sid, room, fn) {
if (!this.rooms[room] || this.client(sid).rooms[room] === undefined) {
return this;
}
var i = this.client(sid).rooms[room];
this.rooms[room][i] = null;
delete this.client(sid).rooms[room];
fn && fn();
return this;
};
/**
* Simple publish
*
* @api public
*/
Memory.prototype.publish = function (ev, data, fn) {
if ('function' == typeof data) {
fn = data;
data = undefined;
}
this.emit(ev, data);
if (fn) fn();
return this;
};
/**
* Simple subscribe
*
* @api public
*/
Memory.prototype.subscribe = function (chn, fn) {
this.on(chn, fn);
return this;
};
/**
* Simple unsubscribe
*
* @api public
*/
Memory.prototype.unsubscribe = function (chn) {
this.removeAllListeners(chn);
};
/**
* Client constructor

@@ -240,5 +74,3 @@ *

Store.Client.apply(this, arguments);
this.reqs = 0;
this.paused = true;
this.rooms = {};
this.data = {};
};

@@ -253,3 +85,3 @@

/**
* Counts transport requests.
* Gets a key
*

@@ -259,4 +91,4 @@ * @api public

Client.prototype.count = function (fn) {
fn(null, ++this.reqs);
Client.prototype.get = function (key, fn) {
fn(null, this.data[key] === undefined ? null : this.data[key]);
return this;

@@ -266,3 +98,3 @@ };

/**
* Sets up queue consumption
* Sets a key
*

@@ -272,11 +104,5 @@ * @api public

Client.prototype.consume = function (fn) {
this.consumer = fn;
this.paused = false;
if (this.buffer.length) {
fn(this.buffer, null);
this.buffer = [];
}
Client.prototype.set = function (key, value, fn) {
this.data[key] = value;
fn && fn(null);
return this;

@@ -286,20 +112,13 @@ };

/**
* Publishes a message to be sent to the client.
* Has a key
*
* @String encoded message
* @api public
*/
Client.prototype.publish = function (msg) {
if (this.paused) {
this.buffer.push(msg);
} else {
this.consumer(null, msg);
}
return this;
Client.prototype.has = function (key, fn) {
fn(null, key in this.data);
};
/**
* Pauses the stream.
* Deletes a key
*

@@ -309,4 +128,5 @@ * @api public

Client.prototype.pause = function () {
this.paused = true;
Client.prototype.del = function (key, fn) {
delete this.data[key];
fn && fn(null);
return this;

@@ -318,41 +138,18 @@ };

*
* @api public
* @param {Number} number of seconds to expire data
* @api private
*/
Client.prototype.destroy = function () {
this.buffer = null;
};
Client.prototype.destroy = function (expiration) {
if ('number' != typeof expiration) {
this.data = {};
} else {
var self = this;
/**
* Gets a key
*
* @api public
*/
setTimeout(function () {
self.data = {};
}, expiration * 1000);
}
Client.prototype.get = function (key, fn) {
fn(null, this.dict[key]);
return this;
};
/**
* Sets a key
*
* @api public
*/
Client.prototype.set = function (key, value, fn) {
this.dict[key] = value;
fn && fn(null);
return this;
};
/**
* Emits a message incoming from client.
*
* @api private
*/
Client.prototype.onMessage = function (msg) {
this.store.emit('message:' + id, msg);
};

@@ -26,20 +26,12 @@

function Transport (mng, data) {
function Transport (mng, data, req) {
this.manager = mng;
this.id = data.id;
this.paused = true;
this.disconnected = false;
this.drained = true;
this.buffer = [];
this.handleRequest(req);
};
/**
* Sets the corresponding request object.
*/
Transport.prototype.__defineSetter__('request', function (req) {
this.log.debug('setting request', req.method, req.url);
this.handleRequest(req);
});
/**
* Access the logger.

@@ -71,2 +63,3 @@ *

Transport.prototype.handleRequest = function (req) {
this.log.debug('setting request', req.method, req.url);
this.req = req;

@@ -78,20 +71,4 @@

this.drained = true;
this.setHeartbeatInterval();
this.log.debug('publishing that', this.id, 'connected');
var self = this;
this.store.publish('open:' + this.id, function () {
self.store.once('open:' + self.id, function () {
self.log.info('request for existing session connection change');
self.close();
self.clearTimeouts();
self.clearHandlers();
});
if (!self.paused) {
self.subscribe();
}
});
this.setHandlers();

@@ -119,13 +96,14 @@ this.onSocketConnect();

this.store.once('disconnect-force:' + this.id, function () {
self.onForcedDisconnect();
// we need to do this in a pub/sub way since the client can POST the message
// over a different socket (ie: different Transport instance)
this.store.subscribe('heartbeat-clear:' + this.id, function () {
self.onHeartbeatClear();
});
this.store.on('heartbeat-clear:' + this.id, function () {
self.clearHeartbeatTimeout();
self.setHeartbeatInterval();
this.store.subscribe('disconnect-force:' + this.id, function () {
self.onForcedDisconnect();
});
this.store.on('volatile:' + this.id, function (packet) {
self.writeVolatile(packet);
this.store.subscribe('dispatch:' + this.id, function (packet, volatile) {
self.onDispatch(packet, volatile);
});

@@ -155,3 +133,3 @@

this.store.unsubscribe('heartbeat-clear:' + this.id);
this.store.unsubscribe('volatile:' + this.id);
this.store.unsubscribe('dispatch:' + this.id);

@@ -171,6 +149,3 @@ this.socket.removeListener('end', this.bound.end);

Transport.prototype.onSocketEnd = function () {
// we check that the socket wasn't swapped
// we don't want to sever a connection that's not active, since we don't kill
// inactive sockets that the browser might reuse for other purposes
this.end(false, 'socket end');
this.end('socket end');
};

@@ -185,3 +160,3 @@

Transport.prototype.onSocketClose = function (error) {
this.end(false, error ? 'socket error' : 'socket close');
this.end(error ? 'socket error' : 'socket close');
};

@@ -215,2 +190,13 @@

/**
* Called upon receiving a heartbeat packet.
*
* @api private
*/
Transport.prototype.onHeartbeatClear = function () {
this.clearHeartbeatTimeout();
this.setHeartbeatInterval();
};
/**
* Called upon a forced disconnection.

@@ -227,3 +213,3 @@ *

}
this.end(true);
this.end('booted');
}

@@ -233,2 +219,16 @@ };

/**
* Dispatches a packet.
*
* @api private
*/
Transport.prototype.onDispatch = function (packet, volatile) {
if (volatile) {
this.writeVolatile(packet);
} else {
this.write(packet);
}
};
/**
* Sets the close timeout.

@@ -244,3 +244,3 @@ */

self.closeTimeout = null;
self.end(false, 'close timeout');
self.end('close timeout');
}, this.manager.get('close timeout') * 1000);

@@ -276,3 +276,3 @@

self.heartbeatTimeout = null;
self.end(false, 'heartbeat timeout');
self.end('heartbeat timeout');
}, this.manager.get('heartbeat timeout') * 1000);

@@ -306,3 +306,3 @@

Transport.prototype.setHeartbeatInterval = function () {
if (!this.heartbeatTimeout) {
if (!this.heartbeatInterval) {
var self = this;

@@ -312,2 +312,3 @@

self.heartbeat();
self.heartbeatInterval = null;
}, this.manager.get('heartbeat interval') * 1000);

@@ -355,21 +356,46 @@

Transport.prototype.onMessage = function (packet) {
var current = this.manager.transports[this.id];
if ('heartbeat' == packet.type) {
this.log.debug('got heartbeat packet');
this.store.heartbeat(this.id);
} else if ('disconnect' == packet.type && packet.endpoint == '') {
this.log.debug('got disconnection packet');
this.store.disconnect(this.id, true);
if (current && current.open) {
current.onHeartbeatClear();
} else {
this.store.publish('heartbeat-clear:' + this.id);
}
} else {
this.log.debug('got packet');
if ('disconnect' == packet.type && packet.endpoint == '') {
this.log.debug('got disconnection packet');
if (current && current.open) {
current.onForcedDisconnect();
} else {
this.store.publish('disconnect-force:' + this.id);
}
}
if (packet.id && packet.ack != 'data') {
this.log.debug('acknowledging packet automatically');
this.store.client(this.id).publish(parser.encodePacket({
var ack = parser.encodePacket({
type: 'ack'
, ackId: packet.id
, endpoint: packet.endpoint || ''
}));
});
if (current && current.open) {
current.onDispatch(ack);
} else {
this.manager.onClientDispatch(this.id, ack);
this.store.publish('dispatch:' + this.id, ack);
}
}
this.store.message(this.id, packet);
// handle packet locally or publish it
if (current) {
this.manager.onClientMessage(this.id, packet);
} else {
this.store.publish('message:' + this.id, packet);
}
}

@@ -400,3 +426,3 @@ };

this.packet({ type: 'disconnect' });
this.end(false, reason);
this.end(reason);

@@ -428,4 +454,5 @@ return this;

this.setCloseTimeout();
this.unsubscribe();
this.open = false;
this.manager.onClose(this.id);
this.store.publish('close', this.id);
}

@@ -440,29 +467,18 @@ };

Transport.prototype.end = function (forced, reason) {
Transport.prototype.end = function (reason) {
if (!this.disconnected) {
this.log.info('ending socket');
var local = this.manager.transports[this.id];
this.close();
this.clearTimeouts();
if (!forced)
this.store.disconnect(this.id, false, reason);
this.disconnected = true;
}
};
/**
* Signals that the transport can start flushing buffers.
*
* @api public
*/
Transport.prototype.resume = function () {
if (!this.disconnected) {
this.paused = false;
this.setHeartbeatInterval();
this.subscribe();
if (local) {
this.manager.onClientDisconnect(this.id, reason, true);
} else {
this.store.publish('disconnect:' + this.id, reason);
}
}
return this;
};

@@ -476,4 +492,9 @@

Transport.prototype.pause = function () {
this.paused = true;
Transport.prototype.discard = function () {
this.log.debug('discarding transport');
this.discarded = true;
this.clearTimeouts();
this.clearHandlers();
this.buffer = [];
return this;

@@ -498,3 +519,3 @@ };

this.log.warn(reason, advice ? ('client should ' + advice) : '');
this.end(false, 'error');
this.end('error');
};

@@ -513,40 +534,2 @@

/**
* Subscribe client.
*
* @api private
*/
Transport.prototype.subscribe = function () {
if (!this.subscribed) {
this.log.debug('subscribing', this.id);
var self = this;
// subscribe to buffered + normal messages
this.store.client(this.id).consume(function (payload, packet) {
if (payload) {
self.payload(payload);
} else {
self.write(packet);
}
});
this.subscribed = true;
}
};
/**
* Unsubscribe client.
*
* @api private
*/
Transport.prototype.unsubscribe = function () {
this.log.info('unsubscribing', this.id);
this.store.client(this.id).pause();
this.subscribed = false;
};
/**
* Writes a volatile message.

@@ -553,0 +536,0 @@ *

@@ -26,4 +26,4 @@

function FlashSocket () {
WebSocket.apply(this, arguments);
function FlashSocket (mng, data, req) {
WebSocket.call(this, mng, data, req);
}

@@ -38,2 +38,10 @@

/**
* Transport name
*
* @api public
*/
FlashSocket.prototype.name = 'flashsocket';
/**
* Listens for new configuration changes of the Manager

@@ -40,0 +48,0 @@ * this way we can enable and disable the flash server.

@@ -26,4 +26,4 @@

function HTMLFile (mng, data) {
HTTPTransport.call(this, mng, data);
function HTMLFile (mng, data, req) {
HTTPTransport.call(this, mng, data, req);
};

@@ -38,2 +38,10 @@

/**
* Transport name
*
* @api public
*/
HTMLFile.prototype.name = 'htmlfile';
/**
* Handles the request.

@@ -75,3 +83,3 @@ *

this.log.debug('htmlfile writing', data);
this.log.debug(this.name + ' writing', data);
};

@@ -26,4 +26,4 @@

function HTTPPolling (mng, data) {
HTTPTransport.call(this, mng, data);
function HTTPPolling (mng, data, req) {
HTTPTransport.call(this, mng, data, req);
};

@@ -40,2 +40,10 @@

/**
* Transport name
*
* @api public
*/
HTTPPolling.prototype.name = 'httppolling';
/**
* Removes heartbeat timeouts for polling.

@@ -62,3 +70,3 @@ */

self.packet({ type: 'noop' });
self.log.debug('polling closed due to exceeded duration');
self.log.debug(self.name + ' closed due to exceeded duration');
}, this.manager.get('polling duration') * 1000);

@@ -65,0 +73,0 @@

@@ -28,4 +28,4 @@

function HTTPTransport (mng, data) {
Transport.call(this, mng, data);
function HTTPTransport (mng, data, req) {
Transport.call(this, mng, data, req);
};

@@ -89,3 +89,3 @@

for (var i = 0, l = messages.length; i < l; i++) {
this.log.debug('xhr received data packet', data);
this.log.debug(this.name + ' received data packet', data);
this.onMessage(messages[i]);

@@ -92,0 +92,0 @@ }

@@ -26,4 +26,4 @@

function JSONPPolling (mng, data) {
HTTPPolling.call(this, mng, data);
function JSONPPolling (mng, data, req) {
HTTPPolling.call(this, mng, data, req);

@@ -45,2 +45,10 @@ this.head = 'io.j[0](';

/**
* Transport name
*
* @api public
*/
JSONPPolling.prototype.name = 'jsonppolling';
/**
* Make sure POST are decoded.

@@ -70,3 +78,3 @@ */

this.response.write(data);
this.log.debug('json-p writing', data);
this.log.debug(this.name + ' writing', data);
};

@@ -30,3 +30,3 @@

function WebSocket (mng, data) {
function WebSocket (mng, data, req) {
// parser

@@ -37,3 +37,3 @@ var self = this;

this.parser.on('data', function (packet) {
self.log.debug('websocket received data packet', packet);
self.log.debug(self.name + ' received data packet', packet);
self.onMessage(parser.decodePacket(packet));

@@ -48,3 +48,3 @@ });

Transport.call(this, mng, data);
Transport.call(this, mng, data, req);
};

@@ -59,2 +59,10 @@

/**
* Transport name
*
* @api public
*/
WebSocket.prototype.name = 'websocket';
/**
* Called when the socket connects.

@@ -74,3 +82,3 @@ *

if (this.req.headers.upgrade !== 'WebSocket') {
this.log.warn('WebSocket connection invalid');
this.log.warn(this.name + ' connection invalid');
this.end();

@@ -188,3 +196,3 @@ return;

this.log.debug('websocket writing', data);
this.log.debug(this.name + ' writing', data);
}

@@ -203,3 +211,3 @@ };

for (var i = 0, l = this.buffered.length; i < l; i++) {
this.write(this.buffered.splice(0, 1));
this.write(this.buffered.splice(0, 1)[0]);
}

@@ -227,3 +235,3 @@ };

if (spaces === 0 || n % spaces !== 0){
self.log.warn('Invalid WebSocket key: "' + k + '".');
self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
self.end();

@@ -230,0 +238,0 @@ return false;

@@ -26,4 +26,4 @@

function XHRPolling (mng, data) {
HTTPPolling.call(this, mng, data);
function XHRPolling (mng, data, req) {
HTTPPolling.call(this, mng, data, req);
};

@@ -38,2 +38,10 @@

/**
* Transport name
*
* @api public
*/
XHRPolling.prototype.name = 'xhr-polling';
/**
* Frames data prior to write.

@@ -65,3 +73,3 @@ *

this.response.write(data);
this.log.debug('xhr-polling writing', data);
this.log.debug(this.name + ' writing', data);
};
{
"name": "socket.io"
, "version": "0.7.2"
, "version": "0.7.3"
, "description": "Realtime apps made cross-browser & easy with a WebSocket-like API"

@@ -18,4 +18,5 @@ , "homepage": "http://socket.io"

, "dependencies": {
"socket.io-client": "0.7.2"
, "policyfile": ">= 0.0.3"
"socket.io-client": "0.7.3"
, "policyfile": "0.0.3"
, "redis": "0.6.0"
}

@@ -22,0 +23,0 @@ , "devDependencies": {

@@ -1,2 +0,1 @@

# Socket.IO

@@ -92,3 +91,3 @@

socket.on('msg', function () {
socket.get('nickname', function (name) {
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);

@@ -153,5 +152,4 @@ });

<script>
var socket = io.connect('http://localhost/')
, chat = socket.of('/chat')
, news = socket.of('/news');
var chat = io.connect('http://localhost/chat')
, news = io.connect('http://localhost/news');

@@ -282,3 +280,3 @@ chat.on('connect', function () {

```js
var io = require('socket.io-node').listen(80);
var io = require('socket.io').listen(80);

@@ -313,3 +311,3 @@ io.sockets.on('connection', function (socket) {

```js
var io = require('socket.io-node').listen(80);
var io = require('socket.io').listen(80);

@@ -316,0 +314,0 @@ io.configure(function () {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc