Skip to content

Commit 03bed33

Browse files
committed
add webtorrent (websocket) tracker server
This PR merges webtorrent-tracker into this repo. Keeping the code in sync between the two repos was becoming burdensome. This change should not effect performance of the server since the webtorrent tracker is disabled by default. To enable the webtorrent tracker (disabled by default), do: ```js var server = new Server({ ws: true }) ```
1 parent 5c08723 commit 03bed33

File tree

7 files changed

+278
-80
lines changed

7 files changed

+278
-80
lines changed

client.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ var WebSocketTracker = require('./lib/websocket-tracker')
1414
inherits(Client, EventEmitter)
1515

1616
/**
17-
* A Client manages tracker connections for a torrent.
17+
* BitTorrent tracker client.
18+
*
19+
* Find torrent peers, to help a torrent client participate in a torrent swarm.
1820
*
1921
* @param {string} peerId peer id
2022
* @param {Number} port torrent client listening port

lib/parse_http.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ var common = require('./common')
44

55
var REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/
66

7-
function parseHttpRequest (req, options) {
8-
options = options || {}
7+
function parseHttpRequest (req, opts) {
8+
if (!opts) opts = {}
99
var s = req.url.split('?')
1010
var params = common.querystringParse(s[1])
1111

12-
if (options.action === 'announce' || s[0] === '/announce') {
12+
if (opts.action === 'announce' || s[0] === '/announce') {
1313
params.action = common.ACTIONS.ANNOUNCE
1414

1515
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
1616
throw new Error('invalid info_hash')
1717
}
1818
params.info_hash = common.binaryToHex(params.info_hash)
19+
1920
if (typeof params.peer_id !== 'string' || params.peer_id.length !== 20) {
2021
throw new Error('invalid peer_id')
2122
}
@@ -24,18 +25,18 @@ function parseHttpRequest (req, options) {
2425
params.port = Number(params.port)
2526
if (!params.port) throw new Error('invalid port')
2627

27-
params.left = Number(params.left)
28-
params.compact = Number(params.compact)
28+
params.left = Number(params.left) || Infinity
29+
params.compact = Number(params.compact) || 0
2930
params.numwant = Math.min(
3031
Number(params.numwant) || common.DEFAULT_ANNOUNCE_PEERS,
3132
common.MAX_ANNOUNCE_PEERS
3233
)
3334

34-
params.ip = options.trustProxy
35+
params.ip = opts.trustProxy
3536
? req.headers['x-forwarded-for'] || req.connection.remoteAddress
3637
: req.connection.remoteAddress.replace(REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
3738
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
38-
} else if (options.action === 'scrape' || s[0] === '/scrape') {
39+
} else if (opts.action === 'scrape' || s[0] === '/scrape') {
3940
params.action = common.ACTIONS.SCRAPE
4041
if (typeof params.info_hash === 'string') params.info_hash = [ params.info_hash ]
4142

@@ -48,7 +49,7 @@ function parseHttpRequest (req, options) {
4849
})
4950
}
5051
} else {
51-
throw new Error('Invalid action in HTTP request: ' + params.action)
52+
throw new Error('invalid action in HTTP request: ' + params.action)
5253
}
5354

5455
return params

lib/parse_websocket.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module.exports = parseWebSocketRequest
2+
3+
var common = require('./common')
4+
5+
function parseWebSocketRequest (socket, params) {
6+
params = JSON.parse(params) // may throw
7+
8+
params.action = common.ACTIONS.ANNOUNCE
9+
params.socket = socket
10+
11+
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
12+
throw new Error('invalid info_hash')
13+
}
14+
params.info_hash = common.binaryToHex(params.info_hash)
15+
16+
if (typeof params.peer_id !== 'string' || params.peer_id.length !== 20) {
17+
throw new Error('invalid peer_id')
18+
}
19+
params.peer_id = common.binaryToHex(params.peer_id)
20+
21+
if (params.answer &&
22+
(typeof params.to_peer_id !== 'string' || params.to_peer_id.length !== 20)) {
23+
throw new Error('invalid `to_peer_id` (required with `answer`)')
24+
}
25+
26+
params.left = Number(params.left) || Infinity
27+
params.numwant = Math.min(
28+
Number(params.offers && params.offers.length) || 0, // no default - explicit only
29+
common.MAX_ANNOUNCE_PEERS
30+
)
31+
32+
return params
33+
}

lib/swarm.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function Swarm (infoHash, server) {
1212

1313
Swarm.prototype.announce = function (params, cb) {
1414
var self = this
15-
var peer = self.peers[params.addr]
15+
var peer = self.peers[params.addr || params.peer_id]
1616

1717
// Dispatch announce event
1818
var fn = '_onAnnounce_' + params.event
@@ -24,13 +24,20 @@ Swarm.prototype.announce = function (params, cb) {
2424
cb(null, {
2525
complete: self.complete,
2626
incomplete: self.incomplete,
27-
peers: self._getPeers(params.numwant)
27+
peers: self._getPeers(params.numwant, params.peer_id)
2828
})
2929
} else {
3030
cb(new Error('invalid event'))
3131
}
3232
}
3333

34+
Swarm.prototype.scrape = function (params, cb) {
35+
cb(null, {
36+
complete: this.complete,
37+
incomplete: this.incomplete
38+
})
39+
}
40+
3441
Swarm.prototype._onAnnounce_started = function (params, peer) {
3542
if (peer) {
3643
debug('unexpected `started` event from peer that is already in swarm')
@@ -39,11 +46,12 @@ Swarm.prototype._onAnnounce_started = function (params, peer) {
3946

4047
if (params.left === 0) this.complete += 1
4148
else this.incomplete += 1
42-
peer = this.peers[params.addr] = {
43-
ip: params.ip,
44-
port: params.port,
49+
peer = this.peers[params.addr || params.peer_id] = {
50+
complete: false,
51+
ip: params.ip, // only http+udp
4552
peerId: params.peer_id,
46-
complete: false
53+
port: params.port, // only http+udp
54+
socket: params.socket // only websocket
4755
}
4856
}
4957

@@ -55,7 +63,7 @@ Swarm.prototype._onAnnounce_stopped = function (params, peer) {
5563

5664
if (peer.complete) this.complete -= 1
5765
else this.incomplete -= 1
58-
this.peers[params.addr] = null
66+
this.peers[params.addr || params.peer_id] = null
5967
}
6068

6169
Swarm.prototype._onAnnounce_completed = function (params, peer) {
@@ -80,24 +88,16 @@ Swarm.prototype._onAnnounce_update = function (params, peer) {
8088
}
8189
}
8290

83-
Swarm.prototype._getPeers = function (numwant) {
91+
// TODO: randomize the peers that are given out
92+
Swarm.prototype._getPeers = function (numWant, fromPeerId) {
8493
var peers = []
8594
for (var peerId in this.peers) {
86-
if (peers.length >= numwant) break
95+
if (peers.length >= numWant) break
96+
if (peerId === fromPeerId) continue // skip self
97+
8798
var peer = this.peers[peerId]
8899
if (!peer) continue // ignore null values
89-
peers.push({
90-
'peer id': peer.peerId,
91-
ip: peer.ip,
92-
port: peer.port
93-
})
100+
peers.push(peer)
94101
}
95102
return peers
96103
}
97-
98-
Swarm.prototype.scrape = function (params, cb) {
99-
cb(null, {
100-
complete: this.complete,
101-
incomplete: this.incomplete
102-
})
103-
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"simple-peer": "4.0.4",
3636
"simple-websocket": "1.0.4",
3737
"string2compact": "^1.1.1",
38+
"ws": "^0.7.1",
3839
"xtend": "4.0.0"
3940
},
4041
"devDependencies": {

0 commit comments

Comments
 (0)