| |
| /** |
| * Module dependencies. |
| */ |
| |
| var Emitter = require('events').EventEmitter; |
| |
| /** |
| * 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 = nsp.server.encoder; |
| } |
| |
| /** |
| * Inherits from `EventEmitter`. |
| */ |
| |
| Adapter.prototype.__proto__ = Emitter.prototype; |
| |
| /** |
| * Adds a socket to a room. |
| * |
| * @param {String} socket id |
| * @param {String} room name |
| * @param {Function} callback |
| * @api public |
| */ |
| |
| Adapter.prototype.add = function(id, room, fn){ |
| return this.addAll(id, [ room ], fn); |
| }; |
| |
| /** |
| * Adds a socket to a list of room. |
| * |
| * @param {String} socket id |
| * @param {String} rooms |
| * @param {Function} callback |
| * @api public |
| */ |
| |
| Adapter.prototype.addAll = function(id, rooms, fn){ |
| for (var i = 0; i < rooms.length; i++) { |
| var room = rooms[i]; |
| this.sids[id] = this.sids[id] || {}; |
| this.sids[id][room] = true; |
| this.rooms[room] = this.rooms[room] || Room(); |
| this.rooms[room].add(id); |
| } |
| 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] || {}; |
| delete this.sids[id][room]; |
| if (this.rooms.hasOwnProperty(room)) { |
| this.rooms[room].del(id); |
| if (this.rooms[room].length === 0) delete this.rooms[room]; |
| } |
| |
| if (fn) process.nextTick(fn.bind(null, null)); |
| }; |
| |
| /** |
| * Removes a socket from all rooms it's joined. |
| * |
| * @param {String} socket id |
| * @param {Function} callback |
| * @api public |
| */ |
| |
| Adapter.prototype.delAll = function(id, fn){ |
| var rooms = this.sids[id]; |
| if (rooms) { |
| for (var room in rooms) { |
| if (this.rooms.hasOwnProperty(room)) { |
| this.rooms[room].del(id); |
| if (this.rooms[room].length === 0) delete this.rooms[room]; |
| } |
| } |
| } |
| delete this.sids[id]; |
| |
| if (fn) process.nextTick(fn.bind(null, null)); |
| }; |
| |
| /** |
| * 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 flags = opts.flags || {}; |
| var packetOpts = { |
| preEncoded: true, |
| volatile: flags.volatile, |
| compress: flags.compress |
| }; |
| 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; |
| var sockets = room.sockets; |
| for (var id in sockets) { |
| if (sockets.hasOwnProperty(id)) { |
| if (ids[id] || ~except.indexOf(id)) continue; |
| socket = self.nsp.connected[id]; |
| if (socket) { |
| socket.packet(encodedPackets, packetOpts); |
| ids[id] = true; |
| } |
| } |
| } |
| } |
| } else { |
| for (var id in self.sids) { |
| if (self.sids.hasOwnProperty(id)) { |
| if (~except.indexOf(id)) continue; |
| socket = self.nsp.connected[id]; |
| if (socket) socket.packet(encodedPackets, packetOpts); |
| } |
| } |
| } |
| }); |
| }; |
| |
| /** |
| * Gets a list of clients by sid. |
| * |
| * @param {Array} explicit set of rooms to check. |
| * @param {Function} callback |
| * @api public |
| */ |
| |
| Adapter.prototype.clients = function(rooms, fn){ |
| if ('function' == typeof rooms){ |
| fn = rooms; |
| rooms = null; |
| } |
| |
| rooms = rooms || []; |
| |
| var ids = {}; |
| var sids = []; |
| var socket; |
| |
| if (rooms.length) { |
| for (var i = 0; i < rooms.length; i++) { |
| var room = this.rooms[rooms[i]]; |
| if (!room) continue; |
| var sockets = room.sockets; |
| for (var id in sockets) { |
| if (sockets.hasOwnProperty(id)) { |
| if (ids[id]) continue; |
| socket = this.nsp.connected[id]; |
| if (socket) { |
| sids.push(id); |
| ids[id] = true; |
| } |
| } |
| } |
| } |
| } else { |
| for (var id in this.sids) { |
| if (this.sids.hasOwnProperty(id)) { |
| socket = this.nsp.connected[id]; |
| if (socket) sids.push(id); |
| } |
| } |
| } |
| |
| if (fn) process.nextTick(fn.bind(null, null, sids)); |
| }; |
| |
| /** |
| * Gets the list of rooms a given client has joined. |
| * |
| * @param {String} socket id |
| * @param {Function} callback |
| * @api public |
| */ |
| Adapter.prototype.clientRooms = function(id, fn){ |
| var rooms = this.sids[id]; |
| if (fn) process.nextTick(fn.bind(null, null, rooms ? Object.keys(rooms) : null)); |
| }; |
| |
| /** |
| * Room constructor. |
| * |
| * @api private |
| */ |
| |
| function Room(){ |
| if (!(this instanceof Room)) return new Room(); |
| this.sockets = {}; |
| this.length = 0; |
| } |
| |
| /** |
| * Adds a socket to a room. |
| * |
| * @param {String} socket id |
| * @api private |
| */ |
| |
| Room.prototype.add = function(id){ |
| if (!this.sockets.hasOwnProperty(id)) { |
| this.sockets[id] = true; |
| this.length++; |
| } |
| }; |
| |
| /** |
| * Removes a socket from a room. |
| * |
| * @param {String} socket id |
| * @api private |
| */ |
| |
| Room.prototype.del = function(id){ |
| if (this.sockets.hasOwnProperty(id)) { |
| delete this.sockets[id]; |
| this.length--; |
| } |
| }; |