diff --git a/lib/client.js b/lib/client.js index 71ec38b095..1ce3fc4986 100644 --- a/lib/client.js +++ b/lib/client.js @@ -28,7 +28,7 @@ function Client(server, conn){ this.id = conn.id; this.request = conn.request; this.setup(); - this.sockets = []; + this.sockets = {}; this.nsps = {}; this.connectBuffer = []; } @@ -73,7 +73,7 @@ Client.prototype.connect = function(name){ var self = this; var socket = nsp.add(this, function(){ - self.sockets.push(socket); + self.sockets[socket.id] = socket; self.nsps[nsp.name] = socket; if ('/' == nsp.name && self.connectBuffer.length > 0) { @@ -90,12 +90,10 @@ Client.prototype.connect = function(name){ */ Client.prototype.disconnect = function(){ - var socket; - // we don't use a for loop because the length of - // `sockets` changes upon each iteration - while (socket = this.sockets.shift()) { - socket.disconnect(); + for (var id in this.sockets) { + this.sockets[id].disconnect(); } + this.sockets = {}; this.close(); }; @@ -106,10 +104,9 @@ Client.prototype.disconnect = function(){ */ Client.prototype.remove = function(socket){ - var i = this.sockets.indexOf(socket); - if (~i) { - var nsp = this.sockets[i].nsp.name; - this.sockets.splice(i, 1); + if (this.sockets[socket.id]) { + var nsp = this.sockets[socket.id].nsp.name; + delete this.sockets[socket.id]; delete this.nsps[nsp]; } else { debug('ignoring remove for %s', socket.id); @@ -206,9 +203,9 @@ Client.prototype.ondecoded = function(packet) { */ Client.prototype.onerror = function(err){ - this.sockets.forEach(function(socket){ - socket.onerror(err); - }); + for (var id in this.sockets) { + this.sockets[id].onerror(err); + } this.onclose('client error'); }; @@ -226,10 +223,10 @@ Client.prototype.onclose = function(reason){ this.destroy(); // `nsps` and `sockets` are cleaned up seamlessly - var socket; - while (socket = this.sockets.shift()) { - socket.onclose(reason); + for (var id in this.sockets) { + this.sockets[id].onclose(reason); } + this.sockets = {}; this.decoder.destroy(); // clean up decoder }; diff --git a/lib/index.js b/lib/index.js index 449fb6fa12..1612c0cfa3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -347,9 +347,9 @@ Server.prototype.of = function(name, fn){ */ Server.prototype.close = function(){ - this.nsps['/'].sockets.forEach(function(socket){ - socket.onclose(); - }); + for (var id in this.nsps['/'].sockets) { + this.nsps['/'].sockets[id].onclose(); + } this.engine.close(); diff --git a/lib/namespace.js b/lib/namespace.js index 11c231dc38..1a5b7efcfd 100644 --- a/lib/namespace.js +++ b/lib/namespace.js @@ -51,7 +51,7 @@ var emit = Emitter.prototype.emit; function Namespace(server, name){ this.name = name; this.server = server; - this.sockets = []; + this.sockets = {}; this.connected = {}; this.fns = []; this.ids = 0; @@ -160,7 +160,7 @@ Namespace.prototype.add = function(client, fn){ if (err) return socket.error(err.data || err.message); // track socket - self.sockets.push(socket); + self.sockets[socket.id] = socket; // it's paramount that the internal `onconnect` logic // fires before user-set events to prevent state order @@ -187,9 +187,8 @@ Namespace.prototype.add = function(client, fn){ */ Namespace.prototype.remove = function(socket){ - var i = this.sockets.indexOf(socket); - if (~i) { - this.sockets.splice(i, 1); + if (this.sockets[socket.id]) { + delete this.sockets[socket.id]; } else { debug('ignoring remove for %s', socket.id); } diff --git a/lib/socket.js b/lib/socket.js index eeb8cb2159..1e50a0232b 100644 --- a/lib/socket.js +++ b/lib/socket.js @@ -60,9 +60,10 @@ function Socket(nsp, client){ this.server = nsp.server; this.adapter = this.nsp.adapter; this.id = client.id; + this.id = nsp.name + '#' + client.id; this.client = client; this.conn = client.conn; - this.rooms = []; + this.rooms = {}; this.acks = {}; this.connected = true; this.disconnected = false; @@ -222,11 +223,11 @@ Socket.prototype.packet = function(packet, opts){ Socket.prototype.join = function(room, fn){ debug('joining room %s', room); var self = this; - if (~this.rooms.indexOf(room)) return this; + if (this.rooms[room]) return this; this.adapter.add(this.id, room, function(err){ if (err) return fn && fn(err); debug('joined room %s', room); - self.rooms.push(room); + self.rooms[room] = room; fn && fn(null); }); return this; @@ -247,10 +248,7 @@ Socket.prototype.leave = function(room, fn){ this.adapter.del(this.id, room, function(err){ if (err) return fn && fn(err); debug('left room %s', room); - var idx = self.rooms.indexOf(room); - if (idx >= 0) { - self.rooms.splice(idx, 1); - } + delete self.rooms[room]; fn && fn(null); }); return this; @@ -264,7 +262,7 @@ Socket.prototype.leave = function(room, fn){ Socket.prototype.leaveAll = function(){ this.adapter.delAll(this.id); - this.rooms = []; + this.rooms = {}; }; /** diff --git a/test/socket.io.js b/test/socket.io.js index 06b1c77362..026cb5f143 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -368,12 +368,12 @@ describe('socket.io', function(){ var clientSocket = client(srv, { reconnection: false }); clientSocket.on('disconnect', function init() { - expect(sio.nsps['/'].sockets.length).to.equal(0); + expect(Object.keys(sio.nsps['/'].sockets).length).to.equal(0); server.listen(PORT); }); clientSocket.on('connect', function init() { - expect(sio.nsps['/'].sockets.length).to.equal(1); + expect(Object.keys(sio.nsps['/'].sockets).length).to.equal(1); sio.close(); }); @@ -395,12 +395,12 @@ describe('socket.io', function(){ var clientSocket = ioc('ws://0.0.0.0:' + PORT); clientSocket.on('disconnect', function init() { - expect(sio.nsps['/'].sockets.length).to.equal(0); + expect(Object.keys(sio.nsps['/'].sockets).length).to.equal(0); server.listen(PORT); }); clientSocket.on('connect', function init() { - expect(sio.nsps['/'].sockets.length).to.equal(1); + expect(Object.keys(sio.nsps['/'].sockets).length).to.equal(1); sio.close(); }); @@ -1932,15 +1932,15 @@ describe('socket.io', function(){ var socket = client(srv); sio.on('connection', function(s){ s.join('a', function(){ - expect(s.rooms).to.eql([s.id, 'a']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a']); s.join('b', function(){ - expect(s.rooms).to.eql([s.id, 'a', 'b']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a', 'b']); s.join( 'c', function(){ - expect(s.rooms).to.eql([s.id, 'a', 'b', 'c']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a', 'b', 'c']); s.leave('b', function(){ - expect(s.rooms).to.eql([s.id, 'a', 'c']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a', 'c']); s.leaveAll(); - expect(s.rooms).to.eql([]); + expect(Object.keys(s.rooms)).to.eql([]); done(); }); }); @@ -1976,13 +1976,13 @@ describe('socket.io', function(){ var socket = client(srv); sio.on('connection', function(s){ s.join('a', function(){ - expect(s.rooms).to.eql([s.id, 'a']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a']); s.join('b', function(){ - expect(s.rooms).to.eql([s.id, 'a', 'b']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a', 'b']); s.leave('unknown', function(){ - expect(s.rooms).to.eql([s.id, 'a', 'b']); + expect(Object.keys(s.rooms)).to.eql([s.id, 'a', 'b']); s.leaveAll(); - expect(s.rooms).to.eql([]); + expect(Object.keys(s.rooms)).to.eql([]); done(); }); });