diff --git a/lib/manager.js b/lib/manager.js index 1d6ab58f89..d0d02be680 100644 --- a/lib/manager.js +++ b/lib/manager.js @@ -100,6 +100,13 @@ function Manager (server, options) { self.handleUpgrade(req, socket, head); }); + server.on('close', function () { + clearInterval(self.gc); + }); + + // run our private gc every 10 seconds + this.gc = setInterval(this.garbageCollection.bind(this), 10000); + for (var i in transports) { if (transports[i].init) { transports[i].init(this); @@ -593,9 +600,10 @@ Manager.prototype.handleClient = function (data, req) { return; } - var transport = new transports[data.transport](this, data, req); + var transport = new transports[data.transport](this, data, req) + , handshaken = this.handshaken[data.id]; - if (this.handshaken[data.id]) { + if (handshaken) { if (transport.open) { if (this.closed[data.id] && this.closed[data.id].length) { transport.payload(this.closed[data.id]); @@ -611,6 +619,11 @@ Manager.prototype.handleClient = function (data, req) { this.onConnect(data.id); this.store.publish('connect', data.id); + // flag as used + delete handshaken.issued; + this.onHandshake(data.id, handshaken); + this.store.publish('handshake', data.id, handshaken); + // initialize the socket for all namespaces for (var i in this.namespaces) { var socket = this.namespaces[i].socket(data.id, true); @@ -818,7 +831,8 @@ Manager.prototype.handleHandshake = function (data, req, res) { Manager.prototype.handshakeData = function (data) { var connection = data.request.connection - , connectionAddress; + , connectionAddress + , date = new Date; if (connection.remoteAddress) { connectionAddress = { @@ -835,11 +849,12 @@ Manager.prototype.handshakeData = function (data) { return { headers: data.headers , address: connectionAddress - , time: (new Date).toString() + , time: date.toString() , query: data.query , url: data.request.url , xdomain: !!data.request.headers.origin , secure: data.request.connection.secure + , issued: +date }; }; @@ -969,6 +984,8 @@ Manager.prototype.checkRequest = function (req) { /** * Declares a socket namespace + * + * @api public */ Manager.prototype.of = function (nsp) { @@ -978,3 +995,26 @@ Manager.prototype.of = function (nsp) { return this.namespaces[nsp] = new SocketNamespace(this, nsp); }; + +/** + * Perform garbage collection on long living objects and properties that cannot + * be removed automatically. + * + * @api private + */ + +Manager.prototype.garbageCollection = function () { + // clean up unused handshakes + var ids = Object.keys(this.handshaken) + , i = ids.length + , now = Date.now() + , handshake; + + while (i--) { + handshake = this.handshaken[ids[i]]; + + if ('issued' in handshake && (now - handshake.issued) >= 3E4) { + this.onDisconnect(ids[i]); + } + } +};