diff --git a/src/app.rs b/src/app.rs index 67a319549..3f0e8d399 100644 --- a/src/app.rs +++ b/src/app.rs @@ -80,6 +80,7 @@ pub async fn start(config: &Configuration, app_container: &AppContainer) -> Vec< udp_tracker::start_job( udp_tracker_config, app_container.tracker.clone(), + app_container.scrape_handler.clone(), app_container.whitelist_authorization.clone(), app_container.stats_event_sender.clone(), app_container.ban_service.clone(), @@ -99,6 +100,7 @@ pub async fn start(config: &Configuration, app_container: &AppContainer) -> Vec< if let Some(job) = http_tracker::start_job( http_tracker_config, app_container.tracker.clone(), + app_container.scrape_handler.clone(), app_container.authentication_service.clone(), app_container.whitelist_authorization.clone(), app_container.stats_event_sender.clone(), diff --git a/src/bootstrap/app.rs b/src/bootstrap/app.rs index 294b2ca73..a0b6df3ca 100644 --- a/src/bootstrap/app.rs +++ b/src/bootstrap/app.rs @@ -26,6 +26,7 @@ use crate::core::authentication::handler::KeysHandler; use crate::core::authentication::key::repository::in_memory::InMemoryKeyRepository; use crate::core::authentication::key::repository::persisted::DatabaseKeyRepository; use crate::core::authentication::service; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::services::{initialize_database, initialize_tracker, initialize_whitelist_manager, statistics}; use crate::core::torrent::manager::TorrentsManager; use crate::core::torrent::repository::in_memory::InMemoryTorrentRepository; @@ -116,14 +117,16 @@ pub fn initialize_app_container(configuration: &Configuration) -> AppContainer { let tracker = Arc::new(initialize_tracker( configuration, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, )); + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + AppContainer { database, tracker, + scrape_handler, keys_handler, authentication_service, whitelist_authorization, diff --git a/src/bootstrap/jobs/http_tracker.rs b/src/bootstrap/jobs/http_tracker.rs index 92a255c9e..2e76e2f31 100644 --- a/src/bootstrap/jobs/http_tracker.rs +++ b/src/bootstrap/jobs/http_tracker.rs @@ -20,6 +20,7 @@ use tracing::instrument; use super::make_rust_tls; use crate::core::authentication::service::AuthenticationService; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{self, statistics, whitelist}; use crate::servers::http::server::{HttpServer, Launcher}; @@ -34,11 +35,20 @@ use crate::servers::registar::ServiceRegistrationForm; /// # Panics /// /// It would panic if the `config::HttpTracker` struct would contain inappropriate values. -/// -#[instrument(skip(config, tracker, authentication_service, whitelist_authorization, stats_event_sender, form))] +#[allow(clippy::too_many_arguments)] +#[instrument(skip( + config, + tracker, + scrape_handler, + authentication_service, + whitelist_authorization, + stats_event_sender, + form +))] pub async fn start_job( config: &HttpTracker, tracker: Arc, + scrape_handler: Arc, authentication_service: Arc, whitelist_authorization: Arc, stats_event_sender: Arc>>, @@ -57,6 +67,7 @@ pub async fn start_job( socket, tls, tracker.clone(), + scrape_handler.clone(), authentication_service.clone(), whitelist_authorization.clone(), stats_event_sender.clone(), @@ -67,12 +78,14 @@ pub async fn start_job( } } +#[allow(clippy::too_many_arguments)] #[allow(clippy::async_yields_async)] -#[instrument(skip(socket, tls, tracker, whitelist_authorization, stats_event_sender, form))] +#[instrument(skip(socket, tls, tracker, scrape_handler, whitelist_authorization, stats_event_sender, form))] async fn start_v1( socket: SocketAddr, tls: Option, tracker: Arc, + scrape_handler: Arc, authentication_service: Arc, whitelist_authorization: Arc, stats_event_sender: Arc>>, @@ -81,6 +94,7 @@ async fn start_v1( let server = HttpServer::new(Launcher::new(socket, tls)) .start( tracker, + scrape_handler, authentication_service, whitelist_authorization, stats_event_sender, @@ -128,6 +142,7 @@ mod tests { start_job( config, app_container.tracker, + app_container.scrape_handler, app_container.authentication_service, app_container.whitelist_authorization, app_container.stats_event_sender, diff --git a/src/bootstrap/jobs/udp_tracker.rs b/src/bootstrap/jobs/udp_tracker.rs index 724e2043e..dd55e4b8b 100644 --- a/src/bootstrap/jobs/udp_tracker.rs +++ b/src/bootstrap/jobs/udp_tracker.rs @@ -13,6 +13,7 @@ use tokio::task::JoinHandle; use torrust_tracker_configuration::UdpTracker; use tracing::instrument; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{self, whitelist}; use crate::servers::registar::ServiceRegistrationForm; @@ -32,10 +33,19 @@ use crate::servers::udp::UDP_TRACKER_LOG_TARGET; /// It will panic if the task did not finish successfully. #[must_use] #[allow(clippy::async_yields_async)] -#[instrument(skip(config, tracker, whitelist_authorization, stats_event_sender, ban_service, form))] +#[instrument(skip( + config, + tracker, + scrape_handler, + whitelist_authorization, + stats_event_sender, + ban_service, + form +))] pub async fn start_job( config: &UdpTracker, tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, stats_event_sender: Arc>>, ban_service: Arc>, @@ -47,6 +57,7 @@ pub async fn start_job( let server = Server::new(Spawner::new(bind_to)) .start( tracker, + scrape_handler, whitelist_authorization, stats_event_sender, ban_service, diff --git a/src/container.rs b/src/container.rs index 8407d0b69..a73862006 100644 --- a/src/container.rs +++ b/src/container.rs @@ -5,6 +5,7 @@ use tokio::sync::RwLock; use crate::core::authentication::handler::KeysHandler; use crate::core::authentication::service::AuthenticationService; use crate::core::databases::Database; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::statistics::repository::Repository; use crate::core::torrent::manager::TorrentsManager; @@ -17,6 +18,7 @@ use crate::servers::udp::server::banning::BanService; pub struct AppContainer { pub database: Arc>, pub tracker: Arc, + pub scrape_handler: Arc, pub keys_handler: Arc, pub authentication_service: Arc, pub whitelist_authorization: Arc, diff --git a/src/core/mod.rs b/src/core/mod.rs index 6ad48289f..064e8eb3e 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -442,6 +442,7 @@ pub mod authentication; pub mod databases; pub mod error; +pub mod scrape_handler; pub mod services; pub mod statistics; pub mod torrent; @@ -456,7 +457,7 @@ use bittorrent_primitives::info_hash::InfoHash; use torrent::repository::in_memory::InMemoryTorrentRepository; use torrent::repository::persisted::DatabasePersistentTorrentRepository; use torrust_tracker_configuration::{AnnouncePolicy, Core, TORRENT_PEERS_LIMIT}; -use torrust_tracker_primitives::core::{AnnounceData, ScrapeData}; +use torrust_tracker_primitives::core::AnnounceData; use torrust_tracker_primitives::peer; use torrust_tracker_primitives::swarm_metadata::SwarmMetadata; @@ -473,9 +474,6 @@ pub struct Tracker { /// The tracker configuration. config: Core, - /// The service to check is a torrent is whitelisted. - whitelist_authorization: Arc, - /// The in-memory torrents repository. in_memory_torrent_repository: Arc, @@ -533,13 +531,11 @@ impl Tracker { /// Will return a `databases::error::Error` if unable to connect to database. The `Tracker` is responsible for the persistence. pub fn new( config: &Core, - whitelist_authorization: &Arc, in_memory_torrent_repository: &Arc, db_torrent_repository: &Arc, ) -> Result { Ok(Tracker { config: config.clone(), - whitelist_authorization: whitelist_authorization.clone(), in_memory_torrent_repository: in_memory_torrent_repository.clone(), db_torrent_repository: db_torrent_repository.clone(), }) @@ -629,25 +625,6 @@ impl Tracker { } } - /// It handles a scrape request. - /// - /// # Context: Tracker - /// - /// BEP 48: [Tracker Protocol Extension: Scrape](https://www.bittorrent.org/beps/bep_0048.html). - pub async fn scrape(&self, info_hashes: &Vec) -> ScrapeData { - let mut scrape_data = ScrapeData::empty(); - - for info_hash in info_hashes { - let swarm_metadata = match self.whitelist_authorization.authorize(info_hash).await { - Ok(()) => self.in_memory_torrent_repository.get_swarm_metadata(info_hash), - Err(_) => SwarmMetadata::zeroed(), - }; - scrape_data.add_file(info_hash, swarm_metadata); - } - - scrape_data - } - /// It updates the torrent entry in memory, it also stores in the database /// the torrent info data which is persistent, and finally return the data /// needed for a `announce` request response. @@ -715,13 +692,14 @@ mod tests { use crate::app_test::initialize_tracker_dependencies; use crate::core::peer::Peer; + use crate::core::scrape_handler::ScrapeHandler; use crate::core::services::{initialize_tracker, initialize_whitelist_manager}; use crate::core::torrent::manager::TorrentsManager; use crate::core::torrent::repository::in_memory::InMemoryTorrentRepository; use crate::core::whitelist::manager::WhiteListManager; use crate::core::{whitelist, Tracker}; - fn public_tracker() -> Tracker { + fn public_tracker() -> (Arc, Arc) { let config = configuration::ephemeral_public(); let ( @@ -734,12 +712,15 @@ mod tests { _torrents_manager, ) = initialize_tracker_dependencies(&config); - initialize_tracker( + let tracker = Arc::new(initialize_tracker( &config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, - ) + )); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler) } fn public_tracker_and_in_memory_torrents_repository() -> (Arc, Arc) { @@ -748,7 +729,7 @@ mod tests { let ( _database, _in_memory_whitelist, - whitelist_authorization, + _whitelist_authorization, _authentication_service, in_memory_torrent_repository, db_torrent_repository, @@ -757,7 +738,6 @@ mod tests { let tracker = Arc::new(initialize_tracker( &config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, )); @@ -765,7 +745,12 @@ mod tests { (tracker, in_memory_torrent_repository) } - fn whitelisted_tracker() -> (Tracker, Arc, Arc) { + fn whitelisted_tracker() -> ( + Tracker, + Arc, + Arc, + Arc, + ) { let config = configuration::ephemeral_listed(); let ( @@ -780,14 +765,11 @@ mod tests { let whitelist_manager = initialize_whitelist_manager(database.clone(), in_memory_whitelist.clone()); - let tracker = initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ); + let tracker = initialize_tracker(&config, &in_memory_torrent_repository, &db_torrent_repository); - (tracker, whitelist_authorization, whitelist_manager) + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, whitelist_authorization, whitelist_manager, scrape_handler) } pub fn tracker_persisting_torrents_in_database() -> (Tracker, Arc, Arc) { @@ -797,19 +779,14 @@ mod tests { let ( _database, _in_memory_whitelist, - whitelist_authorization, + _whitelist_authorization, _authentication_service, in_memory_torrent_repository, db_torrent_repository, torrents_manager, ) = initialize_tracker_dependencies(&config); - let tracker = initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ); + let tracker = initialize_tracker(&config, &in_memory_torrent_repository, &db_torrent_repository); (tracker, torrents_manager, in_memory_torrent_repository) } @@ -957,7 +934,7 @@ mod tests { #[tokio::test] async fn it_should_return_the_peers_for_a_given_torrent_excluding_a_given_peer() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); let info_hash = sample_info_hash(); let peer = sample_peer(); @@ -973,7 +950,7 @@ mod tests { #[tokio::test] async fn it_should_return_74_peers_at_the_most_for_a_given_torrent_when_it_filters_out_a_given_peer() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); let info_hash = sample_info_hash(); @@ -1159,7 +1136,7 @@ mod tests { #[tokio::test] async fn it_should_return_the_announce_data_with_an_empty_peer_list_when_it_is_the_first_announced_peer() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); let mut peer = sample_peer(); @@ -1170,7 +1147,7 @@ mod tests { #[tokio::test] async fn it_should_return_the_announce_data_with_the_previously_announced_peers() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); let mut previously_announced_peer = sample_peer_1(); tracker.announce( @@ -1195,7 +1172,7 @@ mod tests { #[tokio::test] async fn when_the_peer_is_a_seeder() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); let mut peer = seeder(); @@ -1206,7 +1183,7 @@ mod tests { #[tokio::test] async fn when_the_peer_is_a_leecher() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); let mut peer = leecher(); @@ -1217,7 +1194,7 @@ mod tests { #[tokio::test] async fn when_a_previously_announced_started_peer_has_completed_downloading() { - let tracker = public_tracker(); + let (tracker, _scrape_handler) = public_tracker(); // We have to announce with "started" event because peer does not count if peer was not previously known let mut started_peer = started_peer(); @@ -1237,31 +1214,16 @@ mod tests { use std::net::{IpAddr, Ipv4Addr}; use bittorrent_primitives::info_hash::InfoHash; + use torrust_tracker_primitives::core::ScrapeData; use crate::core::tests::the_tracker::{complete_peer, incomplete_peer, public_tracker}; - use crate::core::{PeersWanted, ScrapeData, SwarmMetadata}; - - #[tokio::test] - async fn it_should_return_a_zeroed_swarm_metadata_for_the_requested_file_if_the_tracker_does_not_have_that_torrent( - ) { - let tracker = public_tracker(); - - let info_hashes = vec!["3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap()]; - - let scrape_data = tracker.scrape(&info_hashes).await; - - let mut expected_scrape_data = ScrapeData::empty(); - - expected_scrape_data.add_file_with_zeroed_metadata(&info_hashes[0]); - - assert_eq!(scrape_data, expected_scrape_data); - } + use crate::core::{PeersWanted, SwarmMetadata}; #[tokio::test] async fn it_should_return_the_swarm_metadata_for_the_requested_file_if_the_tracker_has_that_torrent() { - let tracker = public_tracker(); + let (tracker, scrape_handler) = public_tracker(); - let info_hash = "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap(); + let info_hash = "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap(); // # DevSkim: ignore DS173237 // Announce a "complete" peer for the torrent let mut complete_peer = complete_peer(); @@ -1282,7 +1244,7 @@ mod tests { ); // Scrape - let scrape_data = tracker.scrape(&vec![info_hash]).await; + let scrape_data = scrape_handler.scrape(&vec![info_hash]).await; // The expected swarm metadata for the file let mut expected_scrape_data = ScrapeData::empty(); @@ -1297,24 +1259,6 @@ mod tests { assert_eq!(scrape_data, expected_scrape_data); } - - #[tokio::test] - async fn it_should_allow_scraping_for_multiple_torrents() { - let tracker = public_tracker(); - - let info_hashes = vec![ - "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap(), - "99c82bb73505a3c0b453f9fa0e881d6e5a32a0c1".parse::().unwrap(), - ]; - - let scrape_data = tracker.scrape(&info_hashes).await; - - let mut expected_scrape_data = ScrapeData::empty(); - expected_scrape_data.add_file_with_zeroed_metadata(&info_hashes[0]); - expected_scrape_data.add_file_with_zeroed_metadata(&info_hashes[1]); - - assert_eq!(scrape_data, expected_scrape_data); - } } } @@ -1325,7 +1269,7 @@ mod tests { #[tokio::test] async fn it_should_authorize_the_announce_and_scrape_actions_on_whitelisted_torrents() { - let (_tracker, whitelist_authorization, whitelist_manager) = whitelisted_tracker(); + let (_tracker, whitelist_authorization, whitelist_manager, _scrape_handler) = whitelisted_tracker(); let info_hash = sample_info_hash(); @@ -1338,7 +1282,7 @@ mod tests { #[tokio::test] async fn it_should_not_authorize_the_announce_and_scrape_actions_on_not_whitelisted_torrents() { - let (_tracker, whitelist_authorization, _whitelist_manager) = whitelisted_tracker(); + let (_tracker, whitelist_authorization, _whitelist_manager, _scrape_handler) = whitelisted_tracker(); let info_hash = sample_info_hash(); @@ -1357,7 +1301,7 @@ mod tests { #[tokio::test] async fn it_should_add_a_torrent_to_the_whitelist() { - let (_tracker, _whitelist_authorization, whitelist_manager) = whitelisted_tracker(); + let (_tracker, _whitelist_authorization, whitelist_manager, _scrape_handler) = whitelisted_tracker(); let info_hash = sample_info_hash(); @@ -1368,7 +1312,7 @@ mod tests { #[tokio::test] async fn it_should_remove_a_torrent_from_the_whitelist() { - let (_tracker, _whitelist_authorization, whitelist_manager) = whitelisted_tracker(); + let (_tracker, _whitelist_authorization, whitelist_manager, _scrape_handler) = whitelisted_tracker(); let info_hash = sample_info_hash(); @@ -1384,7 +1328,7 @@ mod tests { #[tokio::test] async fn it_should_load_the_whitelist_from_the_database() { - let (_tracker, _whitelist_authorization, whitelist_manager) = whitelisted_tracker(); + let (_tracker, _whitelist_authorization, whitelist_manager, _scrape_handler) = whitelisted_tracker(); let info_hash = sample_info_hash(); @@ -1406,12 +1350,13 @@ mod tests { mod handling_an_scrape_request { use bittorrent_primitives::info_hash::InfoHash; + use torrust_tracker_primitives::core::ScrapeData; use torrust_tracker_primitives::swarm_metadata::SwarmMetadata; use crate::core::tests::the_tracker::{ complete_peer, incomplete_peer, peer_ip, sample_info_hash, whitelisted_tracker, }; - use crate::core::{PeersWanted, ScrapeData}; + use crate::core::PeersWanted; #[test] fn it_should_be_able_to_build_a_zeroed_scrape_data_for_a_list_of_info_hashes() { @@ -1427,9 +1372,9 @@ mod tests { #[tokio::test] async fn it_should_return_the_zeroed_swarm_metadata_for_the_requested_file_if_it_is_not_whitelisted() { - let (tracker, _whitelist_authorization, _whitelist_manager) = whitelisted_tracker(); + let (tracker, _whitelist_authorization, _whitelist_manager, scrape_handler) = whitelisted_tracker(); - let info_hash = "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap(); + let info_hash = "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap(); // # DevSkim: ignore DS173237 let mut peer = incomplete_peer(); tracker.announce(&info_hash, &mut peer, &peer_ip(), &PeersWanted::All); @@ -1438,7 +1383,7 @@ mod tests { let mut peer = complete_peer(); tracker.announce(&info_hash, &mut peer, &peer_ip(), &PeersWanted::All); - let scrape_data = tracker.scrape(&vec![info_hash]).await; + let scrape_data = scrape_handler.scrape(&vec![info_hash]).await; // The expected zeroed swarm metadata for the file let mut expected_scrape_data = ScrapeData::empty(); diff --git a/src/core/scrape_handler.rs b/src/core/scrape_handler.rs new file mode 100644 index 000000000..47049ed71 --- /dev/null +++ b/src/core/scrape_handler.rs @@ -0,0 +1,108 @@ +use std::sync::Arc; + +use bittorrent_primitives::info_hash::InfoHash; +use torrust_tracker_primitives::core::ScrapeData; +use torrust_tracker_primitives::swarm_metadata::SwarmMetadata; + +use super::torrent::repository::in_memory::InMemoryTorrentRepository; +use super::whitelist; + +pub struct ScrapeHandler { + /// The service to check is a torrent is whitelisted. + whitelist_authorization: Arc, + + /// The in-memory torrents repository. + in_memory_torrent_repository: Arc, +} + +impl ScrapeHandler { + #[must_use] + pub fn new( + whitelist_authorization: &Arc, + in_memory_torrent_repository: &Arc, + ) -> Self { + Self { + whitelist_authorization: whitelist_authorization.clone(), + in_memory_torrent_repository: in_memory_torrent_repository.clone(), + } + } + + /// It handles a scrape request. + /// + /// # Context: Tracker + /// + /// BEP 48: [Tracker Protocol Extension: Scrape](https://www.bittorrent.org/beps/bep_0048.html). + pub async fn scrape(&self, info_hashes: &Vec) -> ScrapeData { + let mut scrape_data = ScrapeData::empty(); + + for info_hash in info_hashes { + let swarm_metadata = match self.whitelist_authorization.authorize(info_hash).await { + Ok(()) => self.in_memory_torrent_repository.get_swarm_metadata(info_hash), + Err(_) => SwarmMetadata::zeroed(), + }; + scrape_data.add_file(info_hash, swarm_metadata); + } + + scrape_data + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use bittorrent_primitives::info_hash::InfoHash; + use torrust_tracker_primitives::core::ScrapeData; + use torrust_tracker_test_helpers::configuration; + + use super::ScrapeHandler; + use crate::core::torrent::repository::in_memory::InMemoryTorrentRepository; + use crate::core::whitelist::repository::in_memory::InMemoryWhitelist; + use crate::core::whitelist::{self}; + + fn scrape_handler() -> ScrapeHandler { + let config = configuration::ephemeral_public(); + + let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); + let whitelist_authorization = Arc::new(whitelist::authorization::Authorization::new( + &config.core, + &in_memory_whitelist.clone(), + )); + let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); + + ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository) + } + + #[tokio::test] + async fn it_should_return_a_zeroed_swarm_metadata_for_the_requested_file_if_the_tracker_does_not_have_that_torrent() { + let scrape_handler = scrape_handler(); + + let info_hashes = vec!["3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap()]; // # DevSkim: ignore DS173237 + + let scrape_data = scrape_handler.scrape(&info_hashes).await; + + let mut expected_scrape_data = ScrapeData::empty(); + + expected_scrape_data.add_file_with_zeroed_metadata(&info_hashes[0]); + + assert_eq!(scrape_data, expected_scrape_data); + } + + #[tokio::test] + async fn it_should_allow_scraping_for_multiple_torrents() { + let scrape_handler = scrape_handler(); + + let info_hashes = vec![ + "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap(), // # DevSkim: ignore DS173237 + "99c82bb73505a3c0b453f9fa0e881d6e5a32a0c1".parse::().unwrap(), // # DevSkim: ignore DS173237 + ]; + + let scrape_data = scrape_handler.scrape(&info_hashes).await; + + let mut expected_scrape_data = ScrapeData::empty(); + expected_scrape_data.add_file_with_zeroed_metadata(&info_hashes[0]); + expected_scrape_data.add_file_with_zeroed_metadata(&info_hashes[1]); + + assert_eq!(scrape_data, expected_scrape_data); + } +} diff --git a/src/core/services/mod.rs b/src/core/services/mod.rs index a9bca2df7..a6cf54d60 100644 --- a/src/core/services/mod.rs +++ b/src/core/services/mod.rs @@ -16,7 +16,6 @@ use torrust_tracker_configuration::Configuration; use super::databases::{self, Database}; use super::torrent::repository::in_memory::InMemoryTorrentRepository; use super::torrent::repository::persisted::DatabasePersistentTorrentRepository; -use super::whitelist; use super::whitelist::manager::WhiteListManager; use super::whitelist::repository::in_memory::InMemoryWhitelist; use super::whitelist::repository::persisted::DatabaseWhitelist; @@ -30,16 +29,10 @@ use crate::core::Tracker; #[must_use] pub fn initialize_tracker( config: &Configuration, - whitelist_authorization: &Arc, in_memory_torrent_repository: &Arc, db_torrent_repository: &Arc, ) -> Tracker { - match Tracker::new( - &Arc::new(config).core, - whitelist_authorization, - in_memory_torrent_repository, - db_torrent_repository, - ) { + match Tracker::new(&Arc::new(config).core, in_memory_torrent_repository, db_torrent_repository) { Ok(tracker) => tracker, Err(error) => { panic!("{}", error) diff --git a/src/core/services/statistics/mod.rs b/src/core/services/statistics/mod.rs index ea7ebe994..680504607 100644 --- a/src/core/services/statistics/mod.rs +++ b/src/core/services/statistics/mod.rs @@ -135,7 +135,7 @@ mod tests { let ( _database, _in_memory_whitelist, - whitelist_authorization, + _whitelist_authorization, _authentication_service, in_memory_torrent_repository, db_torrent_repository, @@ -147,7 +147,6 @@ mod tests { let _tracker = Arc::new(initialize_tracker( &config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, )); diff --git a/src/core/services/torrent.rs b/src/core/services/torrent.rs index dae619d62..8677096cc 100644 --- a/src/core/services/torrent.rs +++ b/src/core/services/torrent.rs @@ -127,7 +127,7 @@ mod tests { let ( _database, _in_memory_whitelist, - whitelist_authorization, + _whitelist_authorization, _authentication_service, in_memory_torrent_repository, db_torrent_repository, @@ -136,7 +136,6 @@ mod tests { let tracker = Arc::new(initialize_tracker( config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, )); diff --git a/src/servers/http/server.rs b/src/servers/http/server.rs index e7a3a92ec..573337ba9 100644 --- a/src/servers/http/server.rs +++ b/src/servers/http/server.rs @@ -12,6 +12,7 @@ use tracing::instrument; use super::v1::routes::router; use crate::bootstrap::jobs::Started; use crate::core::authentication::service::AuthenticationService; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::{statistics, whitelist, Tracker}; use crate::servers::custom_axum_server::{self, TimeoutAcceptor}; use crate::servers::http::HTTP_TRACKER_LOG_TARGET; @@ -43,9 +44,11 @@ pub struct Launcher { } impl Launcher { + #[allow(clippy::too_many_arguments)] #[instrument(skip( self, tracker, + scrape_handler, authentication_service, whitelist_authorization, stats_event_sender, @@ -55,6 +58,7 @@ impl Launcher { fn start( &self, tracker: Arc, + scrape_handler: Arc, authentication_service: Arc, whitelist_authorization: Arc, stats_event_sender: Arc>>, @@ -79,6 +83,7 @@ impl Launcher { let app = router( tracker, + scrape_handler, authentication_service, whitelist_authorization, stats_event_sender, @@ -179,6 +184,7 @@ impl HttpServer { pub async fn start( self, tracker: Arc, + scrape_handler: Arc, authentication_service: Arc, whitelist_authorization: Arc, stats_event_sender: Arc>>, @@ -192,6 +198,7 @@ impl HttpServer { let task = tokio::spawn(async move { let server = launcher.start( tracker, + scrape_handler, authentication_service, whitelist_authorization, stats_event_sender, @@ -296,6 +303,7 @@ mod tests { let started = stopped .start( app_container.tracker, + app_container.scrape_handler, app_container.authentication_service, app_container.whitelist_authorization, app_container.stats_event_sender, diff --git a/src/servers/http/v1/handlers/announce.rs b/src/servers/http/v1/handlers/announce.rs index a9567fb81..8b57ce543 100644 --- a/src/servers/http/v1/handlers/announce.rs +++ b/src/servers/http/v1/handlers/announce.rs @@ -289,7 +289,6 @@ mod tests { let tracker = Arc::new(initialize_tracker( config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, )); diff --git a/src/servers/http/v1/handlers/scrape.rs b/src/servers/http/v1/handlers/scrape.rs index 116d717a1..3c19fe324 100644 --- a/src/servers/http/v1/handlers/scrape.rs +++ b/src/servers/http/v1/handlers/scrape.rs @@ -17,6 +17,7 @@ use torrust_tracker_primitives::core::ScrapeData; use crate::core::authentication::service::AuthenticationService; use crate::core::authentication::Key; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::Tracker; use crate::servers::http::v1::extractors::authentication_key::Extract as ExtractKey; @@ -29,13 +30,27 @@ use crate::servers::http::v1::services; #[allow(clippy::unused_async)] #[allow(clippy::type_complexity)] pub async fn handle_without_key( - State(state): State<(Arc, Arc, Arc>>)>, + State(state): State<( + Arc, + Arc, + Arc, + Arc>>, + )>, ExtractRequest(scrape_request): ExtractRequest, ExtractClientIpSources(client_ip_sources): ExtractClientIpSources, ) -> Response { tracing::debug!("http scrape request: {:#?}", &scrape_request); - handle(&state.0, &state.1, &state.2, &scrape_request, &client_ip_sources, None).await + handle( + &state.0, + &state.1, + &state.2, + &state.3, + &scrape_request, + &client_ip_sources, + None, + ) + .await } /// It handles the `scrape` request when the HTTP tracker is configured @@ -45,18 +60,33 @@ pub async fn handle_without_key( #[allow(clippy::unused_async)] #[allow(clippy::type_complexity)] pub async fn handle_with_key( - State(state): State<(Arc, Arc, Arc>>)>, + State(state): State<( + Arc, + Arc, + Arc, + Arc>>, + )>, ExtractRequest(scrape_request): ExtractRequest, ExtractClientIpSources(client_ip_sources): ExtractClientIpSources, ExtractKey(key): ExtractKey, ) -> Response { tracing::debug!("http scrape request: {:#?}", &scrape_request); - handle(&state.0, &state.1, &state.2, &scrape_request, &client_ip_sources, Some(key)).await + handle( + &state.0, + &state.1, + &state.2, + &state.3, + &scrape_request, + &client_ip_sources, + Some(key), + ) + .await } async fn handle( tracker: &Arc, + scrape_handler: &Arc, authentication_service: &Arc, stats_event_sender: &Arc>>, scrape_request: &Scrape, @@ -65,6 +95,7 @@ async fn handle( ) -> Response { let scrape_data = match handle_scrape( tracker, + scrape_handler, authentication_service, stats_event_sender, scrape_request, @@ -87,6 +118,7 @@ async fn handle( async fn handle_scrape( tracker: &Arc, + scrape_handler: &Arc, authentication_service: &Arc, opt_stats_event_sender: &Arc>>, scrape_request: &Scrape, @@ -115,7 +147,7 @@ async fn handle_scrape( }; if return_real_scrape_data { - Ok(services::scrape::invoke(tracker, opt_stats_event_sender, &scrape_request.info_hashes, &peer_ip).await) + Ok(services::scrape::invoke(scrape_handler, opt_stats_event_sender, &scrape_request.info_hashes, &peer_ip).await) } else { Ok(services::scrape::fake(opt_stats_event_sender, &scrape_request.info_hashes, &peer_ip).await) } @@ -141,12 +173,15 @@ mod tests { use crate::app_test::initialize_tracker_dependencies; use crate::core::authentication::service::AuthenticationService; + use crate::core::scrape_handler::ScrapeHandler; use crate::core::services::{initialize_tracker, statistics}; use crate::core::Tracker; + #[allow(clippy::type_complexity)] fn private_tracker() -> ( - Tracker, - Option>, + Arc, + Arc, + Arc>>, Arc, ) { let config = configuration::ephemeral_private(); @@ -163,21 +198,24 @@ mod tests { let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - ( - initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ), - stats_event_sender, - authentication_service, - ) + let stats_event_sender = Arc::new(stats_event_sender); + + let tracker = Arc::new(initialize_tracker( + &config, + &in_memory_torrent_repository, + &db_torrent_repository, + )); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler, stats_event_sender, authentication_service) } + #[allow(clippy::type_complexity)] fn whitelisted_tracker() -> ( - Tracker, - Option>, + Arc, + Arc, + Arc>>, Arc, ) { let config = configuration::ephemeral_listed(); @@ -194,21 +232,24 @@ mod tests { let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - ( - initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ), - stats_event_sender, - authentication_service, - ) + let stats_event_sender = Arc::new(stats_event_sender); + + let tracker = Arc::new(initialize_tracker( + &config, + &in_memory_torrent_repository, + &db_torrent_repository, + )); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler, stats_event_sender, authentication_service) } + #[allow(clippy::type_complexity)] fn tracker_on_reverse_proxy() -> ( - Tracker, - Option>, + Arc, + Arc, + Arc>>, Arc, ) { let config = configuration::ephemeral_with_reverse_proxy(); @@ -225,21 +266,24 @@ mod tests { let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - ( - initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ), - stats_event_sender, - authentication_service, - ) + let stats_event_sender = Arc::new(stats_event_sender); + + let tracker = Arc::new(initialize_tracker( + &config, + &in_memory_torrent_repository, + &db_torrent_repository, + )); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler, stats_event_sender, authentication_service) } + #[allow(clippy::type_complexity)] fn tracker_not_on_reverse_proxy() -> ( - Tracker, - Option>, + Arc, + Arc, + Arc>>, Arc, ) { let config = configuration::ephemeral_without_reverse_proxy(); @@ -256,21 +300,22 @@ mod tests { let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - ( - initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ), - stats_event_sender, - authentication_service, - ) + let stats_event_sender = Arc::new(stats_event_sender); + + let tracker = Arc::new(initialize_tracker( + &config, + &in_memory_torrent_repository, + &db_torrent_repository, + )); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler, stats_event_sender, authentication_service) } fn sample_scrape_request() -> Scrape { Scrape { - info_hashes: vec!["3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap()], + info_hashes: vec!["3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap()], // # DevSkim: ignore DS173237 } } @@ -290,7 +335,6 @@ mod tests { mod with_tracker_in_private_mode { use std::str::FromStr; - use std::sync::Arc; use torrust_tracker_primitives::core::ScrapeData; @@ -300,15 +344,14 @@ mod tests { #[tokio::test] async fn it_should_return_zeroed_swarm_metadata_when_the_authentication_key_is_missing() { - let (tracker, stats_event_sender, authentication_service) = private_tracker(); - let tracker = Arc::new(tracker); - let stats_event_sender = Arc::new(stats_event_sender); + let (tracker, scrape_handler, stats_event_sender, authentication_service) = private_tracker(); let scrape_request = sample_scrape_request(); let maybe_key = None; let scrape_data = handle_scrape( &tracker, + &scrape_handler, &authentication_service, &stats_event_sender, &scrape_request, @@ -325,9 +368,7 @@ mod tests { #[tokio::test] async fn it_should_return_zeroed_swarm_metadata_when_the_authentication_key_is_invalid() { - let (tracker, stats_event_sender, authentication_service) = private_tracker(); - let tracker = Arc::new(tracker); - let stats_event_sender = Arc::new(stats_event_sender); + let (tracker, scrape_handler, stats_event_sender, authentication_service) = private_tracker(); let scrape_request = sample_scrape_request(); let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(); @@ -335,6 +376,7 @@ mod tests { let scrape_data = handle_scrape( &tracker, + &scrape_handler, &authentication_service, &stats_event_sender, &scrape_request, @@ -352,8 +394,6 @@ mod tests { mod with_tracker_in_listed_mode { - use std::sync::Arc; - use torrust_tracker_primitives::core::ScrapeData; use super::{sample_client_ip_sources, sample_scrape_request, whitelisted_tracker}; @@ -361,14 +401,13 @@ mod tests { #[tokio::test] async fn it_should_return_zeroed_swarm_metadata_when_the_torrent_is_not_whitelisted() { - let (tracker, stats_event_sender, authentication_service) = whitelisted_tracker(); - let tracker: Arc = Arc::new(tracker); - let stats_event_sender = Arc::new(stats_event_sender); + let (tracker, scrape_handler, stats_event_sender, authentication_service) = whitelisted_tracker(); let scrape_request = sample_scrape_request(); let scrape_data = handle_scrape( &tracker, + &scrape_handler, &authentication_service, &stats_event_sender, &scrape_request, @@ -385,7 +424,6 @@ mod tests { } mod with_tracker_on_reverse_proxy { - use std::sync::Arc; use bittorrent_http_protocol::v1::services::peer_ip_resolver::ClientIpSources; @@ -395,9 +433,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_right_most_x_forwarded_for_header_ip_is_not_available() { - let (tracker, stats_event_sender, authentication_service) = tracker_on_reverse_proxy(); - let tracker: Arc = Arc::new(tracker); - let stats_event_sender = Arc::new(stats_event_sender); + let (tracker, scrape_handler, stats_event_sender, authentication_service) = tracker_on_reverse_proxy(); let client_ip_sources = ClientIpSources { right_most_x_forwarded_for: None, @@ -406,6 +442,7 @@ mod tests { let response = handle_scrape( &tracker, + &scrape_handler, &authentication_service, &stats_event_sender, &sample_scrape_request(), @@ -423,7 +460,6 @@ mod tests { } mod with_tracker_not_on_reverse_proxy { - use std::sync::Arc; use bittorrent_http_protocol::v1::services::peer_ip_resolver::ClientIpSources; @@ -433,9 +469,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_client_ip_from_the_connection_info_is_not_available() { - let (tracker, stats_event_sender, authentication_service) = tracker_not_on_reverse_proxy(); - let tracker: Arc = Arc::new(tracker); - let stats_event_sender = Arc::new(stats_event_sender); + let (tracker, scrape_handler, stats_event_sender, authentication_service) = tracker_not_on_reverse_proxy(); let client_ip_sources = ClientIpSources { right_most_x_forwarded_for: None, @@ -444,6 +478,7 @@ mod tests { let response = handle_scrape( &tracker, + &scrape_handler, &authentication_service, &stats_event_sender, &sample_scrape_request(), diff --git a/src/servers/http/v1/routes.rs b/src/servers/http/v1/routes.rs index 7a1465500..0c0be5bd5 100644 --- a/src/servers/http/v1/routes.rs +++ b/src/servers/http/v1/routes.rs @@ -23,6 +23,7 @@ use tracing::{instrument, Level, Span}; use super::handlers::{announce, health_check, scrape}; use crate::core::authentication::service::AuthenticationService; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{whitelist, Tracker}; use crate::servers::http::HTTP_TRACKER_LOG_TARGET; @@ -35,6 +36,7 @@ use crate::servers::logging::Latency; #[allow(clippy::needless_pass_by_value)] #[instrument(skip( tracker, + scrape_handler, authentication_service, whitelist_authorization, stats_event_sender, @@ -42,6 +44,7 @@ use crate::servers::logging::Latency; ))] pub fn router( tracker: Arc, + scrape_handler: Arc, authentication_service: Arc, whitelist_authorization: Arc, stats_event_sender: Arc>>, @@ -74,6 +77,7 @@ pub fn router( "/scrape", get(scrape::handle_without_key).with_state(( tracker.clone(), + scrape_handler.clone(), authentication_service.clone(), stats_event_sender.clone(), )), @@ -82,6 +86,7 @@ pub fn router( "/scrape/{key}", get(scrape::handle_with_key).with_state(( tracker.clone(), + scrape_handler.clone(), authentication_service.clone(), stats_event_sender.clone(), )), diff --git a/src/servers/http/v1/services/announce.rs b/src/servers/http/v1/services/announce.rs index 322bc80eb..9e381d8b2 100644 --- a/src/servers/http/v1/services/announce.rs +++ b/src/servers/http/v1/services/announce.rs @@ -76,7 +76,7 @@ mod tests { let ( _database, _in_memory_whitelist, - whitelist_authorization, + _whitelist_authorization, _authentication_service, in_memory_torrent_repository, db_torrent_repository, @@ -85,12 +85,7 @@ mod tests { let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); let stats_event_sender = Arc::new(stats_event_sender); - let tracker = initialize_tracker( - &config, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ); + let tracker = initialize_tracker(&config, &in_memory_torrent_repository, &db_torrent_repository); (tracker, stats_event_sender) } @@ -147,20 +142,14 @@ mod tests { let ( _database, _in_memory_whitelist, - whitelist_authorization, + _whitelist_authorization, _authentication_service, in_memory_torrent_repository, db_torrent_repository, _torrents_manager, ) = initialize_tracker_dependencies(&config); - Tracker::new( - &config.core, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ) - .unwrap() + Tracker::new(&config.core, &in_memory_torrent_repository, &db_torrent_repository).unwrap() } #[tokio::test] diff --git a/src/servers/http/v1/services/scrape.rs b/src/servers/http/v1/services/scrape.rs index 299938f84..e3ee6560f 100644 --- a/src/servers/http/v1/services/scrape.rs +++ b/src/servers/http/v1/services/scrape.rs @@ -2,9 +2,8 @@ //! //! The service is responsible for handling the `scrape` requests. //! -//! It delegates the `scrape` logic to the [`Tracker`](crate::core::Tracker::scrape) -//! and it returns the [`ScrapeData`] returned -//! by the [`Tracker`]. +//! It delegates the `scrape` logic to the [`ScrapeHandler`] and it returns the +//! [`ScrapeData`]. //! //! It also sends an [`statistics::event::Event`] //! because events are specific for the HTTP tracker. @@ -14,9 +13,9 @@ use std::sync::Arc; use bittorrent_primitives::info_hash::InfoHash; use torrust_tracker_primitives::core::ScrapeData; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::statistics::{self}; -use crate::core::Tracker; /// The HTTP tracker `scrape` service. /// @@ -29,12 +28,12 @@ use crate::core::Tracker; /// > like the UDP tracker, the number of TCP connections is incremented for /// > each `scrape` request. pub async fn invoke( - tracker: &Arc, + scrape_handler: &Arc, opt_stats_event_sender: &Arc>>, info_hashes: &Vec, original_peer_ip: &IpAddr, ) -> ScrapeData { - let scrape_data = tracker.scrape(info_hashes).await; + let scrape_data = scrape_handler.scrape(info_hashes).await; send_scrape_event(original_peer_ip, opt_stats_event_sender).await; @@ -74,6 +73,7 @@ async fn send_scrape_event(original_peer_ip: &IpAddr, opt_stats_event_sender: &A mod tests { use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + use std::sync::Arc; use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId}; use bittorrent_primitives::info_hash::InfoHash; @@ -81,10 +81,11 @@ mod tests { use torrust_tracker_test_helpers::configuration; use crate::app_test::initialize_tracker_dependencies; + use crate::core::scrape_handler::ScrapeHandler; use crate::core::services::initialize_tracker; use crate::core::Tracker; - fn public_tracker() -> Tracker { + fn public_tracker_and_scrape_handler() -> (Arc, Arc) { let config = configuration::ephemeral_public(); let ( @@ -97,12 +98,15 @@ mod tests { _torrents_manager, ) = initialize_tracker_dependencies(&config); - initialize_tracker( + let tracker = Arc::new(initialize_tracker( &config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, - ) + )); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler) } fn sample_info_hashes() -> Vec { @@ -110,7 +114,7 @@ mod tests { } fn sample_info_hash() -> InfoHash { - "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap() + "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::().unwrap() // # DevSkim: ignore DS173237 } fn sample_peer() -> peer::Peer { @@ -125,7 +129,7 @@ mod tests { } } - fn test_tracker_factory() -> Tracker { + fn test_tracker_factory() -> (Arc, Arc) { let config = configuration::ephemeral(); let ( @@ -138,13 +142,11 @@ mod tests { _torrents_manager, ) = initialize_tracker_dependencies(&config); - Tracker::new( - &config.core, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ) - .unwrap() + let tracker = Arc::new(Tracker::new(&config.core, &in_memory_torrent_repository, &db_torrent_repository).unwrap()); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + + (tracker, scrape_handler) } mod with_real_data { @@ -160,7 +162,7 @@ mod tests { use crate::core::{statistics, PeersWanted}; use crate::servers::http::v1::services::scrape::invoke; use crate::servers::http::v1::services::scrape::tests::{ - public_tracker, sample_info_hash, sample_info_hashes, sample_peer, test_tracker_factory, + public_tracker_and_scrape_handler, sample_info_hash, sample_info_hashes, sample_peer, test_tracker_factory, }; #[tokio::test] @@ -168,7 +170,7 @@ mod tests { let (stats_event_sender, _stats_repository) = crate::core::services::statistics::setup::factory(false); let stats_event_sender = Arc::new(stats_event_sender); - let tracker = Arc::new(public_tracker()); + let (tracker, scrape_handler) = public_tracker_and_scrape_handler(); let info_hash = sample_info_hash(); let info_hashes = vec![info_hash]; @@ -178,7 +180,7 @@ mod tests { let original_peer_ip = peer.ip(); tracker.announce(&info_hash, &mut peer, &original_peer_ip, &PeersWanted::All); - let scrape_data = invoke(&tracker, &stats_event_sender, &info_hashes, &original_peer_ip).await; + let scrape_data = invoke(&scrape_handler, &stats_event_sender, &info_hashes, &original_peer_ip).await; let mut expected_scrape_data = ScrapeData::empty(); expected_scrape_data.add_file( @@ -204,11 +206,11 @@ mod tests { let stats_event_sender: Arc>> = Arc::new(Some(Box::new(stats_event_sender_mock))); - let tracker = Arc::new(test_tracker_factory()); + let (_tracker, scrape_handler) = test_tracker_factory(); let peer_ip = IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)); - invoke(&tracker, &stats_event_sender, &sample_info_hashes(), &peer_ip).await; + invoke(&scrape_handler, &stats_event_sender, &sample_info_hashes(), &peer_ip).await; } #[tokio::test] @@ -222,11 +224,11 @@ mod tests { let stats_event_sender: Arc>> = Arc::new(Some(Box::new(stats_event_sender_mock))); - let tracker = Arc::new(test_tracker_factory()); + let (_tracker, scrape_handler) = test_tracker_factory(); let peer_ip = IpAddr::V6(Ipv6Addr::new(0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969)); - invoke(&tracker, &stats_event_sender, &sample_info_hashes(), &peer_ip).await; + invoke(&scrape_handler, &stats_event_sender, &sample_info_hashes(), &peer_ip).await; } } @@ -242,14 +244,15 @@ mod tests { use crate::core::{statistics, PeersWanted}; use crate::servers::http::v1::services::scrape::fake; use crate::servers::http::v1::services::scrape::tests::{ - public_tracker, sample_info_hash, sample_info_hashes, sample_peer, + public_tracker_and_scrape_handler, sample_info_hash, sample_info_hashes, sample_peer, }; #[tokio::test] async fn it_should_always_return_the_zeroed_scrape_data_for_a_torrent() { let (stats_event_sender, _stats_repository) = crate::core::services::statistics::setup::factory(false); let stats_event_sender = Arc::new(stats_event_sender); - let tracker = Arc::new(public_tracker()); + + let (tracker, _scrape_handler) = public_tracker_and_scrape_handler(); let info_hash = sample_info_hash(); let info_hashes = vec![info_hash]; diff --git a/src/servers/udp/handlers.rs b/src/servers/udp/handlers.rs index c88f6fdc9..f8f57aea9 100644 --- a/src/servers/udp/handlers.rs +++ b/src/servers/udp/handlers.rs @@ -20,6 +20,7 @@ use zerocopy::network_endian::I32; use super::connection_cookie::{check, make}; use super::server::banning::BanService; use super::RawRequest; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{statistics, whitelist, PeersWanted, Tracker}; use crate::servers::udp::error::Error; @@ -54,10 +55,12 @@ impl CookieTimeValues { /// - Delegating the request to the correct handler depending on the request type. /// /// It will return an `Error` response if the request is invalid. -#[instrument(fields(request_id), skip(udp_request, tracker, whitelist_authorization, opt_stats_event_sender, cookie_time_values, ban_service), ret(level = Level::TRACE))] +#[allow(clippy::too_many_arguments)] +#[instrument(fields(request_id), skip(udp_request, tracker, scrape_handler, whitelist_authorization, opt_stats_event_sender, cookie_time_values, ban_service), ret(level = Level::TRACE))] pub(crate) async fn handle_packet( udp_request: RawRequest, tracker: &Tracker, + scrape_handler: &Arc, whitelist_authorization: &Arc, opt_stats_event_sender: &Arc>>, local_addr: SocketAddr, @@ -77,6 +80,7 @@ pub(crate) async fn handle_packet( request, udp_request.from, tracker, + scrape_handler, whitelist_authorization, opt_stats_event_sender, cookie_time_values.clone(), @@ -137,6 +141,7 @@ pub(crate) async fn handle_packet( request, remote_addr, tracker, + scrape_handler, whitelist_authorization, opt_stats_event_sender, cookie_time_values @@ -145,6 +150,7 @@ pub async fn handle_request( request: Request, remote_addr: SocketAddr, tracker: &Tracker, + scrape_handler: &Arc, whitelist_authorization: &Arc, opt_stats_event_sender: &Arc>>, cookie_time_values: CookieTimeValues, @@ -174,7 +180,7 @@ pub async fn handle_request( handle_scrape( remote_addr, &scrape_request, - tracker, + scrape_handler, opt_stats_event_sender, cookie_time_values.valid_range, ) @@ -338,11 +344,11 @@ pub async fn handle_announce( /// # Errors /// /// This function does not ever return an error. -#[instrument(fields(transaction_id, connection_id), skip(tracker, opt_stats_event_sender), ret(level = Level::TRACE))] +#[instrument(fields(transaction_id, connection_id), skip(scrape_handler, opt_stats_event_sender), ret(level = Level::TRACE))] pub async fn handle_scrape( remote_addr: SocketAddr, request: &ScrapeRequest, - tracker: &Tracker, + scrape_handler: &Arc, opt_stats_event_sender: &Arc>>, cookie_valid_range: Range, ) -> Result { @@ -365,7 +371,7 @@ pub async fn handle_scrape( info_hashes.push((*info_hash).into()); } - let scrape_data = tracker.scrape(&info_hashes).await; + let scrape_data = scrape_handler.scrape(&info_hashes).await; let mut torrent_stats: Vec = Vec::new(); @@ -484,6 +490,7 @@ mod tests { use super::gen_remote_fingerprint; use crate::app_test::initialize_tracker_dependencies; + use crate::core::scrape_handler::ScrapeHandler; use crate::core::services::{initialize_tracker, initialize_whitelist_manager, statistics}; use crate::core::statistics::event::sender::Sender; use crate::core::torrent::repository::in_memory::InMemoryTorrentRepository; @@ -494,6 +501,7 @@ mod tests { type TrackerAndDeps = ( Arc, + Arc, Arc, Arc>>, Arc, @@ -534,13 +542,15 @@ mod tests { let tracker = Arc::new(initialize_tracker( config, - &whitelist_authorization, &in_memory_torrent_repository, &db_torrent_repository, )); + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); + ( tracker, + scrape_handler, in_memory_torrent_repository, stats_event_sender, in_memory_whitelist, @@ -643,7 +653,7 @@ mod tests { } } - fn test_tracker_factory() -> (Arc, Arc) { + fn test_tracker_factory() -> (Arc, Arc, Arc) { let config = tracker_configuration(); let ( @@ -656,17 +666,11 @@ mod tests { _torrents_manager, ) = initialize_tracker_dependencies(&config); - let tracker = Arc::new( - Tracker::new( - &config.core, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ) - .unwrap(), - ); + let tracker = Arc::new(Tracker::new(&config.core, &in_memory_torrent_repository, &db_torrent_repository).unwrap()); + + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); - (tracker, whitelist_authorization) + (tracker, scrape_handler, whitelist_authorization) } mod connect_request { @@ -892,6 +896,7 @@ mod tests { async fn an_announced_peer_should_be_added_to_the_tracker() { let ( tracker, + _scrape_handler, in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -939,6 +944,7 @@ mod tests { async fn the_announced_peer_should_not_be_included_in_the_response() { let ( tracker, + _scrape_handler, _in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -986,6 +992,7 @@ mod tests { let ( tracker, + _scrape_handler, in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1071,6 +1078,7 @@ mod tests { async fn when_the_announce_request_comes_from_a_client_using_ipv4_the_response_should_not_include_peers_using_ipv6() { let ( tracker, + _scrape_handler, _in_memory_torrent_repository, _stats_event_sender, _in_memory_whitelist, @@ -1102,7 +1110,7 @@ mod tests { let stats_event_sender: Arc>> = Arc::new(Some(Box::new(stats_event_sender_mock))); - let (tracker, whitelist_authorization) = test_tracker_factory(); + let (tracker, _scrape_handler, whitelist_authorization) = test_tracker_factory(); handle_announce( sample_ipv4_socket_address(), @@ -1133,6 +1141,7 @@ mod tests { async fn the_peer_ip_should_be_changed_to_the_external_ip_in_the_tracker_configuration_if_defined() { let ( tracker, + _scrape_handler, in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1205,6 +1214,7 @@ mod tests { async fn an_announced_peer_should_be_added_to_the_tracker() { let ( tracker, + _scrape_handler, in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1253,6 +1263,7 @@ mod tests { async fn the_announced_peer_should_not_be_included_in_the_response() { let ( tracker, + _scrape_handler, _in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1303,6 +1314,7 @@ mod tests { let ( tracker, + _scrape_handler, in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1391,6 +1403,7 @@ mod tests { async fn when_the_announce_request_comes_from_a_client_using_ipv6_the_response_should_not_include_peers_using_ipv4() { let ( tracker, + _scrape_handler, _in_memory_torrent_repository, _stats_event_sender, _in_memory_whitelist, @@ -1422,7 +1435,7 @@ mod tests { let stats_event_sender: Arc>> = Arc::new(Some(Box::new(stats_event_sender_mock))); - let (tracker, whitelist_authorization) = test_tracker_factory(); + let (tracker, _scrape_handler, whitelist_authorization) = test_tracker_factory(); let remote_addr = sample_ipv6_remote_addr(); @@ -1483,13 +1496,7 @@ mod tests { Arc::new(Some(Box::new(stats_event_sender_mock))); let tracker = Arc::new( - core::Tracker::new( - &config.core, - &whitelist_authorization, - &in_memory_torrent_repository, - &db_torrent_repository, - ) - .unwrap(), + core::Tracker::new(&config.core, &in_memory_torrent_repository, &db_torrent_repository).unwrap(), ); let loopback_ipv4 = Ipv4Addr::new(127, 0, 0, 1); @@ -1550,6 +1557,7 @@ mod tests { }; use super::{gen_remote_fingerprint, TorrentPeerBuilder}; + use crate::core::scrape_handler::ScrapeHandler; use crate::core::services::statistics; use crate::core::{self}; use crate::servers::udp::connection_cookie::make; @@ -1569,7 +1577,8 @@ mod tests { #[tokio::test] async fn should_return_no_stats_when_the_tracker_does_not_have_any_torrent() { let ( - tracker, + _tracker, + scrape_handler, _in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1591,7 +1600,7 @@ mod tests { let response = handle_scrape( remote_addr, &request, - &tracker, + &scrape_handler, &stats_event_sender, sample_cookie_valid_range(), ) @@ -1631,7 +1640,7 @@ mod tests { } } - async fn add_a_sample_seeder_and_scrape(tracker: Arc) -> Response { + async fn add_a_sample_seeder_and_scrape(tracker: Arc, scrape_handler: Arc) -> Response { let (stats_event_sender, _stats_repository) = statistics::setup::factory(false); let stats_event_sender = Arc::new(stats_event_sender); @@ -1645,7 +1654,7 @@ mod tests { handle_scrape( remote_addr, &request, - &tracker, + &scrape_handler, &stats_event_sender, sample_cookie_valid_range(), ) @@ -1670,6 +1679,7 @@ mod tests { async fn should_return_torrent_statistics_when_the_tracker_has_the_requested_torrent() { let ( tracker, + scrape_handler, _in_memory_torrent_repository, _stats_event_sender, _in_memory_whitelist, @@ -1677,7 +1687,8 @@ mod tests { _whitelist_authorization, ) = public_tracker(); - let torrent_stats = match_scrape_response(add_a_sample_seeder_and_scrape(tracker.clone()).await); + let torrent_stats = + match_scrape_response(add_a_sample_seeder_and_scrape(tracker.clone(), scrape_handler.clone()).await); let expected_torrent_stats = vec![TorrentScrapeStatistics { seeders: NumberOfPeers(1.into()), @@ -1702,6 +1713,7 @@ mod tests { async fn should_return_the_torrent_statistics_when_the_requested_torrent_is_whitelisted() { let ( tracker, + scrape_handler, _in_memory_torrent_repository, stats_event_sender, in_memory_whitelist, @@ -1722,7 +1734,7 @@ mod tests { handle_scrape( remote_addr, &request, - &tracker, + &scrape_handler, &stats_event_sender, sample_cookie_valid_range(), ) @@ -1744,6 +1756,7 @@ mod tests { async fn should_return_zeroed_statistics_when_the_requested_torrent_is_not_whitelisted() { let ( tracker, + scrape_handler, _in_memory_torrent_repository, stats_event_sender, _in_memory_whitelist, @@ -1762,7 +1775,7 @@ mod tests { handle_scrape( remote_addr, &request, - &tracker, + &scrape_handler, &stats_event_sender, sample_cookie_valid_range(), ) @@ -1814,12 +1827,12 @@ mod tests { let remote_addr = sample_ipv4_remote_addr(); - let (tracker, _whitelist_authorization) = test_tracker_factory(); + let (_tracker, scrape_handler, _whitelist_authorization) = test_tracker_factory(); handle_scrape( remote_addr, &sample_scrape_request(&remote_addr), - &tracker, + &scrape_handler, &stats_event_sender, sample_cookie_valid_range(), ) @@ -1854,12 +1867,12 @@ mod tests { let remote_addr = sample_ipv6_remote_addr(); - let (tracker, _whitelist_authorization) = test_tracker_factory(); + let (_tracker, scrape_handler, _whitelist_authorization) = test_tracker_factory(); handle_scrape( remote_addr, &sample_scrape_request(&remote_addr), - &tracker, + &scrape_handler, &stats_event_sender, sample_cookie_valid_range(), ) diff --git a/src/servers/udp/server/launcher.rs b/src/servers/udp/server/launcher.rs index bb5c30d44..d6bc230e1 100644 --- a/src/servers/udp/server/launcher.rs +++ b/src/servers/udp/server/launcher.rs @@ -13,6 +13,7 @@ use tracing::instrument; use super::banning::BanService; use super::request_buffer::ActiveRequests; use crate::bootstrap::jobs::Started; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{statistics, whitelist, Tracker}; use crate::servers::logging::STARTED_ON; @@ -43,6 +44,7 @@ impl Launcher { #[allow(clippy::too_many_arguments)] #[instrument(skip( tracker, + scrape_handler, whitelist_authorization, opt_stats_event_sender, ban_service, @@ -52,6 +54,7 @@ impl Launcher { ))] pub async fn run_with_graceful_shutdown( tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, opt_stats_event_sender: Arc>>, ban_service: Arc>, @@ -95,6 +98,7 @@ impl Launcher { let () = Self::run_udp_server_main( receiver, tracker.clone(), + scrape_handler.clone(), whitelist_authorization.clone(), opt_stats_event_sender.clone(), ban_service.clone(), @@ -137,10 +141,18 @@ impl Launcher { ServiceHealthCheckJob::new(binding, info, job) } - #[instrument(skip(receiver, tracker, whitelist_authorization, opt_stats_event_sender, ban_service))] + #[instrument(skip( + receiver, + tracker, + scrape_handler, + whitelist_authorization, + opt_stats_event_sender, + ban_service + ))] async fn run_udp_server_main( mut receiver: Receiver, tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, opt_stats_event_sender: Arc>>, ban_service: Arc>, @@ -212,6 +224,7 @@ impl Launcher { let processor = Processor::new( receiver.socket.clone(), tracker.clone(), + scrape_handler.clone(), whitelist_authorization.clone(), opt_stats_event_sender.clone(), cookie_lifetime, diff --git a/src/servers/udp/server/mod.rs b/src/servers/udp/server/mod.rs index af51b7fb7..668265752 100644 --- a/src/servers/udp/server/mod.rs +++ b/src/servers/udp/server/mod.rs @@ -83,6 +83,7 @@ mod tests { let started = stopped .start( app_container.tracker, + app_container.scrape_handler, app_container.whitelist_authorization, app_container.stats_event_sender, app_container.ban_service, @@ -116,6 +117,7 @@ mod tests { let started = stopped .start( app_container.tracker, + app_container.scrape_handler, app_container.whitelist_authorization, app_container.stats_event_sender, app_container.ban_service, diff --git a/src/servers/udp/server/processor.rs b/src/servers/udp/server/processor.rs index fe3666c1d..889a2a913 100644 --- a/src/servers/udp/server/processor.rs +++ b/src/servers/udp/server/processor.rs @@ -10,6 +10,7 @@ use tracing::{instrument, Level}; use super::banning::BanService; use super::bound_socket::BoundSocket; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::statistics::event::UdpResponseKind; use crate::core::{statistics, whitelist, Tracker}; @@ -19,6 +20,7 @@ use crate::servers::udp::{handlers, RawRequest}; pub struct Processor { socket: Arc, tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, opt_stats_event_sender: Arc>>, cookie_lifetime: f64, @@ -28,6 +30,7 @@ impl Processor { pub fn new( socket: Arc, tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, opt_stats_event_sender: Arc>>, cookie_lifetime: f64, @@ -35,6 +38,7 @@ impl Processor { Self { socket, tracker, + scrape_handler, whitelist_authorization, opt_stats_event_sender, cookie_lifetime, @@ -50,6 +54,7 @@ impl Processor { let response = handlers::handle_packet( request, &self.tracker, + &self.scrape_handler, &self.whitelist_authorization, &self.opt_stats_event_sender, self.socket.address(), diff --git a/src/servers/udp/server/spawner.rs b/src/servers/udp/server/spawner.rs index aecba39ec..82fd808c4 100644 --- a/src/servers/udp/server/spawner.rs +++ b/src/servers/udp/server/spawner.rs @@ -11,6 +11,7 @@ use tokio::task::JoinHandle; use super::banning::BanService; use super::launcher::Launcher; use crate::bootstrap::jobs::Started; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{whitelist, Tracker}; use crate::servers::signals::Halted; @@ -31,6 +32,7 @@ impl Spawner { pub fn spawn_launcher( &self, tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, opt_stats_event_sender: Arc>>, ban_service: Arc>, @@ -43,6 +45,7 @@ impl Spawner { tokio::spawn(async move { Launcher::run_with_graceful_shutdown( tracker, + scrape_handler, whitelist_authorization, opt_stats_event_sender, ban_service, diff --git a/src/servers/udp/server/states.rs b/src/servers/udp/server/states.rs index 9a01b5c6d..d2c91b03d 100644 --- a/src/servers/udp/server/states.rs +++ b/src/servers/udp/server/states.rs @@ -13,6 +13,7 @@ use super::banning::BanService; use super::spawner::Spawner; use super::{Server, UdpError}; use crate::bootstrap::jobs::Started; +use crate::core::scrape_handler::ScrapeHandler; use crate::core::statistics::event::sender::Sender; use crate::core::{whitelist, Tracker}; use crate::servers::registar::{ServiceRegistration, ServiceRegistrationForm}; @@ -64,11 +65,12 @@ impl Server { /// # Panics /// /// It panics if unable to receive the bound socket address from service. - /// - #[instrument(skip(self, tracker, whitelist_authorization, opt_stats_event_sender, ban_service, form), err, ret(Display, level = Level::INFO))] + #[allow(clippy::too_many_arguments)] + #[instrument(skip(self, tracker, scrape_handler, whitelist_authorization, opt_stats_event_sender, ban_service, form), err, ret(Display, level = Level::INFO))] pub async fn start( self, tracker: Arc, + scrape_handler: Arc, whitelist_authorization: Arc, opt_stats_event_sender: Arc>>, ban_service: Arc>, @@ -83,6 +85,7 @@ impl Server { // May need to wrap in a task to about a tokio bug. let task = self.state.spawner.spawn_launcher( tracker, + scrape_handler, whitelist_authorization, opt_stats_event_sender, ban_service, diff --git a/tests/servers/http/environment.rs b/tests/servers/http/environment.rs index c0de4efbe..63d372880 100644 --- a/tests/servers/http/environment.rs +++ b/tests/servers/http/environment.rs @@ -8,6 +8,7 @@ use torrust_tracker_lib::bootstrap::jobs::make_rust_tls; use torrust_tracker_lib::core::authentication::handler::KeysHandler; use torrust_tracker_lib::core::authentication::service::AuthenticationService; use torrust_tracker_lib::core::databases::Database; +use torrust_tracker_lib::core::scrape_handler::ScrapeHandler; use torrust_tracker_lib::core::statistics::event::sender::Sender; use torrust_tracker_lib::core::statistics::repository::Repository; use torrust_tracker_lib::core::torrent::repository::in_memory::InMemoryTorrentRepository; @@ -21,6 +22,7 @@ pub struct Environment { pub config: Arc, pub database: Arc>, pub tracker: Arc, + pub scrape_handler: Arc, pub in_memory_torrent_repository: Arc, pub keys_handler: Arc, pub authentication_service: Arc, @@ -63,6 +65,7 @@ impl Environment { config, database: app_container.database.clone(), tracker: app_container.tracker.clone(), + scrape_handler: app_container.scrape_handler.clone(), in_memory_torrent_repository: app_container.in_memory_torrent_repository.clone(), keys_handler: app_container.keys_handler.clone(), authentication_service: app_container.authentication_service.clone(), @@ -81,6 +84,7 @@ impl Environment { config: self.config, database: self.database.clone(), tracker: self.tracker.clone(), + scrape_handler: self.scrape_handler.clone(), in_memory_torrent_repository: self.in_memory_torrent_repository.clone(), keys_handler: self.keys_handler.clone(), authentication_service: self.authentication_service.clone(), @@ -93,6 +97,7 @@ impl Environment { .server .start( self.tracker, + self.scrape_handler, self.authentication_service, self.whitelist_authorization, self.stats_event_sender, @@ -114,6 +119,7 @@ impl Environment { config: self.config, database: self.database, tracker: self.tracker, + scrape_handler: self.scrape_handler, in_memory_torrent_repository: self.in_memory_torrent_repository, keys_handler: self.keys_handler, authentication_service: self.authentication_service, diff --git a/tests/servers/udp/environment.rs b/tests/servers/udp/environment.rs index c02e35e6e..16719c317 100644 --- a/tests/servers/udp/environment.rs +++ b/tests/servers/udp/environment.rs @@ -6,6 +6,7 @@ use tokio::sync::RwLock; use torrust_tracker_configuration::{Configuration, UdpTracker, DEFAULT_TIMEOUT}; use torrust_tracker_lib::bootstrap::app::{initialize_app_container, initialize_global_services}; use torrust_tracker_lib::core::databases::Database; +use torrust_tracker_lib::core::scrape_handler::ScrapeHandler; use torrust_tracker_lib::core::statistics::event::sender::Sender; use torrust_tracker_lib::core::statistics::repository::Repository; use torrust_tracker_lib::core::{whitelist, Tracker}; @@ -23,6 +24,7 @@ where pub config: Arc, pub database: Arc>, pub tracker: Arc, + pub scrape_handler: Arc, pub whitelist_authorization: Arc, pub stats_event_sender: Arc>>, pub stats_repository: Arc, @@ -61,6 +63,7 @@ impl Environment { config, database: app_container.database.clone(), tracker: app_container.tracker.clone(), + scrape_handler: app_container.scrape_handler.clone(), whitelist_authorization: app_container.whitelist_authorization.clone(), stats_event_sender: app_container.stats_event_sender.clone(), stats_repository: app_container.stats_repository.clone(), @@ -77,6 +80,7 @@ impl Environment { config: self.config, database: self.database.clone(), tracker: self.tracker.clone(), + scrape_handler: self.scrape_handler.clone(), whitelist_authorization: self.whitelist_authorization.clone(), stats_event_sender: self.stats_event_sender.clone(), stats_repository: self.stats_repository.clone(), @@ -86,6 +90,7 @@ impl Environment { .server .start( self.tracker, + self.scrape_handler, self.whitelist_authorization, self.stats_event_sender, self.ban_service, @@ -115,6 +120,7 @@ impl Environment { config: self.config, database: self.database, tracker: self.tracker, + scrape_handler: self.scrape_handler, whitelist_authorization: self.whitelist_authorization, stats_event_sender: self.stats_event_sender, stats_repository: self.stats_repository,