index.js (5421B)
1 2 /** 3 * Module dependencies. 4 */ 5 6 var Emitter = require('events').EventEmitter; 7 8 /** 9 * Module exports. 10 */ 11 12 module.exports = Adapter; 13 14 /** 15 * Memory adapter constructor. 16 * 17 * @param {Namespace} nsp 18 * @api public 19 */ 20 21 function Adapter(nsp){ 22 this.nsp = nsp; 23 this.rooms = {}; 24 this.sids = {}; 25 this.encoder = nsp.server.encoder; 26 } 27 28 /** 29 * Inherits from `EventEmitter`. 30 */ 31 32 Adapter.prototype.__proto__ = Emitter.prototype; 33 34 /** 35 * Adds a socket to a room. 36 * 37 * @param {String} socket id 38 * @param {String} room name 39 * @param {Function} callback 40 * @api public 41 */ 42 43 Adapter.prototype.add = function(id, room, fn){ 44 return this.addAll(id, [ room ], fn); 45 }; 46 47 /** 48 * Adds a socket to a list of room. 49 * 50 * @param {String} socket id 51 * @param {String} rooms 52 * @param {Function} callback 53 * @api public 54 */ 55 56 Adapter.prototype.addAll = function(id, rooms, fn){ 57 for (var i = 0; i < rooms.length; i++) { 58 var room = rooms[i]; 59 this.sids[id] = this.sids[id] || {}; 60 this.sids[id][room] = true; 61 this.rooms[room] = this.rooms[room] || Room(); 62 this.rooms[room].add(id); 63 } 64 if (fn) process.nextTick(fn.bind(null, null)); 65 }; 66 67 /** 68 * Removes a socket from a room. 69 * 70 * @param {String} socket id 71 * @param {String} room name 72 * @param {Function} callback 73 * @api public 74 */ 75 76 Adapter.prototype.del = function(id, room, fn){ 77 if (this.sids[id]) delete this.sids[id][room]; 78 79 if (this.rooms.hasOwnProperty(room)) { 80 this.rooms[room].del(id); 81 if (this.rooms[room].length === 0) delete this.rooms[room]; 82 } 83 84 if (fn) process.nextTick(fn.bind(null, null)); 85 }; 86 87 /** 88 * Removes a socket from all rooms it's joined. 89 * 90 * @param {String} socket id 91 * @param {Function} callback 92 * @api public 93 */ 94 95 Adapter.prototype.delAll = function(id, fn){ 96 var rooms = this.sids[id]; 97 if (rooms) { 98 for (var room in rooms) { 99 if (this.rooms.hasOwnProperty(room)) { 100 this.rooms[room].del(id); 101 if (this.rooms[room].length === 0) delete this.rooms[room]; 102 } 103 } 104 } 105 delete this.sids[id]; 106 107 if (fn) process.nextTick(fn.bind(null, null)); 108 }; 109 110 /** 111 * Broadcasts a packet. 112 * 113 * Options: 114 * - `flags` {Object} flags for this packet 115 * - `except` {Array} sids that should be excluded 116 * - `rooms` {Array} list of rooms to broadcast to 117 * 118 * @param {Object} packet object 119 * @api public 120 */ 121 122 Adapter.prototype.broadcast = function(packet, opts){ 123 var rooms = opts.rooms || []; 124 var except = opts.except || []; 125 var flags = opts.flags || {}; 126 var packetOpts = { 127 preEncoded: true, 128 volatile: flags.volatile, 129 compress: flags.compress 130 }; 131 var ids = {}; 132 var self = this; 133 var socket; 134 135 packet.nsp = this.nsp.name; 136 this.encoder.encode(packet, function(encodedPackets) { 137 if (rooms.length) { 138 for (var i = 0; i < rooms.length; i++) { 139 var room = self.rooms[rooms[i]]; 140 if (!room) continue; 141 var sockets = room.sockets; 142 for (var id in sockets) { 143 if (sockets.hasOwnProperty(id)) { 144 if (ids[id] || ~except.indexOf(id)) continue; 145 socket = self.nsp.connected[id]; 146 if (socket) { 147 socket.packet(encodedPackets, packetOpts); 148 ids[id] = true; 149 } 150 } 151 } 152 } 153 } else { 154 for (var id in self.sids) { 155 if (self.sids.hasOwnProperty(id)) { 156 if (~except.indexOf(id)) continue; 157 socket = self.nsp.connected[id]; 158 if (socket) socket.packet(encodedPackets, packetOpts); 159 } 160 } 161 } 162 }); 163 }; 164 165 /** 166 * Gets a list of clients by sid. 167 * 168 * @param {Array} explicit set of rooms to check. 169 * @param {Function} callback 170 * @api public 171 */ 172 173 Adapter.prototype.clients = function(rooms, fn){ 174 if ('function' == typeof rooms){ 175 fn = rooms; 176 rooms = null; 177 } 178 179 rooms = rooms || []; 180 181 var ids = {}; 182 var sids = []; 183 var socket; 184 185 if (rooms.length) { 186 for (var i = 0; i < rooms.length; i++) { 187 var room = this.rooms[rooms[i]]; 188 if (!room) continue; 189 var sockets = room.sockets; 190 for (var id in sockets) { 191 if (sockets.hasOwnProperty(id)) { 192 if (ids[id]) continue; 193 socket = this.nsp.connected[id]; 194 if (socket) { 195 sids.push(id); 196 ids[id] = true; 197 } 198 } 199 } 200 } 201 } else { 202 for (var id in this.sids) { 203 if (this.sids.hasOwnProperty(id)) { 204 socket = this.nsp.connected[id]; 205 if (socket) sids.push(id); 206 } 207 } 208 } 209 210 if (fn) process.nextTick(fn.bind(null, null, sids)); 211 }; 212 213 /** 214 * Gets the list of rooms a given client has joined. 215 * 216 * @param {String} socket id 217 * @param {Function} callback 218 * @api public 219 */ 220 Adapter.prototype.clientRooms = function(id, fn){ 221 var rooms = this.sids[id]; 222 if (fn) process.nextTick(fn.bind(null, null, rooms ? Object.keys(rooms) : null)); 223 }; 224 225 /** 226 * Room constructor. 227 * 228 * @api private 229 */ 230 231 function Room(){ 232 if (!(this instanceof Room)) return new Room(); 233 this.sockets = {}; 234 this.length = 0; 235 } 236 237 /** 238 * Adds a socket to a room. 239 * 240 * @param {String} socket id 241 * @api private 242 */ 243 244 Room.prototype.add = function(id){ 245 if (!this.sockets.hasOwnProperty(id)) { 246 this.sockets[id] = true; 247 this.length++; 248 } 249 }; 250 251 /** 252 * Removes a socket from a room. 253 * 254 * @param {String} socket id 255 * @api private 256 */ 257 258 Room.prototype.del = function(id){ 259 if (this.sockets.hasOwnProperty(id)) { 260 delete this.sockets[id]; 261 this.length--; 262 } 263 };