diff --git a/lib/server/swarm.js b/lib/server/swarm.js index c8d52cc..6f08543 100644 --- a/lib/server/swarm.js +++ b/lib/server/swarm.js @@ -7,19 +7,29 @@ var randomIterate = require('random-iterate') // Regard this as the default implementation of an interface that you // need to support when overriding Server.createSwarm() and Server.getSwarm() function Swarm (infoHash, server) { + this.infoHash = infoHash this.complete = 0 this.incomplete = 0 + this.peers = new LRU({ max: server.peersCacheLength || 1000, maxAge: server.peersCacheTtl || 20 * 60 * 1000 // 20 minutes }) - // When a websocket peer is evicted from the LRU cache, close the websocket - // after a short timeout period. We wait 1s so the server has a chance to send - // a response to 'stopped' events, which remove the peer and cause an eviction. + // When a peer is evicted from the LRU store, send a synthetic 'stopped' event + // so the stats get updated correctly. this.peers.on('evict', function (data) { var peer = data.value - if (peer.socket) { + this.announce({ + type: peer.type, + event: 'stopped', + numwant: 0, + peer_id: peer.peerId + }, noop) + + // When a websocket peer is evicted, and it's not in any other swarms, close + // the websocket to conserve server resources. + if (peer.socket && peer.socket.infoHashes.length === 0) { try { peer.socket.close() peer.socket = null @@ -86,6 +96,14 @@ Swarm.prototype._onAnnounceStopped = function (params, peer, id) { if (peer.complete) this.complete -= 1 else this.incomplete -= 1 + + // If it's a websocket, remove this swarm's infohash from the list of active + // swarms that this peer is participating in. + if (peer.socket) { + var index = peer.socket.infoHashes.indexOf(this.infoHash) + peer.socket.infoHashes.splice(index, 1) + } + this.peers.remove(id) } @@ -133,3 +151,5 @@ Swarm.prototype._getPeers = function (numwant, ownPeerId, isWebRTC) { } return peers } + +function noop () {} diff --git a/server.js b/server.js index bf6c12b..d28b692 100644 --- a/server.js +++ b/server.js @@ -585,7 +585,7 @@ Server.prototype._onWebSocketClose = function (socket) { debug('websocket close %s', socket.peerId) if (socket.peerId) { - socket.infoHashes.forEach(function (infoHash) { + socket.infoHashes.slice(0).forEach(function (infoHash) { var swarm = self.torrents[infoHash] if (swarm) { swarm.announce({