@@ -28,26 +28,24 @@ inherits(Tracker, EventEmitter)
2828 * An individual torrent tracker
2929 *
3030 * @param {Client } client parent bittorrent tracker client
31- * @param {string } announceUrl announce url of tracker
32- * @param {Number } interval interval in ms to send announce requests to the tracker
31+ * @param {string } announceUrl announce url of tracker
3332 * @param {Object } opts optional options
3433 */
35- function Tracker ( client , announceUrl , interval , opts ) {
34+ function Tracker ( client , announceUrl , opts ) {
3635 var self = this
37- if ( ! ( self instanceof Tracker ) ) return new Tracker ( client , announceUrl , interval , opts )
3836 EventEmitter . call ( self )
3937 self . _opts = opts || { }
40-
38+
4139 self . client = client
42-
40+
4341 self . _announceUrl = announceUrl
44- self . _intervalMs = interval
42+ self . _intervalMs = self . client . _intervalMs // use client interval initially
4543 self . _interval = null
46-
44+
4745 if ( self . _announceUrl . indexOf ( 'udp:' ) === 0 ) {
48- self . _requestImpl = self . _requestUdp . bind ( self )
46+ self . _requestImpl = self . _requestUdp
4947 } else {
50- self . _requestImpl = self . _requestHttp . bind ( self )
48+ self . _requestImpl = self . _requestHttp
5149 }
5250}
5351
@@ -56,7 +54,7 @@ Tracker.prototype.start = function (opts) {
5654 opts = opts || { }
5755 opts . event = 'started'
5856 self . _request ( opts )
59-
57+
6058 self . setInterval ( self . _intervalMs ) // start announcing on intervals
6159}
6260
@@ -65,7 +63,7 @@ Tracker.prototype.stop = function (opts) {
6563 opts = opts || { }
6664 opts . event = 'stopped'
6765 self . _request ( opts )
68-
66+
6967 self . setInterval ( 0 ) // stop announcing on intervals
7068}
7169
@@ -85,25 +83,25 @@ Tracker.prototype.update = function (opts) {
8583
8684Tracker . prototype . scrape = function ( opts ) {
8785 var self = this
88-
86+
8987 if ( ! self . _scrapeUrl ) {
9088 var announce = 'announce'
91- var i = self . _announceUrl . lastIndexOf ( '\ /' ) + 1
92-
89+ var i = self . _announceUrl . lastIndexOf ( '/' ) + 1
90+
9391 if ( i >= 1 && self . _announceUrl . slice ( i , i + announce . length ) === announce ) {
9492 self . _scrapeUrl = self . _announceUrl . slice ( 0 , i ) + 'scrape' + self . _announceUrl . slice ( i + announce . length )
9593 }
9694 }
97-
95+
9896 if ( ! self . _scrapeUrl ) {
9997 self . client . emit ( 'error' , new Error ( 'scrape not supported for announceUrl ' + self . _announceUrl ) )
10098 return
10199 }
102-
100+
103101 opts = extend ( {
104102 info_hash : bytewiseEncodeURIComponent ( self . client . _infoHash )
105103 } , opts )
106-
104+
107105 self . _requestImpl ( self . _scrapeUrl , opts )
108106}
109107
@@ -134,11 +132,11 @@ Tracker.prototype._request = function (opts) {
134132 uploaded : 0 , // default, user should provide real value
135133 downloaded : 0 // default, user should provide real value
136134 } , opts )
137-
135+
138136 if ( self . _trackerId ) {
139137 opts . trackerid = self . _trackerId
140138 }
141-
139+
142140 self . _requestImpl ( self . _announceUrl , opts )
143141}
144142
@@ -230,7 +228,7 @@ Tracker.prototype._requestUdp = function (requestUrl, opts) {
230228 clearTimeout ( timeout )
231229 socket . close ( )
232230 return
233-
231+
234232 case 2 : // scrape
235233 if ( message . length < 20 ) {
236234 return error ( 'invalid scrape message' )
@@ -259,7 +257,7 @@ Tracker.prototype._requestUdp = function (requestUrl, opts) {
259257 function genTransactionId ( ) {
260258 transactionId = new Buffer ( hat ( 32 ) , 'hex' )
261259 }
262-
260+
263261 function announce ( connectionId , opts ) {
264262 opts = opts || { }
265263 genTransactionId ( )
@@ -280,7 +278,7 @@ Tracker.prototype._requestUdp = function (requestUrl, opts) {
280278 toUInt16 ( self . client . _port || 0 )
281279 ] ) )
282280 }
283-
281+
284282 function scrape ( connectionId , opts ) {
285283 genTransactionId ( )
286284
@@ -316,7 +314,7 @@ Tracker.prototype._handleResponse = function (requestUrl, data) {
316314 if ( warning ) {
317315 self . client . emit ( 'warning' , warning ) ;
318316 }
319-
317+
320318 if ( requestUrl === self . _announceUrl ) {
321319 var interval = data . interval || data [ 'min interval' ]
322320 if ( interval && ! self . _opts . interval && self . _intervalMs !== 0 ) {
@@ -350,10 +348,10 @@ Tracker.prototype._handleResponse = function (requestUrl, data) {
350348 } )
351349 }
352350 } else if ( requestUrl === self . _scrapeUrl ) {
353- // note : the unofficial spec says to use the 'files' key but i've seen 'host' in practice
351+ // NOTE : the unofficial spec says to use the 'files' key but i've seen 'host' in practice
354352 data = data . files || data . host || { }
355353 data = data [ bytewiseEncodeURIComponent ( self . client . _infoHash ) ]
356-
354+
357355 if ( ! data ) {
358356 self . client . emit ( 'error' , new Error ( 'invalid scrape response' ) )
359357 } else {
@@ -402,7 +400,7 @@ function Client (peerId, port, torrent, opts) {
402400 self . _intervalMs = self . _opts . interval || ( 30 * 60 * 1000 ) // default: 30 minutes
403401
404402 self . _trackers = torrent . announce . map ( function ( announceUrl ) {
405- return Tracker ( self , announceUrl , self . _intervalMs , self . _opts )
403+ return new Tracker ( self , announceUrl , self . _opts )
406404 } )
407405}
408406
@@ -444,7 +442,7 @@ Client.prototype.scrape = function (opts) {
444442Client . prototype . setInterval = function ( intervalMs ) {
445443 var self = this
446444 self . _intervalMs = intervalMs
447-
445+
448446 self . _trackers . forEach ( function ( tracker ) {
449447 tracker . setInterval ( intervalMs )
450448 } )
@@ -523,27 +521,27 @@ Server.prototype._onHttpRequest = function (req, res) {
523521
524522 var warning
525523 var s = req . url . split ( '?' )
524+ var params = querystring . parse ( s [ 1 ] )
526525
527- if ( s [ 0 ] === '/announce' ) {
528- var params = querystring . parse ( s [ 1 ] )
526+ // TODO: detect when required params are missing
527+ // TODO: support multiple info_hash parameters as a concatenation of individual requests
528+ var infoHash = bytewiseDecodeURIComponent ( params . info_hash ) . toString ( 'hex' )
529+
530+ if ( ! infoHash ) {
531+ return error ( 'bittorrent-tracker server only supports announcing one torrent at a time' )
532+ }
529533
534+ if ( s [ 0 ] === '/announce' ) {
530535 var ip = self . _trustProxy
531536 ? req . headers [ 'x-forwarded-for' ] || req . connection . remoteAddress
532537 : req . connection . remoteAddress
533538 var port = Number ( params . port )
534539 var addr = ip + ':' + port
535-
536- // TODO: support multiple info_hash parameters as a concatenation of individual requests
537- var infoHash = bytewiseDecodeURIComponent ( params . info_hash ) . toString ( 'hex' )
538540 var peerId = bytewiseDecodeURIComponent ( params . peer_id ) . toString ( 'utf8' )
539-
540- if ( ! infoHash ) {
541- return error ( 'bittorrent-tracker server only supports announcing one torrent at a time' )
542- }
543-
541+
544542 var swarm = self . _getSwarm ( infoHash )
545543 var peer = swarm . peers [ addr ]
546-
544+
547545 switch ( params . event ) {
548546 case 'started' :
549547 if ( peer ) {
@@ -627,17 +625,11 @@ Server.prototype._onHttpRequest = function (req, res) {
627625 }
628626
629627 res . end ( bncode . encode ( response ) )
628+
630629 } else if ( s [ 0 ] === '/scrape' ) { // unofficial scrape message
631- var params = querystring . parse ( s [ 1 ] )
632- var infoHash = bytewiseDecodeURIComponent ( params . info_hash ) . toString ( 'hex' )
633-
634- if ( ! infoHash ) {
635- return error ( 'bittorrent-tracker server only supports scraping one torrent at a time' )
636- }
637-
638630 var swarm = self . _getSwarm ( infoHash )
639631 var response = { files : { } }
640-
632+
641633 response . files [ params . info_hash ] = {
642634 complete : swarm . complete ,
643635 incomplete : swarm . incomplete ,
@@ -646,7 +638,7 @@ Server.prototype._onHttpRequest = function (req, res) {
646638 min_request_interval : self . _interval
647639 }
648640 }
649-
641+
650642 res . end ( bncode . encode ( response ) )
651643 }
652644}
@@ -661,7 +653,7 @@ Server.prototype._getSwarm = function (infoHash) {
661653 peers : { }
662654 }
663655 }
664-
656+
665657 return swarm
666658}
667659
@@ -711,7 +703,9 @@ function toUInt32 (n) {
711703function toUInt64 ( n ) {
712704 if ( n > MAX_UINT || typeof n === 'string' ) {
713705 var bytes = bn ( n ) . toArray ( )
714- while ( bytes . length < 8 ) bytes . unshift ( 0 )
706+ while ( bytes . length < 8 ) {
707+ bytes . unshift ( 0 )
708+ }
715709 return new Buffer ( bytes )
716710 }
717711 return Buffer . concat ( [ toUInt32 ( 0 ) , toUInt32 ( n ) ] )
0 commit comments