@@ -74,54 +74,35 @@ export class FastTracker implements Tracker {
7474 debug ( "disconnect peer:" , Buffer . from ( peerId ) . toString ( "hex" ) ) ;
7575 }
7676
77- for ( const swarmContext of ( peer as InternalPeerContext ) . swarms ! ) {
78- const swarm = swarmContext . swarm ;
79- swarm . removePeer ( peer ) ;
80- if ( swarm . peers . size === 0 ) {
77+ for ( const swarm of this . _swarms . values ( ) ) {
78+ if ( ! swarm . removePeer ( peer ) ) {
79+ continue ;
80+ } else if ( swarm . peers . size === 0 ) {
8181 if ( debugEnabled ) {
8282 debug ( "disconnect peer: swarm removed (empty)" , Buffer . from ( swarm . infoHash ) . toString ( "hex" ) ) ;
8383 }
8484 this . _swarms . delete ( swarm . infoHash ) ;
85- } else if ( swarmContext . completed ) {
86- swarm . completedCount -- ;
8785 }
8886 }
8987
9088 peer . id = undefined ;
91- ( peer as InternalPeerContext ) . swarms = undefined ;
9289 }
9390
94- private processAnnounce ( json : any , peer : InternalPeerContext , completed : boolean = false ) {
91+ private processAnnounce ( json : any , peer : PeerContext , completed : boolean = false ) {
9592 const infoHash = json . info_hash ;
9693 const peerId = json . peer_id ;
9794
98- let swarmContext : SwarmContext | undefined ;
99-
10095 if ( peer . id === undefined ) {
10196 if ( typeof peerId !== "string" ) {
10297 throw new TrackerError ( "announce: peer_id field is missing or wrong" ) ;
10398 }
10499
105100 peer . id = peerId ;
106- peer . swarms = [ ] ;
107- } else {
108- if ( peer . id !== peerId ) {
109- throw new TrackerError ( "announce: different peer_id on the same connection" ) ;
110- }
111- swarmContext = peer . swarms ! . find ( s => s . swarm . infoHash === infoHash ) ;
101+ } else if ( peer . id !== peerId ) {
102+ throw new TrackerError ( "announce: different peer_id on the same connection" ) ;
112103 }
113104
114- if ( swarmContext === undefined ) {
115- swarmContext = this . addPeerToSwarm ( peer , infoHash ) ;
116- }
117-
118- const swarm = swarmContext . swarm ;
119- const swarmPeers = swarm . peersOrdered ;
120-
121- if ( ! swarmContext . completed && ( completed || json . left === 0 ) ) {
122- swarmContext . completed = true ;
123- swarm . completedCount ++ ;
124- }
105+ const swarm = this . processPeerInSwarm ( peer , infoHash , completed || json . left === 0 ) ;
125106
126107 peer . sendMessage ( {
127108 action : "announce" ,
@@ -131,10 +112,10 @@ export class FastTracker implements Tracker {
131112 incomplete : swarm . peers . size - swarm . completedCount ,
132113 } , peer ) ;
133114
134- this . sendOffersToPeers ( json , swarmPeers , peer , infoHash ) ;
115+ this . sendOffersToPeers ( json , swarm . peersOrdered , peer , infoHash ) ;
135116 }
136117
137- private addPeerToSwarm ( peer : InternalPeerContext , infoHash : any ) {
118+ private processPeerInSwarm ( peer : PeerContext , infoHash : any , completed : boolean ) {
138119 let swarm = this . _swarms . get ( infoHash ) ;
139120
140121 if ( swarm === undefined ) {
@@ -145,28 +126,31 @@ export class FastTracker implements Tracker {
145126 if ( debugEnabled ) {
146127 debug ( "announce: swarm created:" , Buffer . from ( infoHash ) . toString ( "hex" ) ) ;
147128 }
129+
148130 swarm = new Swarm ( infoHash ) ;
149131 this . _swarms . set ( infoHash , swarm ) ;
150132 }
151133
152- if ( debugEnabled ) {
153- debug ( "announce: peer" , Buffer . from ( peer . id ! ) . toString ( "hex" ) , "added to swarm" , Buffer . from ( infoHash ) . toString ( "hex" ) ) ;
134+ const peerAlreadyInSwarm = swarm . peers . get ( peer . id ! ) ;
135+ if ( peerAlreadyInSwarm === peer ) {
136+ if ( completed ) {
137+ swarm . setCompleted ( peer ) ;
138+ }
139+ return swarm ;
140+ } else if ( peerAlreadyInSwarm !== undefined ) {
141+ swarm . removePeer ( peerAlreadyInSwarm ) ;
154142 }
155143
156- const previousPeer = swarm . peers . get ( peer . id ! ) ;
157- if ( previousPeer !== undefined ) {
158- removePeerFromSwarm ( previousPeer , infoHash ) ;
144+ if ( debugEnabled ) {
145+ debug ( "announce: peer" , Buffer . from ( peer . id ! ) . toString ( "hex" ) , "added to swarm" , Buffer . from ( infoHash ) . toString ( "hex" ) ) ;
159146 }
160147
161- swarm . addPeer ( peer ) ;
162- const swarmContext = { completed : false , swarm : swarm } ;
163- peer . swarms ! . push ( swarmContext ) ;
164-
165- return swarmContext ;
148+ swarm . addPeer ( peer , completed ) ;
149+ return swarm ;
166150 }
167151
168152 // tslint:disable-next-line:cognitive-complexity
169- private sendOffersToPeers ( json : any , peers : ReadonlyArray < InternalPeerContext > , peer : InternalPeerContext , infoHash : string ) {
153+ private sendOffersToPeers ( json : any , peers : ReadonlyArray < PeerContext > , peer : PeerContext , infoHash : string ) {
170154 if ( peers . length <= 1 ) {
171155 return ;
172156 }
@@ -217,22 +201,16 @@ export class FastTracker implements Tracker {
217201 debug ( "announce: sent offers" , countOffersToSend < 0 ? 0 : countOffersToSend ) ;
218202 }
219203
220- private processAnswer ( json : any , peer : InternalPeerContext ) {
204+ private processAnswer ( json : any , peer : PeerContext ) {
221205 const infoHash : string = json . info_hash ;
222- const peerSwarms = peer . swarms ;
223-
224- if ( peerSwarms === undefined ) {
225- throw new TrackerError ( "answer: peer is not in the swarm" ) ;
226- }
227-
228- const swarmContext = peerSwarms . find ( s => s . swarm . infoHash === infoHash ) ;
206+ const swarm = this . _swarms . get ( infoHash ) ;
229207
230- if ( swarmContext === undefined ) {
231- throw new TrackerError ( "answer: peer is not in the swarm" ) ;
208+ if ( swarm === undefined ) {
209+ throw new TrackerError ( "answer: no such swarm" ) ;
232210 }
233211
234212 const toPeerId = json . to_peer_id ;
235- const toPeer = swarmContext . swarm . peers . get ( toPeerId ) ;
213+ const toPeer = swarm . peers . get ( toPeerId ) ;
236214 if ( toPeer === undefined ) {
237215 throw new TrackerError ( "answer: to_peer_id is not in the swarm" ) ;
238216 }
@@ -245,7 +223,7 @@ export class FastTracker implements Tracker {
245223 }
246224 }
247225
248- private processStop ( json : any , peer : InternalPeerContext ) {
226+ private processStop ( json : any , peer : PeerContext ) {
249227 const peerId : string | undefined = json . peer_id ;
250228 if ( peer . id !== peerId ) {
251229 throw new TrackerError ( "stop event: different peer_id on the same connection" ) ;
@@ -257,7 +235,7 @@ export class FastTracker implements Tracker {
257235
258236 const infoHash : string = json . info_hash ;
259237
260- const swarm = removePeerFromSwarm ( peer , infoHash ) ;
238+ const swarm = this . _swarms . get ( infoHash ) ;
261239
262240 if ( swarm === undefined ) {
263241 debug ( "stop event: peer not in the swarm" ) ;
@@ -268,6 +246,7 @@ export class FastTracker implements Tracker {
268246 debug ( "stop event: peer" , Buffer . from ( peerId ) . toString ( "hex" ) , "remove from swarm" , Buffer . from ( infoHash ) . toString ( "hex" ) ) ;
269247 }
270248
249+ swarm . removePeer ( peer ) ;
271250 if ( swarm . peers . size === 0 ) {
272251 if ( debugEnabled ) {
273252 debug ( "stop event: swarm removed (empty)" , Buffer . from ( infoHash ) . toString ( "hex" ) ) ;
@@ -329,46 +308,62 @@ export class FastTracker implements Tracker {
329308 }
330309}
331310
332- interface SwarmContext {
333- completed : boolean ;
334- swarm : Swarm ;
335- }
336-
337- interface InternalPeerContext extends PeerContext {
338- swarms ?: SwarmContext [ ] ;
339- }
340-
341311// tslint:disable-next-line:max-classes-per-file
342312class Swarm {
343313 public completedCount = 0 ;
344314
345- private _peers = new Map < string , InternalPeerContext > ( ) ;
346- private _peersOrdered : InternalPeerContext [ ] = [ ] ;
315+ private _peers = new Map < string , PeerContext > ( ) ;
316+ private _peersOrdered : PeerContext [ ] = [ ] ;
317+ private isPeerCompleted : boolean [ ] = [ ] ;
347318
348319 constructor ( readonly infoHash : string ) { }
349320
350- public addPeer ( peer : InternalPeerContext ) {
321+ public addPeer ( peer : PeerContext , completed : boolean ) {
351322 const peerId = peer . id ! ;
352323 this . _peersOrdered . push ( peer ) ;
324+ this . isPeerCompleted . push ( completed ) ;
353325 this . _peers . set ( peerId , peer ) ;
326+ if ( completed ) {
327+ this . completedCount ++ ;
328+ }
354329 }
355330
356- public removePeer ( peer : InternalPeerContext ) {
357- this . _peers . delete ( peer . id ! ) ;
331+ public removePeer ( peer : PeerContext ) {
332+ if ( ! this . _peers . delete ( peer . id ! ) ) {
333+ return false ;
334+ }
358335
359- // Delete peerId from array without calling splice
360336 const index = this . _peersOrdered . indexOf ( peer ) ;
337+
338+ if ( this . isPeerCompleted [ index ] ) {
339+ this . completedCount -- ;
340+ }
341+
342+ // Delete peerId from arrays without calling splice
361343 const last = this . _peersOrdered . pop ( ) ! ;
344+ const lastIsCompleted = this . isPeerCompleted . pop ( ) ! ;
362345 if ( index < this . _peersOrdered . length ) {
363346 this . _peersOrdered [ index ] = last ;
347+ this . isPeerCompleted [ index ] = lastIsCompleted ;
348+ }
349+
350+ return true ;
351+ }
352+
353+ public setCompleted ( peer : PeerContext ) {
354+ const index = this . _peersOrdered . indexOf ( peer ) ;
355+
356+ if ( ! this . isPeerCompleted [ index ] ) {
357+ this . completedCount ++ ;
358+ this . isPeerCompleted [ index ] = true ;
364359 }
365360 }
366361
367- public get peers ( ) : ReadonlyMap < string , InternalPeerContext > {
362+ public get peers ( ) : ReadonlyMap < string , PeerContext > {
368363 return this . _peers ;
369364 }
370365
371- public get peersOrdered ( ) : ReadonlyArray < InternalPeerContext > {
366+ public get peersOrdered ( ) : ReadonlyArray < PeerContext > {
372367 return this . _peersOrdered ;
373368 }
374369}
@@ -396,28 +391,3 @@ function sendOffer(offerItem: {offer?: { sdp?: string }, offer_id?: string } | n
396391 } ,
397392 } , toPeer ) ;
398393}
399-
400- function removePeerFromSwarm ( peer : InternalPeerContext , infoHash : string ) : Swarm | undefined {
401- const peerSwarms = peer . swarms ! ;
402- const swarmIndex = peerSwarms . findIndex ( s => s . swarm . infoHash === infoHash ) ;
403-
404- if ( swarmIndex === - 1 ) {
405- return undefined ;
406- }
407-
408- const swarmContext = peerSwarms [ swarmIndex ] ;
409- const swarm = swarmContext . swarm ;
410-
411- swarm . removePeer ( peer ) ;
412- if ( swarmContext . completed ) {
413- swarm . completedCount -- ;
414- }
415-
416- // Delete swarm from array without calling splice
417- const last = peerSwarms . pop ( ) ! ;
418- if ( swarmIndex < peerSwarms . length ) {
419- peerSwarms [ swarmIndex ] = last ;
420- }
421-
422- return swarm ;
423- }
0 commit comments