Files
socket.io/lib/adapter.js
Kevin Roark c2bf0ea700 Added binary support to broadcasting of events
lib/namespace.js previously was not considering whether an event had
binary data and was giving all events parser.EVENT type -- now it uses
the has-binary-data module to set the event type appropriately.

Then, after this fix there was a problem with lib/adapter.js -- because
socket.io-parser modifies the packet object in its encoding, the sockets
after the 1st in a broadcast were not getting the correct data. To fix
this, the data is encoded once in adapter, and then the encoded data
is passed to each of the sockets.

lib/socket.js and lib/client.js were updated to allow for the above. The
.packet method of each now takes an optional second "preEncoded" parameter
-- if this is true, then client skips the encoding and just writes the
packet argument directly to engine.

test/socket.io.js was updated to add two new tests that test
multi-messaging of events with binary data.
2014-03-02 22:15:16 -05:00

129 lines
2.6 KiB
JavaScript

/**
* Module dependencies.
*/
var Emitter = require('events').EventEmitter;
var parser = require('socket.io-parser');
/**
* Module exports.
*/
module.exports = Adapter;
/**
* Memory adapter constructor.
*
* @param {Namespace} nsp
* @api public
*/
function Adapter(nsp){
this.nsp = nsp;
this.rooms = {};
this.sids = {};
this.encoder = new parser.Encoder();
}
/**
* Inherits from `EventEmitter`.
*/
Adapter.prototype.__proto__ = Emitter.prototype;
/**
* Adds a socket from a room.
*
* @param {String} socket id
* @param {String} room name
* @param {Function} callback
* @api public
*/
Adapter.prototype.add = function(id, room, fn){
this.sids[id] = this.sids[id] || {};
this.sids[id][room] = true;
this.rooms[room] = this.rooms[room] || [];
this.rooms[room][id] = true;
if (fn) process.nextTick(fn.bind(null, null));
};
/**
* Removes a socket from a room.
*
* @param {String} socket id
* @param {String} room name
* @param {Function} callback
* @api public
*/
Adapter.prototype.del = function(id, room, fn){
this.sids[id] = this.sids[id] || {};
this.rooms[room] = this.rooms[room] || {};
delete this.sids[id][room];
delete this.rooms[room][id];
if (fn) process.nextTick(fn.bind(null, null));
};
/**
* Removes a socket from all rooms it's joined.
*
* @param {String} socket id
* @api public
*/
Adapter.prototype.delAll = function(id, fn){
var rooms = this.sids[id];
if (rooms) {
for (var room in rooms) {
delete this.rooms[room][id];
}
}
delete this.sids[id];
};
/**
* Broadcasts a packet.
*
* Options:
* - `flags` {Object} flags for this packet
* - `except` {Array} sids that should be excluded
* - `rooms` {Array} list of rooms to broadcast to
*
* @param {Object} packet object
* @api public
*/
Adapter.prototype.broadcast = function(packet, opts){
var rooms = opts.rooms || [];
var except = opts.except || [];
var ids = {};
var self = this;
var socket;
packet.nsp = this.nsp.name;
this.encoder.encode(packet, function(encodedPackets) {
if (rooms.length) {
for (var i = 0; i < rooms.length; i++) {
var room = self.rooms[rooms[i]];
if (!room) continue;
for (var id in room) {
if (ids[id] || ~except.indexOf(id)) continue;
socket = self.nsp.connected[id];
if (socket) {
socket.packet(encodedPackets, true);
ids[id] = true;
}
}
}
} else {
for (var id in self.sids) {
if (~except.indexOf(id)) continue;
socket = self.nsp.connected[id];
if (socket) socket.packet(encodedPackets, true);
}
}
});
};