Skip to content

Commit b5096e9

Browse files
committed
Support async createSwarm() and getSwarm()
Fix #95. Make server.getSwarm() and server.createSwarm() into async functions that take a callback.
1 parent 9d4c404 commit b5096e9

File tree

3 files changed

+119
-91
lines changed

3 files changed

+119
-91
lines changed

lib/server/swarm.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var debug = require('debug')('bittorrent-tracker')
44
var randomIterate = require('random-iterate')
55

66
// Regard this as the default implementation of an interface that you
7-
// need to support when overriding Server.getSwarm()
7+
// need to support when overriding Server.createSwarm() and Server.getSwarm()
88
function Swarm (infoHash, server) {
99
this.peers = {}
1010
this.complete = 0

server.js

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,23 @@ Server.prototype.close = function (cb) {
196196
else cb(null)
197197
}
198198

199-
Server.prototype.createSwarm = function (infoHash) {
199+
Server.prototype.createSwarm = function (infoHash, cb) {
200200
var self = this
201201
if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex')
202-
var swarm = self.torrents[infoHash] = new Swarm(infoHash, self)
203-
return swarm
202+
203+
process.nextTick(function () {
204+
var swarm = self.torrents[infoHash] = new Swarm(infoHash, self)
205+
cb(null, swarm)
206+
})
204207
}
205208

206-
Server.prototype.getSwarm = function (infoHash) {
209+
Server.prototype.getSwarm = function (infoHash, cb) {
207210
var self = this
208211
if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex')
209-
return self.torrents[infoHash]
212+
213+
process.nextTick(function () {
214+
cb(null, self.torrents[infoHash])
215+
})
210216
}
211217

212218
Server.prototype.onHttpRequest = function (req, res, opts) {
@@ -358,26 +364,35 @@ Server.prototype._onWebSocketRequest = function (socket, params) {
358364
if (params.answer) {
359365
debug('got answer %s from %s', JSON.stringify(params.answer), params.peer_id)
360366

361-
var swarm = self.getSwarm(params.info_hash)
362-
if (!swarm) {
363-
return self.emit('warning', new Error('no swarm with that `info_hash`'))
364-
}
365-
var toPeer = swarm.peers[params.to_peer_id]
366-
if (!toPeer) {
367-
return self.emit('warning', new Error('no peer with that `to_peer_id`'))
368-
}
367+
self.getSwarm(params.info_hash, function (err, swarm) {
368+
if (err) return self.emit('warning', err)
369+
if (!swarm) {
370+
return self.emit('warning', new Error('no swarm with that `info_hash`'))
371+
}
372+
var toPeer = swarm.peers[params.to_peer_id]
373+
if (!toPeer) {
374+
return self.emit('warning', new Error('no peer with that `to_peer_id`'))
375+
}
376+
377+
toPeer.socket.send(JSON.stringify({
378+
answer: params.answer,
379+
offer_id: params.offer_id,
380+
peer_id: common.hexToBinary(params.peer_id),
381+
info_hash: common.hexToBinary(params.info_hash)
382+
}), toPeer.socket.onSend)
383+
debug('sent answer to %s from %s', toPeer.peerId, params.peer_id)
369384

370-
toPeer.socket.send(JSON.stringify({
371-
answer: params.answer,
372-
offer_id: params.offer_id,
373-
peer_id: common.hexToBinary(params.peer_id),
374-
info_hash: common.hexToBinary(params.info_hash)
375-
}), toPeer.socket.onSend)
376-
debug('sent answer to %s from %s', toPeer.peerId, params.peer_id)
385+
done()
386+
})
387+
} else {
388+
done()
377389
}
378390

379-
if (params.action === common.ACTIONS.ANNOUNCE) {
380-
self.emit(common.EVENT_NAMES[params.event], params.peer_id, params)
391+
function done () {
392+
// emit event once the announce is fully "processed"
393+
if (params.action === common.ACTIONS.ANNOUNCE) {
394+
self.emit(common.EVENT_NAMES[params.event], params.peer_id, params)
395+
}
381396
}
382397
})
383398
}
@@ -398,9 +413,14 @@ Server.prototype._onRequest = function (params, cb) {
398413
Server.prototype._onAnnounce = function (params, cb) {
399414
var self = this
400415

401-
var swarm = self.getSwarm(params.info_hash)
402-
if (swarm) announce()
403-
else createSwarm()
416+
self.getSwarm(params.info_hash, function (err, swarm) {
417+
if (err) return cb(err)
418+
if (swarm) {
419+
announce(swarm)
420+
} else {
421+
createSwarm()
422+
}
423+
})
404424

405425
function createSwarm () {
406426
if (self._filter) {
@@ -410,17 +430,21 @@ Server.prototype._onAnnounce = function (params, cb) {
410430
} else if (!allowed) {
411431
cb(new Error('disallowed info_hash'))
412432
} else {
413-
swarm = self.createSwarm(params.info_hash)
414-
announce()
433+
self.createSwarm(params.info_hash, function (err, swarm) {
434+
if (err) return cb(err)
435+
announce(swarm)
436+
})
415437
}
416438
})
417439
} else {
418-
swarm = self.createSwarm(params.info_hash)
419-
announce()
440+
self.createSwarm(params.info_hash, function (err, swarm) {
441+
if (err) return cb(err)
442+
announce(swarm)
443+
})
420444
}
421445
}
422446

423-
function announce () {
447+
function announce (swarm) {
424448
if (!params.event || params.event === 'empty') params.event = 'update'
425449
swarm.announce(params, function (err, response) {
426450
if (err) return cb(err)
@@ -470,19 +494,21 @@ Server.prototype._onScrape = function (params, cb) {
470494

471495
series(params.info_hash.map(function (infoHash) {
472496
return function (cb) {
473-
var swarm = self.getSwarm(infoHash)
474-
if (swarm) {
475-
swarm.scrape(params, function (err, scrapeInfo) {
476-
if (err) return cb(err)
477-
cb(null, {
478-
infoHash: infoHash,
479-
complete: (scrapeInfo && scrapeInfo.complete) || 0,
480-
incomplete: (scrapeInfo && scrapeInfo.incomplete) || 0
497+
self.getSwarm(infoHash, function (err, swarm) {
498+
if (err) return cb(err)
499+
if (swarm) {
500+
swarm.scrape(params, function (err, scrapeInfo) {
501+
if (err) return cb(err)
502+
cb(null, {
503+
infoHash: infoHash,
504+
complete: (scrapeInfo && scrapeInfo.complete) || 0,
505+
incomplete: (scrapeInfo && scrapeInfo.incomplete) || 0
506+
})
481507
})
482-
})
483-
} else {
484-
cb(null, { infoHash: infoHash, complete: 0, incomplete: 0 })
485-
}
508+
} else {
509+
cb(null, { infoHash: infoHash, complete: 0, incomplete: 0 })
510+
}
511+
})
486512
}
487513
}), function (err, results) {
488514
if (err) return cb(err)

test/server.js

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ var peerId2 = new Buffer('12345678901234567890')
88
var torrentLength = 50000
99

1010
function serverTest (t, serverType, serverFamily) {
11-
t.plan(25)
11+
t.plan(26)
1212

1313
var opts = serverType === 'http' ? { udp: false, ws: false } : { http: false, ws: false }
1414
var server = new Server(opts)
@@ -49,65 +49,67 @@ function serverTest (t, serverType, serverFamily) {
4949
t.equal(data.complete, 0)
5050
t.equal(data.incomplete, 1)
5151

52-
var swarm = server.getSwarm(infoHash)
53-
54-
t.equal(Object.keys(server.torrents).length, 1)
55-
t.equal(swarm.complete, 0)
56-
t.equal(swarm.incomplete, 1)
57-
t.equal(Object.keys(swarm.peers).length, 1)
58-
t.deepEqual(swarm.peers[clientAddr + ':6881'], {
59-
ip: clientIp,
60-
port: 6881,
61-
peerId: peerId.toString('hex'),
62-
complete: false,
63-
socket: undefined
64-
})
52+
server.getSwarm(infoHash, function (err, swarm) {
53+
t.error(err)
54+
55+
t.equal(Object.keys(server.torrents).length, 1)
56+
t.equal(swarm.complete, 0)
57+
t.equal(swarm.incomplete, 1)
58+
t.equal(Object.keys(swarm.peers).length, 1)
59+
t.deepEqual(swarm.peers[clientAddr + ':6881'], {
60+
ip: clientIp,
61+
port: 6881,
62+
peerId: peerId.toString('hex'),
63+
complete: false,
64+
socket: undefined
65+
})
6566

66-
client1.complete()
67+
client1.complete()
6768

68-
client1.once('update', function (data) {
69-
t.equal(data.announce, announceUrl)
70-
t.equal(data.complete, 1)
71-
t.equal(data.incomplete, 0)
69+
client1.once('update', function (data) {
70+
t.equal(data.announce, announceUrl)
71+
t.equal(data.complete, 1)
72+
t.equal(data.incomplete, 0)
7273

73-
client1.scrape()
74+
client1.scrape()
7475

75-
client1.once('scrape', function (data) {
76-
t.equal(data.announce, announceUrl)
77-
t.equal(typeof data.complete, 'number')
78-
t.equal(typeof data.incomplete, 'number')
79-
t.equal(typeof data.downloaded, 'number')
80-
81-
var client2 = new Client(peerId2, 6882, {
82-
infoHash: infoHash,
83-
length: torrentLength,
84-
announce: [ announceUrl ]
85-
})
76+
client1.once('scrape', function (data) {
77+
t.equal(data.announce, announceUrl)
78+
t.equal(typeof data.complete, 'number')
79+
t.equal(typeof data.incomplete, 'number')
80+
t.equal(typeof data.downloaded, 'number')
8681

87-
client2.start()
82+
var client2 = new Client(peerId2, 6882, {
83+
infoHash: infoHash,
84+
length: torrentLength,
85+
announce: [ announceUrl ]
86+
})
8887

89-
server.once('start', function () {
90-
t.pass('got start message from client2')
91-
})
88+
client2.start()
9289

93-
client2.once('peer', function (addr) {
94-
t.ok(addr === clientAddr + ':6881' || addr === clientAddr + ':6882')
90+
server.once('start', function () {
91+
t.pass('got start message from client2')
92+
})
9593

96-
client2.stop()
97-
client2.once('update', function (data) {
98-
t.equal(data.announce, announceUrl)
99-
t.equal(data.complete, 1)
100-
t.equal(data.incomplete, 0)
101-
client2.destroy()
94+
client2.once('peer', function (addr) {
95+
t.ok(addr === clientAddr + ':6881' || addr === clientAddr + ':6882')
10296

103-
client1.stop()
104-
client1.once('update', function (data) {
97+
client2.stop()
98+
client2.once('update', function (data) {
10599
t.equal(data.announce, announceUrl)
106-
t.equal(data.complete, 0)
100+
t.equal(data.complete, 1)
107101
t.equal(data.incomplete, 0)
102+
client2.destroy()
103+
104+
client1.stop()
105+
client1.once('update', function (data) {
106+
t.equal(data.announce, announceUrl)
107+
t.equal(data.complete, 0)
108+
t.equal(data.incomplete, 0)
108109

109-
client1.destroy()
110-
server.close()
110+
client1.destroy()
111+
server.close()
112+
})
111113
})
112114
})
113115
})

0 commit comments

Comments
 (0)