Skip to content

Commit ca522c0

Browse files
committed
Prune old peers in server with lru based cache. Issue webtorrent#4
1 parent 92a0710 commit ca522c0

File tree

4 files changed

+32
-19
lines changed

4 files changed

+32
-19
lines changed

lib/server/swarm.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
module.exports = Swarm
22

33
var debug = require('debug')('bittorrent-tracker')
4+
var LRU = require('lru')
45
var randomIterate = require('random-iterate')
56

67
// Regard this as the default implementation of an interface that you
78
// need to support when overriding Server.createSwarm() and Server.getSwarm()
89
function Swarm (infoHash, server) {
9-
this.peers = {}
10+
this.peers = new LRU({
11+
max: server.peersCacheLength || 10000,
12+
maxAge: server.peersCacheTtl || 900 // 900s = 15 minutes
13+
})
1014
this.complete = 0
1115
this.incomplete = 0
1216
}
1317

1418
Swarm.prototype.announce = function (params, cb) {
1519
var self = this
1620
var id = params.type === 'ws' ? params.peer_id : params.addr
17-
var peer = self.peers[id]
21+
// Mark the source peer as recently used in cache
22+
var peer = self.peers.get(id)
1823

1924
if (params.event === 'started') {
2025
self._onAnnounceStarted(params, peer)
@@ -51,14 +56,14 @@ Swarm.prototype._onAnnounceStarted = function (params, peer) {
5156
if (params.left === 0) this.complete += 1
5257
else this.incomplete += 1
5358
var id = params.type === 'ws' ? params.peer_id : params.addr
54-
peer = this.peers[id] = {
59+
peer = this.peers.set(id, {
5560
type: params.type,
5661
complete: params.left === 0,
5762
peerId: params.peer_id, // as hex
5863
ip: params.ip,
5964
port: params.port,
6065
socket: params.socket // only websocket
61-
}
66+
})
6267
}
6368

6469
Swarm.prototype._onAnnounceStopped = function (params, peer) {
@@ -70,7 +75,7 @@ Swarm.prototype._onAnnounceStopped = function (params, peer) {
7075
if (peer.complete) this.complete -= 1
7176
else this.incomplete -= 1
7277
var id = params.type === 'ws' ? params.peer_id : params.addr
73-
delete this.peers[id]
78+
this.peers.remove(id)
7479
}
7580

7681
Swarm.prototype._onAnnounceCompleted = function (params, peer) {
@@ -103,10 +108,11 @@ Swarm.prototype._onAnnounceUpdate = function (params, peer) {
103108

104109
Swarm.prototype._getPeers = function (numwant, ownPeerId, isWebRTC) {
105110
var peers = []
106-
var ite = randomIterate(Object.keys(this.peers))
111+
var ite = randomIterate(Object.keys(this.peers.cache))
107112
var peerId
108113
while ((peerId = ite()) && peers.length < numwant) {
109-
var peer = this.peers[peerId]
114+
// Don't mark the peer as most recently used on announce
115+
var peer = this.peers.peek(peerId)
110116
if (isWebRTC && peer.peerId === ownPeerId) continue // don't send peer to itself
111117
if ((isWebRTC && peer.type !== 'ws') || (!isWebRTC && peer.type === 'ws')) continue // send proper peer type
112118
peers.push(peer)

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"hat": "0.0.3",
2828
"inherits": "^2.0.1",
2929
"ip": "^1.0.1",
30+
"lru": "^2.0.1",
3031
"minimist": "^1.1.1",
3132
"once": "^1.3.0",
3233
"random-iterate": "^1.0.1",

server.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ function Server (opts) {
5050
self._trustProxy = !!opts.trustProxy
5151
if (typeof opts.filter === 'function') self._filter = opts.filter
5252

53+
self.peersCacheLength = opts.peersCacheLength
54+
self.peersCacheTtl = opts.peersCacheTtl
55+
5356
self._listenCalled = false
5457
self.listening = false
5558
self.destroyed = false
@@ -153,7 +156,7 @@ function Server (opts) {
153156
if (req.method === 'GET' && (req.url === '/stats' || req.url === '/stats.json')) {
154157
infoHashes.forEach(function (infoHash) {
155158
var peers = self.torrents[infoHash].peers
156-
var keys = Object.keys(peers)
159+
var keys = Object.keys(peers.cache)
157160
if (keys.length > 0) activeTorrents++
158161

159162
keys.forEach(function (peerId) {
@@ -165,7 +168,8 @@ function Server (opts) {
165168
leecher: false
166169
}
167170
}
168-
var peer = peers[peerId]
171+
// Don't mark the peer as most recently used for stats
172+
var peer = peers.peek(peerId)
169173
if (peer.ip.indexOf(':') >= 0) {
170174
allPeers[peerId].ipv6 = true
171175
} else {
@@ -489,7 +493,8 @@ Server.prototype._onWebSocketRequest = function (socket, opts, params) {
489493
if (!swarm) {
490494
return self.emit('warning', new Error('no swarm with that `info_hash`'))
491495
}
492-
var toPeer = swarm.peers[params.to_peer_id]
496+
// Mark the destination peer as recently used in cache
497+
var toPeer = swarm.peers.get(params.to_peer_id)
493498
if (!toPeer) {
494499
return self.emit('warning', new Error('no peer with that `to_peer_id`'))
495500
}

test/server.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,23 @@ function serverTest (t, serverType, serverFamily) {
5252
t.equal(Object.keys(server.torrents).length, 1)
5353
t.equal(swarm.complete, 0)
5454
t.equal(swarm.incomplete, 1)
55-
t.equal(Object.keys(swarm.peers).length, 1)
55+
t.equal(Object.keys(swarm.peers.cache).length, 1)
5656

5757
var id = serverType === 'ws'
5858
? peerId.toString('hex')
5959
: hostname + ':6881'
6060

61-
t.equal(swarm.peers[id].type, serverType)
62-
t.equal(swarm.peers[id].ip, clientIp)
63-
t.equal(swarm.peers[id].peerId, peerId.toString('hex'))
64-
t.equal(swarm.peers[id].complete, false)
61+
var peer = swarm.peers.peek(id)
62+
t.equal(peer.type, serverType)
63+
t.equal(peer.ip, clientIp)
64+
t.equal(peer.peerId, peerId.toString('hex'))
65+
t.equal(peer.complete, false)
6566
if (serverType === 'ws') {
66-
t.equal(typeof swarm.peers[id].port, 'number')
67-
t.ok(swarm.peers[id].socket)
67+
t.equal(typeof peer.port, 'number')
68+
t.ok(peer.socket)
6869
} else {
69-
t.equal(swarm.peers[id].port, 6881)
70-
t.notOk(swarm.peers[id].socket)
70+
t.equal(peer.port, 6881)
71+
t.notOk(peer.socket)
7172
}
7273

7374
client1.complete()

0 commit comments

Comments
 (0)