@@ -448,6 +448,7 @@ pub mod torrent;
448448
449449pub mod peer_tests;
450450
451+ use std:: cmp:: max;
451452use std:: collections:: HashMap ;
452453use std:: net:: IpAddr ;
453454use std:: panic:: Location ;
@@ -520,6 +521,38 @@ pub struct AnnounceData {
520521 pub policy : AnnouncePolicy ,
521522}
522523
524+ /// How many peers the peer announcing wants in the announce response.
525+ #[ derive( Clone , Debug , PartialEq , Default ) ]
526+ pub enum PeersWanted {
527+ /// The peer wants as many peers as possible in the announce response.
528+ #[ default]
529+ All ,
530+ /// The peer only wants a certain amount of peers in the announce response.
531+ Only { amount : usize } ,
532+ }
533+
534+ impl PeersWanted {
535+ fn limit ( & self ) -> usize {
536+ match self {
537+ PeersWanted :: All => TORRENT_PEERS_LIMIT ,
538+ PeersWanted :: Only { amount } => * amount,
539+ }
540+ }
541+ }
542+
543+ impl From < i32 > for PeersWanted {
544+ fn from ( value : i32 ) -> Self {
545+ if value > 0 {
546+ match value. try_into ( ) {
547+ Ok ( peers_wanted) => Self :: Only { amount : peers_wanted } ,
548+ Err ( _) => Self :: All ,
549+ }
550+ } else {
551+ Self :: All
552+ }
553+ }
554+ }
555+
523556/// Structure that holds the data returned by the `scrape` request.
524557#[ derive( Debug , PartialEq , Default ) ]
525558pub struct ScrapeData {
@@ -639,7 +672,13 @@ impl Tracker {
639672 /// # Context: Tracker
640673 ///
641674 /// BEP 03: [The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html).
642- pub fn announce ( & self , info_hash : & InfoHash , peer : & mut peer:: Peer , remote_client_ip : & IpAddr ) -> AnnounceData {
675+ pub fn announce (
676+ & self ,
677+ info_hash : & InfoHash ,
678+ peer : & mut peer:: Peer ,
679+ remote_client_ip : & IpAddr ,
680+ peers_wanted : & PeersWanted ,
681+ ) -> AnnounceData {
643682 // code-review: maybe instead of mutating the peer we could just return
644683 // a tuple with the new peer and the announce data: (Peer, AnnounceData).
645684 // It could even be a different struct: `StoredPeer` or `PublicPeer`.
@@ -661,7 +700,7 @@ impl Tracker {
661700
662701 let stats = self . upsert_peer_and_get_stats ( info_hash, peer) ;
663702
664- let peers = self . get_peers_for ( info_hash, peer) ;
703+ let peers = self . get_peers_for ( info_hash, peer, peers_wanted . limit ( ) ) ;
665704
666705 AnnounceData {
667706 peers,
@@ -713,16 +752,21 @@ impl Tracker {
713752 Ok ( ( ) )
714753 }
715754
716- fn get_peers_for ( & self , info_hash : & InfoHash , peer : & peer:: Peer ) -> Vec < Arc < peer:: Peer > > {
755+ /// # Context: Tracker
756+ ///
757+ /// Get torrent peers for a given torrent and client.
758+ ///
759+ /// It filters out the client making the request.
760+ fn get_peers_for ( & self , info_hash : & InfoHash , peer : & peer:: Peer , limit : usize ) -> Vec < Arc < peer:: Peer > > {
717761 match self . torrents . get ( info_hash) {
718762 None => vec ! [ ] ,
719- Some ( entry) => entry. get_peers_for_client ( & peer. peer_addr , Some ( TORRENT_PEERS_LIMIT ) ) ,
763+ Some ( entry) => entry. get_peers_for_client ( & peer. peer_addr , Some ( max ( limit , TORRENT_PEERS_LIMIT ) ) ) ,
720764 }
721765 }
722766
723767 /// # Context: Tracker
724768 ///
725- /// Get all torrent peers for a given torrent
769+ /// Get torrent peers for a given torrent.
726770 pub fn get_torrent_peers ( & self , info_hash : & InfoHash ) -> Vec < Arc < peer:: Peer > > {
727771 match self . torrents . get ( info_hash) {
728772 None => vec ! [ ] ,
@@ -1199,6 +1243,7 @@ mod tests {
11991243 use std:: sync:: Arc ;
12001244
12011245 use aquatic_udp_protocol:: { AnnounceEvent , NumberOfBytes , PeerId } ;
1246+ use torrust_tracker_configuration:: TORRENT_PEERS_LIMIT ;
12021247 use torrust_tracker_primitives:: info_hash:: InfoHash ;
12031248 use torrust_tracker_primitives:: DurationSinceUnixEpoch ;
12041249 use torrust_tracker_test_helpers:: configuration;
@@ -1350,7 +1395,7 @@ mod tests {
13501395
13511396 tracker. upsert_peer_and_get_stats ( & info_hash, & peer) ;
13521397
1353- let peers = tracker. get_peers_for ( & info_hash, & peer) ;
1398+ let peers = tracker. get_peers_for ( & info_hash, & peer, TORRENT_PEERS_LIMIT ) ;
13541399
13551400 assert_eq ! ( peers, vec![ ] ) ;
13561401 }
@@ -1409,6 +1454,7 @@ mod tests {
14091454 use crate :: core:: tests:: the_tracker:: {
14101455 peer_ip, public_tracker, sample_info_hash, sample_peer, sample_peer_1, sample_peer_2,
14111456 } ;
1457+ use crate :: core:: PeersWanted ;
14121458
14131459 mod should_assign_the_ip_to_the_peer {
14141460
@@ -1514,7 +1560,7 @@ mod tests {
15141560
15151561 let mut peer = sample_peer ( ) ;
15161562
1517- let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) ) ;
1563+ let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: All ) ;
15181564
15191565 assert_eq ! ( announce_data. peers, vec![ ] ) ;
15201566 }
@@ -1524,10 +1570,15 @@ mod tests {
15241570 let tracker = public_tracker ( ) ;
15251571
15261572 let mut previously_announced_peer = sample_peer_1 ( ) ;
1527- tracker. announce ( & sample_info_hash ( ) , & mut previously_announced_peer, & peer_ip ( ) ) ;
1573+ tracker. announce (
1574+ & sample_info_hash ( ) ,
1575+ & mut previously_announced_peer,
1576+ & peer_ip ( ) ,
1577+ & PeersWanted :: All ,
1578+ ) ;
15281579
15291580 let mut peer = sample_peer_2 ( ) ;
1530- let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) ) ;
1581+ let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: All ) ;
15311582
15321583 assert_eq ! ( announce_data. peers, vec![ Arc :: new( previously_announced_peer) ] ) ;
15331584 }
@@ -1537,14 +1588,15 @@ mod tests {
15371588 use crate :: core:: tests:: the_tracker:: {
15381589 completed_peer, leecher, peer_ip, public_tracker, sample_info_hash, seeder, started_peer,
15391590 } ;
1591+ use crate :: core:: PeersWanted ;
15401592
15411593 #[ tokio:: test]
15421594 async fn when_the_peer_is_a_seeder ( ) {
15431595 let tracker = public_tracker ( ) ;
15441596
15451597 let mut peer = seeder ( ) ;
15461598
1547- let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) ) ;
1599+ let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: All ) ;
15481600
15491601 assert_eq ! ( announce_data. stats. complete, 1 ) ;
15501602 }
@@ -1555,7 +1607,7 @@ mod tests {
15551607
15561608 let mut peer = leecher ( ) ;
15571609
1558- let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) ) ;
1610+ let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut peer, & peer_ip ( ) , & PeersWanted :: All ) ;
15591611
15601612 assert_eq ! ( announce_data. stats. incomplete, 1 ) ;
15611613 }
@@ -1566,10 +1618,11 @@ mod tests {
15661618
15671619 // We have to announce with "started" event because peer does not count if peer was not previously known
15681620 let mut started_peer = started_peer ( ) ;
1569- tracker. announce ( & sample_info_hash ( ) , & mut started_peer, & peer_ip ( ) ) ;
1621+ tracker. announce ( & sample_info_hash ( ) , & mut started_peer, & peer_ip ( ) , & PeersWanted :: All ) ;
15701622
15711623 let mut completed_peer = completed_peer ( ) ;
1572- let announce_data = tracker. announce ( & sample_info_hash ( ) , & mut completed_peer, & peer_ip ( ) ) ;
1624+ let announce_data =
1625+ tracker. announce ( & sample_info_hash ( ) , & mut completed_peer, & peer_ip ( ) , & PeersWanted :: All ) ;
15731626
15741627 assert_eq ! ( announce_data. stats. downloaded, 1 ) ;
15751628 }
@@ -1583,7 +1636,7 @@ mod tests {
15831636 use torrust_tracker_primitives:: info_hash:: InfoHash ;
15841637
15851638 use crate :: core:: tests:: the_tracker:: { complete_peer, incomplete_peer, public_tracker} ;
1586- use crate :: core:: { ScrapeData , SwarmMetadata } ;
1639+ use crate :: core:: { PeersWanted , ScrapeData , SwarmMetadata } ;
15871640
15881641 #[ tokio:: test]
15891642 async fn it_should_return_a_zeroed_swarm_metadata_for_the_requested_file_if_the_tracker_does_not_have_that_torrent (
@@ -1609,11 +1662,21 @@ mod tests {
16091662
16101663 // Announce a "complete" peer for the torrent
16111664 let mut complete_peer = complete_peer ( ) ;
1612- tracker. announce ( & info_hash, & mut complete_peer, & IpAddr :: V4 ( Ipv4Addr :: new ( 126 , 0 , 0 , 10 ) ) ) ;
1665+ tracker. announce (
1666+ & info_hash,
1667+ & mut complete_peer,
1668+ & IpAddr :: V4 ( Ipv4Addr :: new ( 126 , 0 , 0 , 10 ) ) ,
1669+ & PeersWanted :: All ,
1670+ ) ;
16131671
16141672 // Announce an "incomplete" peer for the torrent
16151673 let mut incomplete_peer = incomplete_peer ( ) ;
1616- tracker. announce ( & info_hash, & mut incomplete_peer, & IpAddr :: V4 ( Ipv4Addr :: new ( 126 , 0 , 0 , 11 ) ) ) ;
1674+ tracker. announce (
1675+ & info_hash,
1676+ & mut incomplete_peer,
1677+ & IpAddr :: V4 ( Ipv4Addr :: new ( 126 , 0 , 0 , 11 ) ) ,
1678+ & PeersWanted :: All ,
1679+ ) ;
16171680
16181681 // Scrape
16191682 let scrape_data = tracker. scrape ( & vec ! [ info_hash] ) . await ;
@@ -1740,7 +1803,7 @@ mod tests {
17401803 use crate :: core:: tests:: the_tracker:: {
17411804 complete_peer, incomplete_peer, peer_ip, sample_info_hash, whitelisted_tracker,
17421805 } ;
1743- use crate :: core:: ScrapeData ;
1806+ use crate :: core:: { PeersWanted , ScrapeData } ;
17441807
17451808 #[ test]
17461809 fn it_should_be_able_to_build_a_zeroed_scrape_data_for_a_list_of_info_hashes ( ) {
@@ -1761,11 +1824,11 @@ mod tests {
17611824 let info_hash = "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0" . parse :: < InfoHash > ( ) . unwrap ( ) ;
17621825
17631826 let mut peer = incomplete_peer ( ) ;
1764- tracker. announce ( & info_hash, & mut peer, & peer_ip ( ) ) ;
1827+ tracker. announce ( & info_hash, & mut peer, & peer_ip ( ) , & PeersWanted :: All ) ;
17651828
17661829 // Announce twice to force non zeroed swarm metadata
17671830 let mut peer = complete_peer ( ) ;
1768- tracker. announce ( & info_hash, & mut peer, & peer_ip ( ) ) ;
1831+ tracker. announce ( & info_hash, & mut peer, & peer_ip ( ) , & PeersWanted :: All ) ;
17691832
17701833 let scrape_data = tracker. scrape ( & vec ! [ info_hash] ) . await ;
17711834
0 commit comments