mirror of
https://github.com/webtorrent/bittorrent-tracker.git
synced 2025-01-31 10:31:36 +00:00
BREAKING CHANGES
Breaking changes: - 'listening' event no longer emits with `port` param - `server.port` property removed (instead, use `server.http.address().port`) Added features: - expose http server as `server.http` - expose udp server as `server.udp` - client.destroy() - ungracefully leave the swarm - server: added `filter` option to black/whitelist torrents Bugfixes: - client considers udp tracker errors to be warnings - emit 'start', 'stop', 'update', etc. AFTER response sent - fix udp error response action and message being `undefined` Internal: - remove `portfinder` dep - add complete test for `filter` functionality
This commit is contained in:
parent
098ec7041c
commit
82e6792a6b
23
README.md
23
README.md
@ -87,6 +87,9 @@ client.update()
|
|||||||
// stop getting peers from the tracker, gracefully leave the swarm
|
// stop getting peers from the tracker, gracefully leave the swarm
|
||||||
client.stop()
|
client.stop()
|
||||||
|
|
||||||
|
// ungracefully leave the swarm (without sending final 'stop' message)
|
||||||
|
client.destroy()
|
||||||
|
|
||||||
// scrape
|
// scrape
|
||||||
client.scrape()
|
client.scrape()
|
||||||
|
|
||||||
@ -108,13 +111,17 @@ var Server = require('bittorrent-tracker').Server
|
|||||||
var server = new Server({
|
var server = new Server({
|
||||||
udp: true, // enable udp server? [default=true]
|
udp: true, // enable udp server? [default=true]
|
||||||
http: true, // enable http server? [default=true]
|
http: true, // enable http server? [default=true]
|
||||||
filter: function (hash) {
|
filter: function (infoHash) {
|
||||||
// specify white/blacklist for disallowing/allowing torrents
|
// black/whitelist for disallowing/allowing torrents [default=allow all]
|
||||||
return hash !== 'aaa67059ed6bd08362da625b3ae77f6f4a075aaa'
|
// this example only allows this one torrent
|
||||||
|
return infoHash === 'aaa67059ed6bd08362da625b3ae77f6f4a075aaa'
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Internal http and udp servers exposed as public properties.
|
||||||
|
server.http
|
||||||
|
server.udp
|
||||||
|
|
||||||
server.on('error', function (err) {
|
server.on('error', function (err) {
|
||||||
// fatal server error!
|
// fatal server error!
|
||||||
console.log(err.message)
|
console.log(err.message)
|
||||||
@ -125,11 +132,13 @@ server.on('warning', function (err) {
|
|||||||
console.log(err.message)
|
console.log(err.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
server.on('listening', function (port) {
|
server.on('listening', function () {
|
||||||
console.log('tracker server is now listening on ' + port)
|
// fired when all requested servers are listening
|
||||||
|
console.log('listening on http port:' + server.http.address().port)
|
||||||
|
console.log('listening on udp port:' + server.udp.address().port)
|
||||||
})
|
})
|
||||||
|
|
||||||
// start tracker server listening!
|
// start tracker server listening! Use 0 to listen on a random free port.
|
||||||
server.listen(port)
|
server.listen(port)
|
||||||
|
|
||||||
// listen for individual tracker messages from peers:
|
// listen for individual tracker messages from peers:
|
||||||
|
17
client.js
17
client.js
@ -128,6 +128,13 @@ Client.prototype.setInterval = function (intervalMs) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client.prototype.destroy = function () {
|
||||||
|
var self = this
|
||||||
|
self._trackers.forEach(function (tracker) {
|
||||||
|
tracker.destroy()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
inherits(Tracker, EventEmitter)
|
inherits(Tracker, EventEmitter)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,7 +182,7 @@ Tracker.prototype.stop = function (opts) {
|
|||||||
|
|
||||||
debug('sent `stop` %s', self._announceUrl)
|
debug('sent `stop` %s', self._announceUrl)
|
||||||
self._announce(opts)
|
self._announce(opts)
|
||||||
self.setInterval(0) // stop announcing on intervals
|
self.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
Tracker.prototype.complete = function (opts) {
|
Tracker.prototype.complete = function (opts) {
|
||||||
@ -196,6 +203,12 @@ Tracker.prototype.update = function (opts) {
|
|||||||
self._announce(opts)
|
self._announce(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tracker.prototype.destroy = function () {
|
||||||
|
var self = this
|
||||||
|
debug('destroy', self._announceUrl)
|
||||||
|
self.setInterval(0) // stop announcing on intervals
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send an announce request to the tracker.
|
* Send an announce request to the tracker.
|
||||||
* @param {Object} opts
|
* @param {Object} opts
|
||||||
@ -372,7 +385,7 @@ Tracker.prototype._requestUdp = function (requestUrl, opts) {
|
|||||||
if (msg.length < 8) {
|
if (msg.length < 8) {
|
||||||
return error('invalid error message')
|
return error('invalid error message')
|
||||||
}
|
}
|
||||||
self.client.emit('error', new Error(msg.slice(8).toString()))
|
self.client.emit('warning', new Error(msg.slice(8).toString()))
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -19,6 +19,12 @@ exports.EVENT_IDS = {
|
|||||||
2: 'started',
|
2: 'started',
|
||||||
3: 'stopped'
|
3: 'stopped'
|
||||||
}
|
}
|
||||||
|
exports.EVENT_NAMES = {
|
||||||
|
update: 'update',
|
||||||
|
completed: 'complete',
|
||||||
|
started: 'start',
|
||||||
|
stopped: 'stop'
|
||||||
|
}
|
||||||
|
|
||||||
function toUInt32 (n) {
|
function toUInt32 (n) {
|
||||||
var buf = new Buffer(4)
|
var buf = new Buffer(4)
|
||||||
|
@ -8,7 +8,6 @@ function Swarm (infoHash, server) {
|
|||||||
this.peers = {}
|
this.peers = {}
|
||||||
this.complete = 0
|
this.complete = 0
|
||||||
this.incomplete = 0
|
this.incomplete = 0
|
||||||
this.emit = server.emit.bind(server)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Swarm.prototype.announce = function (params, cb) {
|
Swarm.prototype.announce = function (params, cb) {
|
||||||
@ -16,7 +15,6 @@ Swarm.prototype.announce = function (params, cb) {
|
|||||||
var peer = self.peers[params.addr]
|
var peer = self.peers[params.addr]
|
||||||
|
|
||||||
// Dispatch announce event
|
// Dispatch announce event
|
||||||
if (!params.event || params.event === 'empty') params.event = 'update'
|
|
||||||
var fn = '_onAnnounce_' + params.event
|
var fn = '_onAnnounce_' + params.event
|
||||||
if (self[fn]) {
|
if (self[fn]) {
|
||||||
self[fn](params, peer) // process event
|
self[fn](params, peer) // process event
|
||||||
@ -46,7 +44,6 @@ Swarm.prototype._onAnnounce_started = function (params, peer) {
|
|||||||
port: params.port,
|
port: params.port,
|
||||||
peerId: params.peer_id
|
peerId: params.peer_id
|
||||||
}
|
}
|
||||||
this.emit('start', params.addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Swarm.prototype._onAnnounce_stopped = function (params, peer) {
|
Swarm.prototype._onAnnounce_stopped = function (params, peer) {
|
||||||
@ -58,7 +55,6 @@ Swarm.prototype._onAnnounce_stopped = function (params, peer) {
|
|||||||
if (peer.complete) this.complete -= 1
|
if (peer.complete) this.complete -= 1
|
||||||
else this.incomplete -= 1
|
else this.incomplete -= 1
|
||||||
this.peers[params.addr] = null
|
this.peers[params.addr] = null
|
||||||
this.emit('stop', params.addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Swarm.prototype._onAnnounce_completed = function (params, peer) {
|
Swarm.prototype._onAnnounce_completed = function (params, peer) {
|
||||||
@ -74,7 +70,6 @@ Swarm.prototype._onAnnounce_completed = function (params, peer) {
|
|||||||
this.complete += 1
|
this.complete += 1
|
||||||
this.incomplete -= 1
|
this.incomplete -= 1
|
||||||
peer.complete = true
|
peer.complete = true
|
||||||
this.emit('complete', params.addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Swarm.prototype._onAnnounce_update = function (params, peer) {
|
Swarm.prototype._onAnnounce_update = function (params, peer) {
|
||||||
@ -82,7 +77,6 @@ Swarm.prototype._onAnnounce_update = function (params, peer) {
|
|||||||
debug('unexpected `update` event from peer that is not in swarm')
|
debug('unexpected `update` event from peer that is not in swarm')
|
||||||
return this._onAnnounce_started(params, peer) // treat as a start
|
return this._onAnnounce_started(params, peer) // treat as a start
|
||||||
}
|
}
|
||||||
this.emit('update', params.addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Swarm.prototype._getPeers = function (numwant) {
|
Swarm.prototype._getPeers = function (numwant) {
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
"inherits": "^2.0.1",
|
"inherits": "^2.0.1",
|
||||||
"ip": "^0.3.0",
|
"ip": "^0.3.0",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"portfinder": "^0.3.0",
|
|
||||||
"run-series": "^1.0.2",
|
"run-series": "^1.0.2",
|
||||||
"simple-get": "^1.3.0",
|
"simple-get": "^1.3.0",
|
||||||
"string2compact": "^1.1.1"
|
"string2compact": "^1.1.1"
|
||||||
|
78
server.js
78
server.js
@ -6,7 +6,6 @@ var dgram = require('dgram')
|
|||||||
var EventEmitter = require('events').EventEmitter
|
var EventEmitter = require('events').EventEmitter
|
||||||
var http = require('http')
|
var http = require('http')
|
||||||
var inherits = require('inherits')
|
var inherits = require('inherits')
|
||||||
var portfinder = require('portfinder')
|
|
||||||
var series = require('run-series')
|
var series = require('run-series')
|
||||||
var string2compact = require('string2compact')
|
var string2compact = require('string2compact')
|
||||||
|
|
||||||
@ -15,9 +14,6 @@ var Swarm = require('./lib/swarm')
|
|||||||
var parseHttpRequest = require('./lib/parse_http')
|
var parseHttpRequest = require('./lib/parse_http')
|
||||||
var parseUdpRequest = require('./lib/parse_udp')
|
var parseUdpRequest = require('./lib/parse_udp')
|
||||||
|
|
||||||
// Use random port above 1024
|
|
||||||
portfinder.basePort = Math.floor(Math.random() * 60000) + 1025
|
|
||||||
|
|
||||||
inherits(Server, EventEmitter)
|
inherits(Server, EventEmitter)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,40 +36,41 @@ function Server (opts) {
|
|||||||
EventEmitter.call(self)
|
EventEmitter.call(self)
|
||||||
opts = opts || {}
|
opts = opts || {}
|
||||||
|
|
||||||
|
if (opts.http === false && opts.udp === false)
|
||||||
|
throw new Error('must start at least one type of server (http or udp)')
|
||||||
|
|
||||||
self._intervalMs = opts.interval
|
self._intervalMs = opts.interval
|
||||||
? opts.interval
|
? opts.interval
|
||||||
: 10 * 60 * 1000 // 10 min
|
: 10 * 60 * 1000 // 10 min
|
||||||
|
|
||||||
self._trustProxy = !!opts.trustProxy
|
self._trustProxy = !!opts.trustProxy
|
||||||
|
if (typeof opts.filter === 'function') self._filter = opts.filter
|
||||||
|
|
||||||
self.listening = false
|
self.listening = false
|
||||||
self.port = null
|
|
||||||
self.torrents = {}
|
self.torrents = {}
|
||||||
|
|
||||||
// default to starting an http server unless the user explictly says no
|
// default to starting an http server unless the user explictly says no
|
||||||
if (opts.http !== false) {
|
if (opts.http !== false) {
|
||||||
self._httpServer = http.createServer()
|
self.http = http.createServer()
|
||||||
self._httpServer.on('request', self.onHttpRequest.bind(self))
|
self.http.on('request', self.onHttpRequest.bind(self))
|
||||||
self._httpServer.on('error', self._onError.bind(self))
|
self.http.on('error', self._onError.bind(self))
|
||||||
self._httpServer.on('listening', onListening)
|
self.http.on('listening', onListening)
|
||||||
}
|
}
|
||||||
|
|
||||||
// default to starting a udp server unless the user explicitly says no
|
// default to starting a udp server unless the user explicitly says no
|
||||||
if (opts.udp !== false) {
|
if (opts.udp !== false) {
|
||||||
self._udpSocket = dgram.createSocket('udp4')
|
self.udp = dgram.createSocket('udp4')
|
||||||
self._udpSocket.on('message', self.onUdpRequest.bind(self))
|
self.udp.on('message', self.onUdpRequest.bind(self))
|
||||||
self._udpSocket.on('error', self._onError.bind(self))
|
self.udp.on('error', self._onError.bind(self))
|
||||||
self._udpSocket.on('listening', onListening)
|
self.udp.on('listening', onListening)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof opts.filter === 'function') self._filter = opts.filter
|
var num = !!self.http + !!self.udp
|
||||||
|
|
||||||
var num = !!self._httpServer + !!self._udpSocket
|
|
||||||
function onListening () {
|
function onListening () {
|
||||||
num -= 1
|
num -= 1
|
||||||
if (num === 0) {
|
if (num === 0) {
|
||||||
self.listening = true
|
self.listening = true
|
||||||
self.emit('listening', self.port)
|
self.emit('listening')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,28 +89,24 @@ Server.prototype.listen = function (port, onlistening) {
|
|||||||
if (self.listening) throw new Error('server already listening')
|
if (self.listening) throw new Error('server already listening')
|
||||||
if (onlistening) self.once('listening', onlistening)
|
if (onlistening) self.once('listening', onlistening)
|
||||||
|
|
||||||
function onPort (err, port) {
|
if (!port) port = 0
|
||||||
if (err) return self.emit('error', err)
|
|
||||||
self.port = port
|
|
||||||
// ATTENTION:
|
|
||||||
// binding to :: only receives IPv4 connections if the bindv6only
|
|
||||||
// sysctl is set 0, which is the default on many operating systems.
|
|
||||||
self._httpServer && self._httpServer.listen(port.http || port, '::')
|
|
||||||
self._udpSocket && self._udpSocket.bind(port.udp || port)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port) onPort(null, port)
|
// ATTENTION:
|
||||||
else portfinder.getPort(onPort)
|
// binding to :: only receives IPv4 connections if the bindv6only
|
||||||
|
// sysctl is set 0, which is the default on many operating systems.
|
||||||
|
self.http && self.http.listen(port.http || port, '::')
|
||||||
|
self.udp && self.udp.bind(port.udp || port)
|
||||||
}
|
}
|
||||||
|
|
||||||
Server.prototype.close = function (cb) {
|
Server.prototype.close = function (cb) {
|
||||||
var self = this
|
var self = this
|
||||||
|
self.listening = false
|
||||||
cb = cb || function () {}
|
cb = cb || function () {}
|
||||||
if (self._udpSocket) {
|
if (self.udp) {
|
||||||
self._udpSocket.close()
|
self.udp.close()
|
||||||
}
|
}
|
||||||
if (self._httpServer) {
|
if (self.http) {
|
||||||
self._httpServer.close(cb)
|
self.http.close(cb)
|
||||||
} else {
|
} else {
|
||||||
cb(null)
|
cb(null)
|
||||||
}
|
}
|
||||||
@ -122,7 +115,7 @@ Server.prototype.close = function (cb) {
|
|||||||
Server.prototype.getSwarm = function (infoHash) {
|
Server.prototype.getSwarm = function (infoHash) {
|
||||||
var self = this
|
var self = this
|
||||||
if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex')
|
if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex')
|
||||||
if (self._filter && self._filter(infoHash)) return null
|
if (self._filter && !self._filter(infoHash)) return null
|
||||||
var swarm = self.torrents[infoHash]
|
var swarm = self.torrents[infoHash]
|
||||||
if (!swarm) swarm = self.torrents[infoHash] = new Swarm(infoHash, this)
|
if (!swarm) swarm = self.torrents[infoHash] = new Swarm(infoHash, this)
|
||||||
return swarm
|
return swarm
|
||||||
@ -157,6 +150,10 @@ Server.prototype.onHttpRequest = function (req, res) {
|
|||||||
|
|
||||||
delete response.action // only needed for UDP encoding
|
delete response.action // only needed for UDP encoding
|
||||||
res.end(bencode.encode(response))
|
res.end(bencode.encode(response))
|
||||||
|
|
||||||
|
if (params.action === common.ACTIONS.ANNOUNCE) {
|
||||||
|
self.emit(common.EVENT_NAMES[params.event], params.addr)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,15 +174,21 @@ Server.prototype.onUdpRequest = function (msg, rinfo) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
self.emit('warning', err)
|
self.emit('warning', err)
|
||||||
response = {
|
response = {
|
||||||
action: common.ACTIONS.ERRROR,
|
action: common.ACTIONS.ERROR,
|
||||||
'failure reason': err.message
|
'failure reason': err.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!self.listening) return
|
||||||
|
|
||||||
response.transactionId = params.transactionId
|
response.transactionId = params.transactionId
|
||||||
response.connectionId = params.connectionId
|
response.connectionId = params.connectionId
|
||||||
|
|
||||||
var buf = makeUdpPacket(response)
|
var buf = makeUdpPacket(response)
|
||||||
self._udpSocket.send(buf, 0, buf.length, rinfo.port, rinfo.address)
|
self.udp.send(buf, 0, buf.length, rinfo.port, rinfo.address)
|
||||||
|
|
||||||
|
if (params.action === common.ACTIONS.ANNOUNCE) {
|
||||||
|
self.emit(common.EVENT_NAMES[params.event], params.addr)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +207,8 @@ Server.prototype._onRequest = function (params, cb) {
|
|||||||
Server.prototype._onAnnounce = function (params, cb) {
|
Server.prototype._onAnnounce = function (params, cb) {
|
||||||
var self = this
|
var self = this
|
||||||
var swarm = self.getSwarm(params.info_hash)
|
var swarm = self.getSwarm(params.info_hash)
|
||||||
if (swarm === null) return cb(new Error('invalid hash'))
|
if (swarm === null) return cb(new Error('disallowed info_hash'))
|
||||||
|
if (!params.event || params.event === 'empty') params.event = 'update'
|
||||||
swarm.announce(params, function (err, response) {
|
swarm.announce(params, function (err, response) {
|
||||||
if (response) {
|
if (response) {
|
||||||
if (!response.action) response.action = common.ACTIONS.ANNOUNCE
|
if (!response.action) response.action = common.ACTIONS.ANNOUNCE
|
||||||
@ -311,7 +315,7 @@ function makeUdpPacket (params) {
|
|||||||
packet = Buffer.concat([
|
packet = Buffer.concat([
|
||||||
common.toUInt32(common.ACTIONS.ERROR),
|
common.toUInt32(common.ACTIONS.ERROR),
|
||||||
common.toUInt32(params.transactionId || 0),
|
common.toUInt32(params.transactionId || 0),
|
||||||
new Buffer(params.message, 'utf8')
|
new Buffer(params['failure reason'], 'utf8')
|
||||||
])
|
])
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
var Client = require('../')
|
var Client = require('../')
|
||||||
var fs = require('fs')
|
var fs = require('fs')
|
||||||
var parseTorrent = require('parse-torrent')
|
var parseTorrent = require('parse-torrent')
|
||||||
var portfinder = require('portfinder')
|
|
||||||
var Server = require('../').Server
|
var Server = require('../').Server
|
||||||
var test = require('tape')
|
var test = require('tape')
|
||||||
|
|
||||||
@ -10,7 +9,7 @@ var parsedTorrent = parseTorrent(torrent)
|
|||||||
var peerId = new Buffer('01234567890123456789')
|
var peerId = new Buffer('01234567890123456789')
|
||||||
|
|
||||||
test('large torrent: client.start()', function (t) {
|
test('large torrent: client.start()', function (t) {
|
||||||
t.plan(6)
|
t.plan(5)
|
||||||
|
|
||||||
var server = new Server({ http: false })
|
var server = new Server({ http: false })
|
||||||
|
|
||||||
@ -22,9 +21,8 @@ test('large torrent: client.start()', function (t) {
|
|||||||
t.fail(err.message)
|
t.fail(err.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
portfinder.getPort(function (err, port) {
|
server.listen(0, function () {
|
||||||
t.error(err, 'found free port')
|
var port = server.udp.address().port
|
||||||
server.listen(port)
|
|
||||||
|
|
||||||
// remove all tracker servers except a single UDP one, for now
|
// remove all tracker servers except a single UDP one, for now
|
||||||
parsedTorrent.announce = [ 'udp://127.0.0.1:' + port ]
|
parsedTorrent.announce = [ 'udp://127.0.0.1:' + port ]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
var Client = require('../')
|
var Client = require('../')
|
||||||
var magnet = require('magnet-uri')
|
var magnet = require('magnet-uri')
|
||||||
var portfinder = require('portfinder')
|
|
||||||
var Server = require('../').Server
|
var Server = require('../').Server
|
||||||
var test = require('tape')
|
var test = require('tape')
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ var parsedTorrent = magnet(uri)
|
|||||||
var peerId = new Buffer('01234567890123456789')
|
var peerId = new Buffer('01234567890123456789')
|
||||||
|
|
||||||
test('magnet + udp: client.start/update/stop()', function (t) {
|
test('magnet + udp: client.start/update/stop()', function (t) {
|
||||||
t.plan(12)
|
t.plan(11)
|
||||||
|
|
||||||
var server = new Server({ http: false })
|
var server = new Server({ http: false })
|
||||||
|
|
||||||
@ -21,9 +20,8 @@ test('magnet + udp: client.start/update/stop()', function (t) {
|
|||||||
t.fail(err.message)
|
t.fail(err.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
portfinder.getPort(function (err, port) {
|
server.listen(0, function () {
|
||||||
t.error(err, 'found free port')
|
var port = server.udp.address().port
|
||||||
server.listen(port)
|
|
||||||
var announceUrl = 'udp://127.0.0.1:' + port
|
var announceUrl = 'udp://127.0.0.1:' + port
|
||||||
|
|
||||||
// remove all tracker servers except a single UDP one, for now
|
// remove all tracker servers except a single UDP one, for now
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
var portfinder = require('portfinder')
|
|
||||||
var Server = require('../').Server
|
var Server = require('../').Server
|
||||||
|
|
||||||
exports.createServer = function (t, serverType, cb) {
|
exports.createServer = function (t, serverType, cb) {
|
||||||
@ -13,14 +12,12 @@ exports.createServer = function (t, serverType, cb) {
|
|||||||
t.error(err)
|
t.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
portfinder.getPort(function (err, port) {
|
server.listen(0, function () {
|
||||||
if (err) return t.error(err)
|
var port = server[serverType].address().port
|
||||||
|
|
||||||
var announceUrl = serverType === 'http'
|
var announceUrl = serverType === 'http'
|
||||||
? 'http://127.0.0.1:' + port + '/announce'
|
? 'http://127.0.0.1:' + port + '/announce'
|
||||||
: 'udp://127.0.0.1:' + port
|
: 'udp://127.0.0.1:' + port
|
||||||
|
|
||||||
server.listen(port)
|
|
||||||
cb(server, announceUrl)
|
cb(server, announceUrl)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
85
test/filter.js
Normal file
85
test/filter.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
var Client = require('../')
|
||||||
|
var fs = require('fs')
|
||||||
|
var parseTorrent = require('parse-torrent')
|
||||||
|
var Server = require('../').Server
|
||||||
|
var test = require('tape')
|
||||||
|
|
||||||
|
var bitlove = fs.readFileSync(__dirname + '/torrents/bitlove-intro.torrent')
|
||||||
|
var parsedBitlove = parseTorrent(bitlove)
|
||||||
|
|
||||||
|
var leaves = fs.readFileSync(__dirname + '/torrents/leaves.torrent')
|
||||||
|
var parsedLeaves = parseTorrent(leaves)
|
||||||
|
|
||||||
|
var peerId = new Buffer('01234567890123456789')
|
||||||
|
|
||||||
|
function testFilterOption (t, serverType) {
|
||||||
|
t.plan(6)
|
||||||
|
var opts = serverType === 'http' ? { udp: false } : { http: false }
|
||||||
|
opts.filter = function (infoHash) {
|
||||||
|
return infoHash !== parsedBitlove.infoHash
|
||||||
|
}
|
||||||
|
var server = new Server(opts)
|
||||||
|
|
||||||
|
server.on('error', function (err) {
|
||||||
|
t.error(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
server.listen(0, function () {
|
||||||
|
var port = server[serverType].address().port
|
||||||
|
var announceUrl = serverType === 'http'
|
||||||
|
? 'http://127.0.0.1:' + port + '/announce'
|
||||||
|
: 'udp://127.0.0.1:' + port
|
||||||
|
|
||||||
|
parsedBitlove.announce = [ announceUrl ]
|
||||||
|
parsedLeaves.announce = [ announceUrl ]
|
||||||
|
|
||||||
|
var client = new Client(peerId, port, parsedBitlove)
|
||||||
|
|
||||||
|
client.on('error', function (err) {
|
||||||
|
t.error(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
client.once('warning', function (err) {
|
||||||
|
t.ok(/disallowed info_hash/.test(err.message), 'got client warning')
|
||||||
|
|
||||||
|
client.destroy()
|
||||||
|
client = new Client(peerId, port, parsedLeaves)
|
||||||
|
|
||||||
|
client.on('error', function (err) {
|
||||||
|
t.error(err)
|
||||||
|
})
|
||||||
|
client.on('warning', function (err) {
|
||||||
|
t.error(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on('update', function () {
|
||||||
|
t.pass('got announce')
|
||||||
|
client.destroy()
|
||||||
|
server.close(function () {
|
||||||
|
t.pass('server closed')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
server.on('start', function () {
|
||||||
|
t.equal(Object.keys(server.torrents).length, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
client.start()
|
||||||
|
})
|
||||||
|
|
||||||
|
server.once('warning', function (err) {
|
||||||
|
t.ok(/disallowed info_hash/.test(err.message), 'got server warning')
|
||||||
|
t.equal(Object.keys(server.torrents).length, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
client.start()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test('http: filter option blocks tracker from tracking torrent', function (t) {
|
||||||
|
testFilterOption(t, 'http')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('udp: filter option blocks tracker from tracking torrent', function (t) {
|
||||||
|
testFilterOption(t, 'udp')
|
||||||
|
})
|
188
test/scrape.js
188
test/scrape.js
@ -5,7 +5,6 @@ var commonTest = require('./common')
|
|||||||
var fs = require('fs')
|
var fs = require('fs')
|
||||||
var get = require('simple-get')
|
var get = require('simple-get')
|
||||||
var parseTorrent = require('parse-torrent')
|
var parseTorrent = require('parse-torrent')
|
||||||
var portfinder = require('portfinder')
|
|
||||||
var Server = require('../').Server
|
var Server = require('../').Server
|
||||||
var test = require('tape')
|
var test = require('tape')
|
||||||
|
|
||||||
@ -26,16 +25,14 @@ var peerId = new Buffer('01234567890123456789')
|
|||||||
|
|
||||||
function testSingle (t, serverType) {
|
function testSingle (t, serverType) {
|
||||||
commonTest.createServer(t, serverType, function (server, announceUrl) {
|
commonTest.createServer(t, serverType, function (server, announceUrl) {
|
||||||
server.once('listening', function () {
|
Client.scrape(announceUrl, infoHash1, function (err, data) {
|
||||||
Client.scrape(announceUrl, infoHash1, function (err, data) {
|
t.error(err)
|
||||||
t.error(err)
|
t.equal(data.announce, announceUrl)
|
||||||
t.equal(data.announce, announceUrl)
|
t.equal(typeof data.complete, 'number')
|
||||||
t.equal(typeof data.complete, 'number')
|
t.equal(typeof data.incomplete, 'number')
|
||||||
t.equal(typeof data.incomplete, 'number')
|
t.equal(typeof data.downloaded, 'number')
|
||||||
t.equal(typeof data.downloaded, 'number')
|
server.close(function () {
|
||||||
server.close(function () {
|
t.end()
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -51,16 +48,14 @@ test('udp: single info_hash scrape', function (t) {
|
|||||||
|
|
||||||
function clientScrapeStatic (t, serverType) {
|
function clientScrapeStatic (t, serverType) {
|
||||||
commonTest.createServer(t, serverType, function (server, announceUrl) {
|
commonTest.createServer(t, serverType, function (server, announceUrl) {
|
||||||
server.once('listening', function () {
|
Client.scrape(announceUrl, infoHash1, function (err, data) {
|
||||||
Client.scrape(announceUrl, infoHash1, function (err, data) {
|
t.error(err)
|
||||||
t.error(err)
|
t.equal(data.announce, announceUrl)
|
||||||
t.equal(data.announce, announceUrl)
|
t.equal(typeof data.complete, 'number')
|
||||||
t.equal(typeof data.complete, 'number')
|
t.equal(typeof data.incomplete, 'number')
|
||||||
t.equal(typeof data.incomplete, 'number')
|
t.equal(typeof data.downloaded, 'number')
|
||||||
t.equal(typeof data.downloaded, 'number')
|
server.close(function () {
|
||||||
server.close(function () {
|
t.end()
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -85,36 +80,32 @@ test('server: multiple info_hash scrape', function (t) {
|
|||||||
t.error(err)
|
t.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
portfinder.getPort(function (err, port) {
|
server.listen(0, function () {
|
||||||
t.error(err)
|
var port = server.http.address().port
|
||||||
server.listen(port)
|
|
||||||
var scrapeUrl = 'http://127.0.0.1:' + port + '/scrape'
|
var scrapeUrl = 'http://127.0.0.1:' + port + '/scrape'
|
||||||
|
var url = scrapeUrl + '?' + commonLib.querystringStringify({
|
||||||
|
info_hash: [ binaryInfoHash1, binaryInfoHash2 ]
|
||||||
|
})
|
||||||
|
get.concat(url, function (err, data, res) {
|
||||||
|
if (err) throw err
|
||||||
|
t.equal(res.statusCode, 200)
|
||||||
|
|
||||||
server.once('listening', function () {
|
data = bencode.decode(data)
|
||||||
var url = scrapeUrl + '?' + commonLib.querystringStringify({
|
t.ok(data.files)
|
||||||
info_hash: [ binaryInfoHash1, binaryInfoHash2 ]
|
t.equal(Object.keys(data.files).length, 2)
|
||||||
})
|
|
||||||
get.concat(url, function (err, data, res) {
|
|
||||||
if (err) throw err
|
|
||||||
t.equal(res.statusCode, 200)
|
|
||||||
|
|
||||||
data = bencode.decode(data)
|
t.ok(data.files[binaryInfoHash1])
|
||||||
t.ok(data.files)
|
t.equal(typeof data.files[binaryInfoHash1].complete, 'number')
|
||||||
t.equal(Object.keys(data.files).length, 2)
|
t.equal(typeof data.files[binaryInfoHash1].incomplete, 'number')
|
||||||
|
t.equal(typeof data.files[binaryInfoHash1].downloaded, 'number')
|
||||||
|
|
||||||
t.ok(data.files[binaryInfoHash1])
|
t.ok(data.files[binaryInfoHash2])
|
||||||
t.equal(typeof data.files[binaryInfoHash1].complete, 'number')
|
t.equal(typeof data.files[binaryInfoHash2].complete, 'number')
|
||||||
t.equal(typeof data.files[binaryInfoHash1].incomplete, 'number')
|
t.equal(typeof data.files[binaryInfoHash2].incomplete, 'number')
|
||||||
t.equal(typeof data.files[binaryInfoHash1].downloaded, 'number')
|
t.equal(typeof data.files[binaryInfoHash2].downloaded, 'number')
|
||||||
|
|
||||||
t.ok(data.files[binaryInfoHash2])
|
server.close(function () {
|
||||||
t.equal(typeof data.files[binaryInfoHash2].complete, 'number')
|
t.end()
|
||||||
t.equal(typeof data.files[binaryInfoHash2].incomplete, 'number')
|
|
||||||
t.equal(typeof data.files[binaryInfoHash2].downloaded, 'number')
|
|
||||||
|
|
||||||
server.close(function () {
|
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -129,100 +120,37 @@ test('server: all info_hash scrape', function (t) {
|
|||||||
t.error(err)
|
t.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
portfinder.getPort(function (err, port) {
|
server.listen(0, function () {
|
||||||
t.error(err)
|
var port = server.http.address().port
|
||||||
server.listen(port)
|
|
||||||
var announceUrl = 'http://127.0.0.1:' + port + '/announce'
|
var announceUrl = 'http://127.0.0.1:' + port + '/announce'
|
||||||
var scrapeUrl = 'http://127.0.0.1:' + port + '/scrape'
|
var scrapeUrl = 'http://127.0.0.1:' + port + '/scrape'
|
||||||
|
|
||||||
parsedBitlove.announce = [ announceUrl ]
|
parsedBitlove.announce = [ announceUrl ]
|
||||||
|
|
||||||
server.once('listening', function () {
|
// announce a torrent to the tracker
|
||||||
// announce a torrent to the tracker
|
var client = new Client(peerId, port, parsedBitlove)
|
||||||
var client = new Client(peerId, port, parsedBitlove)
|
client.on('error', function (err) {
|
||||||
client.on('error', function (err) {
|
t.error(err)
|
||||||
t.error(err)
|
|
||||||
})
|
|
||||||
client.start()
|
|
||||||
|
|
||||||
server.once('start', function () {
|
|
||||||
// now do a scrape of everything by omitting the info_hash param
|
|
||||||
get.concat(scrapeUrl, function (err, data, res) {
|
|
||||||
if (err) throw err
|
|
||||||
|
|
||||||
t.equal(res.statusCode, 200)
|
|
||||||
data = bencode.decode(data)
|
|
||||||
t.ok(data.files)
|
|
||||||
t.equal(Object.keys(data.files).length, 1)
|
|
||||||
|
|
||||||
t.ok(data.files[binaryBitlove])
|
|
||||||
t.equal(typeof data.files[binaryBitlove].complete, 'number')
|
|
||||||
t.equal(typeof data.files[binaryBitlove].incomplete, 'number')
|
|
||||||
t.equal(typeof data.files[binaryBitlove].downloaded, 'number')
|
|
||||||
|
|
||||||
client.stop()
|
|
||||||
server.close(function () {
|
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
client.start()
|
||||||
})
|
|
||||||
|
|
||||||
test('http nonwhitelisted torrent does not appear in scrape', function (t) {
|
server.once('start', function () {
|
||||||
var server = new Server({
|
// now do a scrape of everything by omitting the info_hash param
|
||||||
filter: function (hash) {
|
get.concat(scrapeUrl, function (err, data, res) {
|
||||||
return hash !== parsedBitlove
|
|
||||||
},
|
|
||||||
udp: false
|
|
||||||
})
|
|
||||||
|
|
||||||
server.on('error', function (err) {
|
|
||||||
t.error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
portfinder.getPort(function (err, port) {
|
|
||||||
t.error(err)
|
|
||||||
server.listen(port)
|
|
||||||
var announceUrl = 'http://127.0.0.1:' + port + '/announce'
|
|
||||||
var scrapeUrl = 'http://127.0.0.1:' + port + '/scrape'
|
|
||||||
|
|
||||||
parsedBitlove.announce = [ announceUrl ]
|
|
||||||
|
|
||||||
server.once('listening', function () {
|
|
||||||
var client = new Client(peerId, port, parsedBitlove)
|
|
||||||
|
|
||||||
client.start()
|
|
||||||
|
|
||||||
client.on('error', function (err) {
|
|
||||||
t.error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
server.once('warning', function (err) {
|
|
||||||
if (err) {
|
|
||||||
get.concat(scrapeUrl, function (err, data, res) {
|
|
||||||
if (err) throw err
|
|
||||||
|
|
||||||
t.equal(res.statusCode, 200)
|
|
||||||
data = bencode.decode(data)
|
|
||||||
t.ok(data.files)
|
|
||||||
|
|
||||||
t.notOk(data.files[binaryBitlove])
|
|
||||||
|
|
||||||
client.stop()
|
|
||||||
server.close(function () {
|
|
||||||
t.end()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
server.once('start', function (err) {
|
|
||||||
if (err) throw err
|
if (err) throw err
|
||||||
|
|
||||||
|
t.equal(res.statusCode, 200)
|
||||||
|
data = bencode.decode(data)
|
||||||
|
t.ok(data.files)
|
||||||
|
t.equal(Object.keys(data.files).length, 1)
|
||||||
|
|
||||||
|
t.ok(data.files[binaryBitlove])
|
||||||
|
t.equal(typeof data.files[binaryBitlove].complete, 'number')
|
||||||
|
t.equal(typeof data.files[binaryBitlove].incomplete, 'number')
|
||||||
|
t.equal(typeof data.files[binaryBitlove].downloaded, 'number')
|
||||||
|
|
||||||
client.stop()
|
client.stop()
|
||||||
server.close(function () {
|
server.close(function () {
|
||||||
t.fail('server should have thrown an error; filter condition was probably successful')
|
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -28,7 +28,8 @@ function serverTest (t, serverType, serverFamily) {
|
|||||||
t.pass('server listening')
|
t.pass('server listening')
|
||||||
})
|
})
|
||||||
|
|
||||||
server.listen(function (port) {
|
server.listen(0, function () {
|
||||||
|
var port = server[serverType].address().port
|
||||||
var announceUrl = serverType + '://' + serverAddr + ':' + port + '/announce'
|
var announceUrl = serverType + '://' + serverAddr + ':' + port + '/announce'
|
||||||
|
|
||||||
var client = new Client(peerId, 6881, {
|
var client = new Client(peerId, 6881, {
|
||||||
|
Loading…
Reference in New Issue
Block a user