mirror of
https://github.com/webtorrent/bittorrent-tracker.git
synced 2025-01-18 12:11:36 +00:00
massive cleanup
This commit is contained in:
parent
3746c05d79
commit
9db28c2fad
@ -111,7 +111,7 @@ var Server = require('bittorrent-tracker').Server
|
||||
var server = new Server({
|
||||
udp: true, // enable udp server? [default=true]
|
||||
http: true, // enable http server? [default=true]
|
||||
ws: true, // enable websocket server? [default=false]
|
||||
ws: true, // enable websocket server? [default=true]
|
||||
filter: function (infoHash, params, cb) {
|
||||
// Blacklist/whitelist function for allowing/disallowing torrents. If this option is
|
||||
// omitted, all torrents are allowed. It is possible to interface with a database or
|
||||
|
38
client.js
38
client.js
@ -1,10 +1,11 @@
|
||||
module.exports = Client
|
||||
|
||||
var debug = require('debug')('bittorrent-tracker')
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var debug = require('debug')('bittorrent-tracker')
|
||||
var inherits = require('inherits')
|
||||
var once = require('once')
|
||||
var parallel = require('run-parallel')
|
||||
var uniq = require('uniq')
|
||||
var url = require('url')
|
||||
|
||||
var common = require('./lib/common')
|
||||
@ -23,8 +24,6 @@ inherits(Client, EventEmitter)
|
||||
* @param {Number} port torrent client listening port
|
||||
* @param {Object} torrent parsed torrent
|
||||
* @param {Object} opts options object
|
||||
* @param {Number} opts.numwant number of peers to request
|
||||
* @param {Number} opts.interval announce interval (in ms)
|
||||
* @param {Number} opts.rtcConfig RTCPeerConnection configuration object
|
||||
* @param {Number} opts.wrtc custom webrtc implementation
|
||||
*/
|
||||
@ -55,13 +54,8 @@ function Client (peerId, port, torrent, opts) {
|
||||
self._rtcConfig = opts.rtcConfig
|
||||
self._wrtc = opts.wrtc
|
||||
|
||||
// optional
|
||||
self._numwant = opts.numwant || common.DEFAULT_ANNOUNCE_PEERS
|
||||
self._intervalMs = opts.interval || common.DEFAULT_ANNOUNCE_INTERVAL
|
||||
|
||||
debug('new client %s', self._infoHashHex)
|
||||
|
||||
var trackerOpts = { interval: self._intervalMs }
|
||||
var webrtcSupport = !!self._wrtc || typeof window !== 'undefined'
|
||||
|
||||
var announce = (typeof torrent.announce === 'string')
|
||||
@ -70,18 +64,27 @@ function Client (peerId, port, torrent, opts) {
|
||||
? []
|
||||
: torrent.announce
|
||||
|
||||
announce = announce.map(function (announceUrl) {
|
||||
announceUrl = announceUrl.toString()
|
||||
if (announceUrl[announceUrl.length - 1] === '/') {
|
||||
// remove trailing slash from trackers to catch duplicates
|
||||
announceUrl = announceUrl.substring(0, announceUrl.length - 1)
|
||||
}
|
||||
return announceUrl
|
||||
})
|
||||
|
||||
announce = uniq(announce)
|
||||
|
||||
self._trackers = announce
|
||||
.map(function (announceUrl) {
|
||||
announceUrl = announceUrl.toString()
|
||||
var protocol = url.parse(announceUrl).protocol
|
||||
|
||||
if ((protocol === 'http:' || protocol === 'https:') &&
|
||||
typeof HTTPTracker === 'function') {
|
||||
return new HTTPTracker(self, announceUrl, trackerOpts)
|
||||
return new HTTPTracker(self, announceUrl)
|
||||
} else if (protocol === 'udp:' && typeof UDPTracker === 'function') {
|
||||
return new UDPTracker(self, announceUrl, trackerOpts)
|
||||
return new UDPTracker(self, announceUrl)
|
||||
} else if ((protocol === 'ws:' || protocol === 'wss:') && webrtcSupport) {
|
||||
return new WebSocketTracker(self, announceUrl, trackerOpts)
|
||||
return new WebSocketTracker(self, announceUrl)
|
||||
} else {
|
||||
process.nextTick(function () {
|
||||
var err = new Error('unsupported tracker protocol for ' + announceUrl)
|
||||
@ -151,7 +154,7 @@ Client.prototype.start = function (opts) {
|
||||
|
||||
// start announcing on intervals
|
||||
self._trackers.forEach(function (tracker) {
|
||||
tracker.setInterval(self._intervalMs)
|
||||
tracker.setInterval()
|
||||
})
|
||||
}
|
||||
|
||||
@ -231,9 +234,7 @@ Client.prototype.scrape = function (opts) {
|
||||
|
||||
Client.prototype.setInterval = function (intervalMs) {
|
||||
var self = this
|
||||
debug('setInterval')
|
||||
self._intervalMs = intervalMs
|
||||
|
||||
debug('setInterval %d', intervalMs)
|
||||
self._trackers.forEach(function (tracker) {
|
||||
tracker.setInterval(intervalMs)
|
||||
})
|
||||
@ -248,7 +249,6 @@ Client.prototype.destroy = function (cb) {
|
||||
var tasks = self._trackers.map(function (tracker) {
|
||||
return function (cb) {
|
||||
tracker.destroy(cb)
|
||||
tracker.setInterval(0) // stop announcing on intervals
|
||||
}
|
||||
})
|
||||
|
||||
@ -260,7 +260,7 @@ Client.prototype._defaultAnnounceOpts = function (opts) {
|
||||
var self = this
|
||||
if (!opts) opts = {}
|
||||
|
||||
if (opts.numwant == null) opts.numwant = self._numwant
|
||||
if (opts.numwant == null) opts.numwant = common.DEFAULT_ANNOUNCE_PEERS
|
||||
|
||||
if (opts.uploaded == null) opts.uploaded = 0
|
||||
if (opts.downloaded == null) opts.downloaded = 0
|
||||
|
@ -12,6 +12,7 @@ var whitelist = {
|
||||
var server = new Server({
|
||||
http: false, // we do our own
|
||||
udp: false, // not interested
|
||||
ws: false, // not interested
|
||||
filter: function (params) {
|
||||
// black/whitelist for disallowing/allowing specific clients [default=allow all]
|
||||
// this example only allows the uTorrent client
|
||||
|
@ -3,15 +3,15 @@ module.exports = HTTPTracker
|
||||
var bencode = require('bencode')
|
||||
var compact2string = require('compact2string')
|
||||
var debug = require('debug')('bittorrent-tracker:http-tracker')
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var get = require('simple-get')
|
||||
var inherits = require('inherits')
|
||||
|
||||
var common = require('../common')
|
||||
var Tracker = require('./tracker')
|
||||
|
||||
var HTTP_SCRAPE_SUPPORT = /\/(announce)[^\/]*$/
|
||||
|
||||
inherits(HTTPTracker, EventEmitter)
|
||||
inherits(HTTPTracker, Tracker)
|
||||
|
||||
/**
|
||||
* HTTP torrent tracker client (for an individual tracker)
|
||||
@ -22,23 +22,15 @@ inherits(HTTPTracker, EventEmitter)
|
||||
*/
|
||||
function HTTPTracker (client, announceUrl, opts) {
|
||||
var self = this
|
||||
EventEmitter.call(self)
|
||||
Tracker.call(self, client, announceUrl)
|
||||
debug('new http tracker %s', announceUrl)
|
||||
|
||||
self.client = client
|
||||
self.destroyed = false
|
||||
|
||||
self._opts = opts
|
||||
self._announceUrl = announceUrl
|
||||
self._intervalMs = self.client._intervalMs // use client interval initially
|
||||
self._interval = null
|
||||
|
||||
// Determine scrape url (if http tracker supports it)
|
||||
self._scrapeUrl = null
|
||||
self.scrapeUrl = null
|
||||
var m
|
||||
if ((m = self._announceUrl.match(HTTP_SCRAPE_SUPPORT))) {
|
||||
self._scrapeUrl = self._announceUrl.slice(0, m.index) + '/scrape' +
|
||||
self._announceUrl.slice(m.index + 9)
|
||||
if ((m = self.announceUrl.match(HTTP_SCRAPE_SUPPORT))) {
|
||||
self.scrapeUrl = self.announceUrl.slice(0, m.index) + '/scrape' +
|
||||
self.announceUrl.slice(m.index + 9)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,15 +50,15 @@ HTTPTracker.prototype.announce = function (opts) {
|
||||
}
|
||||
if (self._trackerId) params.trackerid = self._trackerId
|
||||
|
||||
self._request(self._announceUrl, params, self._onAnnounceResponse.bind(self))
|
||||
self._request(self.announceUrl, params, self._onAnnounceResponse.bind(self))
|
||||
}
|
||||
|
||||
HTTPTracker.prototype.scrape = function (opts) {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
|
||||
if (!self._scrapeUrl) {
|
||||
self.client.emit('error', new Error('scrape not supported ' + self._announceUrl))
|
||||
if (!self.scrapeUrl) {
|
||||
self.client.emit('error', new Error('scrape not supported ' + self.announceUrl))
|
||||
return
|
||||
}
|
||||
|
||||
@ -78,44 +70,33 @@ HTTPTracker.prototype.scrape = function (opts) {
|
||||
var params = {
|
||||
info_hash: infoHashes
|
||||
}
|
||||
self._request(self._scrapeUrl, params, self._onScrapeResponse.bind(self))
|
||||
}
|
||||
|
||||
// TODO: Improve this interface
|
||||
HTTPTracker.prototype.setInterval = function (intervalMs) {
|
||||
var self = this
|
||||
self._intervalMs = intervalMs
|
||||
clearInterval(self._interval)
|
||||
|
||||
if (intervalMs) {
|
||||
// HACK
|
||||
var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
|
||||
self._interval = setInterval(update, self._intervalMs)
|
||||
}
|
||||
self._request(self.scrapeUrl, params, self._onScrapeResponse.bind(self))
|
||||
}
|
||||
|
||||
HTTPTracker.prototype.destroy = function (cb) {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
self.destroyed = true
|
||||
clearInterval(self.interval)
|
||||
|
||||
cb(null)
|
||||
}
|
||||
|
||||
HTTPTracker.prototype._request = function (requestUrl, params, cb) {
|
||||
var self = this
|
||||
|
||||
var u = requestUrl + (requestUrl.indexOf('?') === -1 ? '?' : '&') +
|
||||
common.querystringStringify(params)
|
||||
|
||||
get.concat(u, function (err, data, res) {
|
||||
if (self.destroyed) return
|
||||
if (err) return self.client.emit('warning', err)
|
||||
if (res.statusCode !== 200) {
|
||||
return self.client.emit('warning', new Error('Non-200 response code ' +
|
||||
res.statusCode + ' from ' + self._announceUrl))
|
||||
res.statusCode + ' from ' + self.announceUrl))
|
||||
}
|
||||
if (!data || data.length === 0) {
|
||||
return self.client.emit('warning', new Error('Invalid tracker response from' +
|
||||
self._announceUrl))
|
||||
self.announceUrl))
|
||||
}
|
||||
|
||||
try {
|
||||
@ -145,11 +126,7 @@ HTTPTracker.prototype._onAnnounceResponse = function (data) {
|
||||
var self = this
|
||||
|
||||
var interval = data.interval || data['min interval']
|
||||
if (interval && !self._opts.interval && self._intervalMs !== 0) {
|
||||
// use the interval the tracker recommends, UNLESS the user manually specifies an
|
||||
// interval they want to use
|
||||
self.setInterval(interval * 1000)
|
||||
}
|
||||
if (interval) self.setInterval(interval * 1000)
|
||||
|
||||
var trackerId = data['tracker id']
|
||||
if (trackerId) {
|
||||
@ -158,7 +135,7 @@ HTTPTracker.prototype._onAnnounceResponse = function (data) {
|
||||
}
|
||||
|
||||
self.client.emit('update', {
|
||||
announce: self._announceUrl,
|
||||
announce: self.announceUrl,
|
||||
complete: data.complete,
|
||||
incomplete: data.incomplete
|
||||
})
|
||||
@ -219,7 +196,7 @@ HTTPTracker.prototype._onScrapeResponse = function (data) {
|
||||
// TODO: optionally handle data.flags.min_request_interval
|
||||
// (separate from announce interval)
|
||||
self.client.emit('scrape', {
|
||||
announce: self._announceUrl,
|
||||
announce: self.announceUrl,
|
||||
infoHash: common.binaryToHex(infoHash),
|
||||
complete: response.complete,
|
||||
incomplete: response.incomplete,
|
||||
|
31
lib/client/tracker.js
Normal file
31
lib/client/tracker.js
Normal file
@ -0,0 +1,31 @@
|
||||
module.exports = Tracker
|
||||
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var inherits = require('inherits')
|
||||
|
||||
var common = require('../common')
|
||||
|
||||
inherits(Tracker, EventEmitter)
|
||||
|
||||
function Tracker (client, announceUrl) {
|
||||
var self = this
|
||||
EventEmitter.call(self)
|
||||
|
||||
self.client = client
|
||||
self.announceUrl = announceUrl
|
||||
self.interval = null
|
||||
self.destroyed = false
|
||||
}
|
||||
|
||||
Tracker.prototype.setInterval = function (intervalMs) {
|
||||
var self = this
|
||||
if (self.interval) return
|
||||
if (intervalMs == null) intervalMs = common.DEFAULT_ANNOUNCE_INTERVAL
|
||||
|
||||
clearInterval(self.interval)
|
||||
|
||||
if (intervalMs) {
|
||||
var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
|
||||
self.interval = setInterval(update, intervalMs)
|
||||
}
|
||||
}
|
@ -4,16 +4,16 @@ var BN = require('bn.js')
|
||||
var compact2string = require('compact2string')
|
||||
var debug = require('debug')('bittorrent-tracker:udp-tracker')
|
||||
var dgram = require('dgram')
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var hat = require('hat')
|
||||
var inherits = require('inherits')
|
||||
var url = require('url')
|
||||
|
||||
var common = require('../common')
|
||||
var Tracker = require('./tracker')
|
||||
|
||||
var TIMEOUT = 15000
|
||||
|
||||
inherits(UDPTracker, EventEmitter)
|
||||
inherits(UDPTracker, Tracker)
|
||||
|
||||
/**
|
||||
* UDP torrent tracker client (for an individual tracker)
|
||||
@ -24,17 +24,10 @@ inherits(UDPTracker, EventEmitter)
|
||||
*/
|
||||
function UDPTracker (client, announceUrl, opts) {
|
||||
var self = this
|
||||
EventEmitter.call(self)
|
||||
Tracker.call(self, client, announceUrl)
|
||||
debug('new udp tracker %s', announceUrl)
|
||||
|
||||
self.client = client
|
||||
self.destroyed = false
|
||||
|
||||
self._opts = opts
|
||||
self._announceUrl = announceUrl
|
||||
self._intervalMs = self.client._intervalMs // use client interval initially
|
||||
self._interval = null
|
||||
self._cleanupFns = []
|
||||
self.cleanupFns = []
|
||||
}
|
||||
|
||||
UDPTracker.prototype.announce = function (opts) {
|
||||
@ -50,41 +43,29 @@ UDPTracker.prototype.scrape = function (opts) {
|
||||
self._request(opts) // udp scrape uses same announce url
|
||||
}
|
||||
|
||||
// TODO: Improve this interface
|
||||
UDPTracker.prototype.setInterval = function (intervalMs) {
|
||||
var self = this
|
||||
clearInterval(self._interval)
|
||||
|
||||
self._intervalMs = intervalMs
|
||||
if (intervalMs) {
|
||||
// HACK
|
||||
var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
|
||||
self._interval = setInterval(update, self._intervalMs)
|
||||
}
|
||||
}
|
||||
|
||||
UDPTracker.prototype.destroy = function (cb) {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
self.destroyed = true
|
||||
clearInterval(self.interval)
|
||||
|
||||
self._cleanupFns.slice(0).forEach(function (cleanup) {
|
||||
self.cleanupFns.slice(0).forEach(function (cleanup) {
|
||||
cleanup()
|
||||
})
|
||||
self._cleanupFns = []
|
||||
self.cleanupFns = []
|
||||
cb(null)
|
||||
}
|
||||
|
||||
UDPTracker.prototype._request = function (opts) {
|
||||
var self = this
|
||||
if (!opts) opts = {}
|
||||
var parsedUrl = url.parse(self._announceUrl)
|
||||
var parsedUrl = url.parse(self.announceUrl)
|
||||
var transactionId = genTransactionId()
|
||||
var socket = dgram.createSocket('udp4')
|
||||
|
||||
var cleanup = function () {
|
||||
if (!socket) return
|
||||
self._cleanupFns.splice(self._cleanupFns.indexOf(cleanup), 1)
|
||||
self.cleanupFns.splice(self.cleanupFns.indexOf(cleanup), 1)
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
timeout = null
|
||||
@ -95,7 +76,7 @@ UDPTracker.prototype._request = function (opts) {
|
||||
try { socket.close() } catch (err) {}
|
||||
socket = null
|
||||
}
|
||||
self._cleanupFns.push(cleanup)
|
||||
self.cleanupFns.push(cleanup)
|
||||
|
||||
// does not matter if `stopped` event arrives, so supress errors & cleanup after timeout
|
||||
var ms = opts.event === 'stopped' ? TIMEOUT / 10 : TIMEOUT
|
||||
@ -122,7 +103,7 @@ UDPTracker.prototype._request = function (opts) {
|
||||
}
|
||||
|
||||
var action = msg.readUInt32BE(0)
|
||||
debug('UDP response %s, action %s', self._announceUrl, action)
|
||||
debug('UDP response %s, action %s', self.announceUrl, action)
|
||||
switch (action) {
|
||||
case 0: // handshake
|
||||
if (msg.length < 16) return onError(new Error('invalid udp handshake'))
|
||||
@ -137,14 +118,10 @@ UDPTracker.prototype._request = function (opts) {
|
||||
if (msg.length < 20) return onError(new Error('invalid announce message'))
|
||||
|
||||
var interval = msg.readUInt32BE(8)
|
||||
if (interval && !self._opts.interval && self._intervalMs !== 0) {
|
||||
// use the interval the tracker recommends, UNLESS the user manually specifies an
|
||||
// interval they want to use
|
||||
self.setInterval(interval * 1000)
|
||||
}
|
||||
if (interval) self.setInterval(interval * 1000)
|
||||
|
||||
self.client.emit('update', {
|
||||
announce: self._announceUrl,
|
||||
announce: self.announceUrl,
|
||||
complete: msg.readUInt32BE(16),
|
||||
incomplete: msg.readUInt32BE(12)
|
||||
})
|
||||
@ -171,7 +148,7 @@ UDPTracker.prototype._request = function (opts) {
|
||||
|
||||
for (var i = 0, len = (msg.length - 8) / 12; i < len; i += 1) {
|
||||
self.client.emit('scrape', {
|
||||
announce: self._announceUrl,
|
||||
announce: self.announceUrl,
|
||||
infoHash: infoHashes[i],
|
||||
complete: msg.readUInt32BE(8 + (i * 12)),
|
||||
downloaded: msg.readUInt32BE(12 + (i * 12)),
|
||||
@ -195,7 +172,7 @@ UDPTracker.prototype._request = function (opts) {
|
||||
function onError (err) {
|
||||
if (self.destroyed) return
|
||||
cleanup()
|
||||
if (err.message) err.message += ' (' + self._announceUrl + ')'
|
||||
if (err.message) err.message += ' (' + self.announceUrl + ')'
|
||||
// errors will often happen if a tracker is offline, so don't treat it as fatal
|
||||
self.client.emit('warning', err)
|
||||
}
|
||||
|
@ -3,13 +3,13 @@
|
||||
module.exports = WebSocketTracker
|
||||
|
||||
var debug = require('debug')('bittorrent-tracker:websocket-tracker')
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var hat = require('hat')
|
||||
var inherits = require('inherits')
|
||||
var Peer = require('simple-peer')
|
||||
var Socket = require('simple-websocket')
|
||||
|
||||
var common = require('../common')
|
||||
var Tracker = require('./tracker')
|
||||
|
||||
// Use a socket pool, so tracker clients share WebSocket objects for the same server.
|
||||
// In practice, WebSockets are pretty slow to establish, so this gives a nice performance
|
||||
@ -19,28 +19,15 @@ var socketPool = {}
|
||||
var RECONNECT_VARIANCE = 30 * 1000
|
||||
var RECONNECT_MINIMUM = 5 * 1000
|
||||
|
||||
inherits(WebSocketTracker, EventEmitter)
|
||||
inherits(WebSocketTracker, Tracker)
|
||||
|
||||
function WebSocketTracker (client, announceUrl, opts) {
|
||||
var self = this
|
||||
EventEmitter.call(self)
|
||||
Tracker.call(self, client, announceUrl)
|
||||
debug('new websocket tracker %s', announceUrl)
|
||||
|
||||
self.client = client
|
||||
self.destroyed = false
|
||||
|
||||
self._opts = opts
|
||||
|
||||
if (announceUrl[announceUrl.length - 1] === '/') {
|
||||
announceUrl = announceUrl.substring(0, announceUrl.length - 1)
|
||||
}
|
||||
self._announceUrl = announceUrl
|
||||
|
||||
self._peers = {} // peers (offer id -> peer)
|
||||
self._socket = null
|
||||
|
||||
self._intervalMs = self.client._intervalMs // use client interval initially
|
||||
self._interval = null
|
||||
self.peers = {} // peers (offer id -> peer)
|
||||
self.socket = null
|
||||
|
||||
self._openSocket()
|
||||
}
|
||||
@ -48,8 +35,8 @@ function WebSocketTracker (client, announceUrl, opts) {
|
||||
WebSocketTracker.prototype.announce = function (opts) {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
if (!self._socket.connected) {
|
||||
return self._socket.once('connect', self.announce.bind(self, opts))
|
||||
if (!self.socket.connected) {
|
||||
return self.socket.once('connect', self.announce.bind(self, opts))
|
||||
}
|
||||
|
||||
// TODO: Limit number of offers (temporarily)
|
||||
@ -75,43 +62,31 @@ WebSocketTracker.prototype.announce = function (opts) {
|
||||
WebSocketTracker.prototype.scrape = function (opts) {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
self._onSocketError(new Error('scrape not supported ' + self._announceUrl))
|
||||
}
|
||||
|
||||
// TODO: Improve this interface
|
||||
WebSocketTracker.prototype.setInterval = function (intervalMs) {
|
||||
var self = this
|
||||
clearInterval(self._interval)
|
||||
|
||||
self._intervalMs = intervalMs
|
||||
if (intervalMs) {
|
||||
// HACK
|
||||
var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
|
||||
self._interval = setInterval(update, self._intervalMs)
|
||||
}
|
||||
self._onSocketError(new Error('scrape not supported ' + self.announceUrl))
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype.destroy = function (onclose) {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
self.destroyed = true
|
||||
clearInterval(self.interval)
|
||||
|
||||
self._socket.removeListener('data', self._onSocketDataBound)
|
||||
self._socket.removeListener('close', self._onSocketCloseBound)
|
||||
self._socket.removeListener('error', self._onSocketErrorBound)
|
||||
self.socket.removeListener('data', self._onSocketDataBound)
|
||||
self.socket.removeListener('close', self._onSocketCloseBound)
|
||||
self.socket.removeListener('error', self._onSocketErrorBound)
|
||||
|
||||
self._onSocketErrorBound = null
|
||||
self._onSocketDataBound = null
|
||||
self._onSocketCloseBound = null
|
||||
|
||||
self._socket.on('error', noop) // ignore all future errors
|
||||
self.socket.on('error', noop) // ignore all future errors
|
||||
try {
|
||||
self._socket.destroy(onclose)
|
||||
self.socket.destroy(onclose)
|
||||
} catch (err) {
|
||||
if (onclose) onclose()
|
||||
}
|
||||
|
||||
self._socket = null
|
||||
self.socket = null
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype._openSocket = function () {
|
||||
@ -120,14 +95,14 @@ WebSocketTracker.prototype._openSocket = function () {
|
||||
self._onSocketDataBound = self._onSocketData.bind(self)
|
||||
self._onSocketCloseBound = self._onSocketClose.bind(self)
|
||||
|
||||
self._socket = socketPool[self._announceUrl]
|
||||
if (!self._socket) {
|
||||
self._socket = socketPool[self._announceUrl] = new Socket(self._announceUrl)
|
||||
self.socket = socketPool[self.announceUrl]
|
||||
if (!self.socket) {
|
||||
self.socket = socketPool[self.announceUrl] = new Socket(self.announceUrl)
|
||||
}
|
||||
|
||||
self._socket.on('data', self._onSocketDataBound)
|
||||
self._socket.on('close', self._onSocketCloseBound)
|
||||
self._socket.on('error', self._onSocketErrorBound)
|
||||
self.socket.on('data', self._onSocketDataBound)
|
||||
self.socket.on('close', self._onSocketCloseBound)
|
||||
self.socket.on('error', self._onSocketErrorBound)
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
@ -141,7 +116,7 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
if (data.info_hash !== self.client._infoHashBinary) {
|
||||
debug(
|
||||
'ignoring websocket data from %s for %s (looking for %s: reused socket)',
|
||||
self._announceUrl, common.binaryToHex(data.info_hash), self.client._infoHashHex
|
||||
self.announceUrl, common.binaryToHex(data.info_hash), self.client._infoHashHex
|
||||
)
|
||||
return
|
||||
}
|
||||
@ -153,7 +128,7 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
|
||||
debug(
|
||||
'received %s from %s for %s',
|
||||
JSON.stringify(data), self._announceUrl, self.client._infoHashHex
|
||||
JSON.stringify(data), self.announceUrl, self.client._infoHashHex
|
||||
)
|
||||
|
||||
var failure = data['failure reason']
|
||||
@ -163,11 +138,7 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
if (warning) self.client.emit('warning', new Error(warning))
|
||||
|
||||
var interval = data.interval || data['min interval']
|
||||
if (interval && !self._opts.interval && self._intervalMs !== 0) {
|
||||
// use the interval the tracker recommends, UNLESS the user manually specifies an
|
||||
// interval they want to use
|
||||
self.setInterval(interval * 1000)
|
||||
}
|
||||
if (interval) self.setInterval(interval * 1000)
|
||||
|
||||
var trackerId = data['tracker id']
|
||||
if (trackerId) {
|
||||
@ -177,7 +148,7 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
|
||||
if (data.complete) {
|
||||
self.client.emit('update', {
|
||||
announce: self._announceUrl,
|
||||
announce: self.announceUrl,
|
||||
complete: data.complete,
|
||||
incomplete: data.incomplete
|
||||
})
|
||||
@ -207,7 +178,7 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
}
|
||||
|
||||
if (data.answer && data.peer_id) {
|
||||
peer = self._peers[common.binaryToHex(data.offer_id)]
|
||||
peer = self.peers[common.binaryToHex(data.offer_id)]
|
||||
if (peer) {
|
||||
peer.id = common.binaryToHex(data.peer_id)
|
||||
peer.signal(data.answer)
|
||||
@ -253,7 +224,7 @@ WebSocketTracker.prototype._send = function (params) {
|
||||
|
||||
var message = JSON.stringify(params)
|
||||
debug('send %s', message)
|
||||
self._socket.send(message)
|
||||
self.socket.send(message)
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype._generateOffers = function (numwant, cb) {
|
||||
@ -261,14 +232,14 @@ WebSocketTracker.prototype._generateOffers = function (numwant, cb) {
|
||||
var offers = []
|
||||
debug('generating %s offers', numwant)
|
||||
|
||||
// TODO: cleanup dead peers and peers that never get a return offer, from self._peers
|
||||
// TODO: cleanup dead peers and peers that never get a return offer, from self.peers
|
||||
for (var i = 0; i < numwant; ++i) {
|
||||
generateOffer()
|
||||
}
|
||||
|
||||
function generateOffer () {
|
||||
var offerId = hat(160)
|
||||
var peer = self._peers[offerId] = new Peer({
|
||||
var peer = self.peers[offerId] = new Peer({
|
||||
initiator: true,
|
||||
trickle: false,
|
||||
config: self.client._rtcConfig,
|
||||
|
@ -5,7 +5,6 @@
|
||||
var extend = require('xtend/mutable')
|
||||
|
||||
exports.DEFAULT_ANNOUNCE_INTERVAL = 30 * 60 * 1000 // 30 minutes
|
||||
exports.DEFAULT_ANNOUNCE_INTERVAL_WEBRTC = 60 * 1000 // 1 minute
|
||||
|
||||
exports.DEFAULT_ANNOUNCE_PEERS = 50
|
||||
exports.MAX_ANNOUNCE_PEERS = 82
|
||||
|
@ -37,6 +37,7 @@
|
||||
"simple-peer": "^5.0.0",
|
||||
"simple-websocket": "^2.0.0",
|
||||
"string2compact": "^1.1.1",
|
||||
"uniq": "^1.0.1",
|
||||
"ws": "^0.7.1",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
|
@ -41,7 +41,7 @@ function Server (opts) {
|
||||
|
||||
debug('new server %s', JSON.stringify(opts))
|
||||
|
||||
self._intervalMs = opts.interval
|
||||
self.intervalMs = opts.interval
|
||||
? opts.interval
|
||||
: 10 * 60 * 1000 // 10 min
|
||||
|
||||
@ -316,7 +316,7 @@ Server.prototype._onWebSocketRequest = function (socket, params) {
|
||||
|
||||
var peers = response.peers
|
||||
delete response.peers
|
||||
response.interval = self._intervalMs
|
||||
response.interval = self.intervalMs
|
||||
response.info_hash = common.hexToBinary(params.info_hash)
|
||||
|
||||
socket.send(JSON.stringify(response), socket.onSend)
|
||||
@ -407,7 +407,7 @@ Server.prototype._onAnnounce = function (params, cb) {
|
||||
if (err) return cb(err)
|
||||
|
||||
if (!response.action) response.action = common.ACTIONS.ANNOUNCE
|
||||
if (!response.interval) response.interval = Math.ceil(self._intervalMs / 1000)
|
||||
if (!response.interval) response.interval = Math.ceil(self.intervalMs / 1000)
|
||||
|
||||
if (params.compact === 1) {
|
||||
var peers = response.peers
|
||||
@ -472,7 +472,7 @@ Server.prototype._onScrape = function (params, cb) {
|
||||
var response = {
|
||||
action: common.ACTIONS.SCRAPE,
|
||||
files: {},
|
||||
flags: { min_request_interval: Math.ceil(self._intervalMs / 1000) }
|
||||
flags: { min_request_interval: Math.ceil(self.intervalMs / 1000) }
|
||||
}
|
||||
|
||||
results.forEach(function (result) {
|
||||
|
@ -11,7 +11,7 @@ var peerId = new Buffer('01234567890123456789')
|
||||
test('large torrent: client.start()', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
var server = new Server({ http: false })
|
||||
var server = new Server({ http: false, ws: false })
|
||||
|
||||
server.on('error', function (err) {
|
||||
t.fail(err.message)
|
||||
|
@ -10,7 +10,7 @@ var peerId = new Buffer('01234567890123456789')
|
||||
test('magnet + udp: client.start/update/stop()', function (t) {
|
||||
t.plan(10)
|
||||
|
||||
var server = new Server({ http: false })
|
||||
var server = new Server({ http: false, ws: false })
|
||||
|
||||
server.on('error', function (err) {
|
||||
t.fail(err.message)
|
||||
|
@ -98,7 +98,8 @@ function testClientUpdate (t, serverType) {
|
||||
t.plan(4)
|
||||
common.createServer(t, serverType, function (server, announceUrl) {
|
||||
parsedTorrent.announce = [ announceUrl ]
|
||||
var client = new Client(peerId1, port, parsedTorrent, { interval: 2000 })
|
||||
var client = new Client(peerId1, port, parsedTorrent)
|
||||
client.setInterval(2000)
|
||||
|
||||
client.on('error', function (err) {
|
||||
t.error(err)
|
||||
@ -190,11 +191,11 @@ function testClientAnnounceWithNumWant (t, serverType) {
|
||||
})
|
||||
client2.start()
|
||||
client2.once('update', function () {
|
||||
var client3 = new Client(peerId3, port + 2, parsedTorrent, { numwant: 1 })
|
||||
var client3 = new Client(peerId3, port + 2, parsedTorrent)
|
||||
client3.on('error', function (err) {
|
||||
t.error(err)
|
||||
})
|
||||
client3.start()
|
||||
client3.start({ numwant: 1 })
|
||||
client3.on('peer', function () {
|
||||
t.pass('got one peer (this should only fire once)')
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
var Server = require('../').Server
|
||||
|
||||
exports.createServer = function (t, serverType, cb) {
|
||||
var opts = serverType === 'http' ? { udp: false } : { http: false }
|
||||
var opts = serverType === 'http' ? { udp: false, ws: false } : { http: false, ws: false }
|
||||
var server = new Server(opts)
|
||||
|
||||
server.on('error', function (err) {
|
||||
|
@ -14,7 +14,7 @@ var peerId = new Buffer('01234567890123456789')
|
||||
|
||||
function testFilterOption (t, serverType) {
|
||||
t.plan(8)
|
||||
var opts = serverType === 'http' ? { udp: false } : { http: false }
|
||||
var opts = serverType === 'http' ? { udp: false, ws: false } : { http: false, ws: false }
|
||||
opts.filter = function (infoHash, params, cb) {
|
||||
process.nextTick(function () {
|
||||
cb(infoHash !== parsedBitlove.infoHash)
|
||||
@ -92,7 +92,7 @@ test('udp: filter option blocks tracker from tracking torrent', function (t) {
|
||||
|
||||
function testFilterCustomError (t, serverType) {
|
||||
t.plan(8)
|
||||
var opts = serverType === 'http' ? { udp: false } : { http: false }
|
||||
var opts = serverType === 'http' ? { udp: false, ws: false } : { http: false, ws: false }
|
||||
opts.filter = function (infoHash, params, cb) {
|
||||
process.nextTick(function () {
|
||||
if (infoHash === parsedBitlove.infoHash) cb(new Error('bitlove blocked'))
|
||||
|
@ -109,7 +109,7 @@ test('udp: MULTI scrape using Client.scrape static method', function (t) {
|
||||
})
|
||||
|
||||
test('server: multiple info_hash scrape (manual http request)', function (t) {
|
||||
var server = new Server({ udp: false })
|
||||
var server = new Server({ udp: false, ws: false })
|
||||
server.on('error', function (err) {
|
||||
t.error(err)
|
||||
})
|
||||
@ -149,7 +149,7 @@ test('server: multiple info_hash scrape (manual http request)', function (t) {
|
||||
})
|
||||
|
||||
test('server: all info_hash scrape (manual http request)', function (t) {
|
||||
var server = new Server({ udp: false })
|
||||
var server = new Server({ udp: false, ws: false })
|
||||
server.on('error', function (err) {
|
||||
t.error(err)
|
||||
})
|
||||
|
@ -10,7 +10,7 @@ var torrentLength = 50000
|
||||
function serverTest (t, serverType, serverFamily) {
|
||||
t.plan(25)
|
||||
|
||||
var opts = serverType === 'http' ? { udp: false } : { http: false }
|
||||
var opts = serverType === 'http' ? { udp: false, ws: false } : { http: false, ws: false }
|
||||
var server = new Server(opts)
|
||||
var serverAddr = serverFamily === 'inet6' ? '[::1]' : '127.0.0.1'
|
||||
var clientAddr = serverFamily === 'inet6' ? '[::1]' : '127.0.0.1'
|
||||
|
Loading…
Reference in New Issue
Block a user