diff --git a/Cargo.lock b/Cargo.lock index bbf225018..d868f7452 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -600,7 +600,6 @@ dependencies = [ "bittorrent-primitives", "chrono", "derive_more", - "futures", "local-ip-address", "mockall", "r2d2", diff --git a/packages/tracker-core/Cargo.toml b/packages/tracker-core/Cargo.toml index b38f7c90f..7b5b1f2c2 100644 --- a/packages/tracker-core/Cargo.toml +++ b/packages/tracker-core/Cargo.toml @@ -20,7 +20,6 @@ bittorrent-http-protocol = { version = "3.0.0-develop", path = "../http-protocol bittorrent-primitives = "0.1.0" chrono = { version = "0", default-features = false, features = ["clock"] } derive_more = { version = "1", features = ["as_ref", "constructor", "from"] } -futures = "0" r2d2 = "0" r2d2_mysql = "25" r2d2_sqlite = { version = "0", features = ["bundled"] } diff --git a/packages/tracker-core/src/lib.rs b/packages/tracker-core/src/lib.rs index 2fb2d936d..68bc48552 100644 --- a/packages/tracker-core/src/lib.rs +++ b/packages/tracker-core/src/lib.rs @@ -346,7 +346,7 @@ //! //! Services are domain services on top of the core tracker domain. Right now there are two types of service: //! -//! - For statistics: [`crate::core::statistics::services`] +//! - For statistics: [`crate::packages::statistics::services`] //! - For torrents: [`crate::core::torrent::services`] //! //! Services usually format the data inside the tracker to make it easier to consume by other parts. @@ -370,60 +370,6 @@ //! To learn more about tracker authentication, refer to the following modules : //! //! - [`authentication`] module. -//! - [`core`](crate::core) module. -//! - [`http`](crate::servers::http) module. -//! -//! # Statistics -//! -//! The `Tracker` keeps metrics for some events: -//! -//! ```rust,no_run -//! pub struct Metrics { -//! // IP version 4 -//! -//! // HTTP tracker -//! pub tcp4_connections_handled: u64, -//! pub tcp4_announces_handled: u64, -//! pub tcp4_scrapes_handled: u64, -//! -//! // UDP tracker -//! pub udp4_connections_handled: u64, -//! pub udp4_announces_handled: u64, -//! pub udp4_scrapes_handled: u64, -//! -//! // IP version 6 -//! -//! // HTTP tracker -//! pub tcp6_connections_handled: u64, -//! pub tcp6_announces_handled: u64, -//! pub tcp6_scrapes_handled: u64, -//! -//! // UDP tracker -//! pub udp6_connections_handled: u64, -//! pub udp6_announces_handled: u64, -//! pub udp6_scrapes_handled: u64, -//! } -//! ``` -//! -//! The metrics maintained by the `Tracker` are: -//! -//! - `connections_handled`: number of connections handled by the tracker -//! - `announces_handled`: number of `announce` requests handled by the tracker -//! - `scrapes_handled`: number of `scrape` handled requests by the tracker -//! -//! > **NOTICE**: as the HTTP tracker does not have an specific `connection` request like the UDP tracker, `connections_handled` are -//! > increased on every `announce` and `scrape` requests. -//! -//! The tracker exposes an event sender API that allows the tracker users to send events. When a higher application service handles a -//! `connection` , `announce` or `scrape` requests, it notifies the `Tracker` by sending statistics events. -//! -//! For example, the HTTP tracker would send an event like the following when it handles an `announce` request received from a peer using IP version 4. -//! -//! ```text -//! stats_event_sender.send_stats_event(statistics::event::Event::Tcp4Announce).await -//! ``` -//! -//! Refer to [`statistics`] module for more information about statistics. //! //! # Persistence //! @@ -442,7 +388,6 @@ pub mod authentication; pub mod databases; pub mod error; pub mod scrape_handler; -pub mod statistics; pub mod torrent; pub mod whitelist; diff --git a/packages/tracker-core/src/statistics/mod.rs b/packages/tracker-core/src/statistics/mod.rs deleted file mode 100644 index 2ffbc0c8f..000000000 --- a/packages/tracker-core/src/statistics/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Structs to collect and keep tracker metrics. -//! -//! The tracker collects metrics such as: -//! -//! - Number of connections handled -//! - Number of `announce` requests handled -//! - Number of `scrape` request handled -//! -//! These metrics are collected for each connection type: UDP and HTTP and -//! also for each IP version used by the peers: IPv4 and IPv6. -//! -//! > Notice: that UDP tracker have an specific `connection` request. For the -//! > `HTTP` metrics the counter counts one connection for each `announce` or -//! > `scrape` request. -//! -//! The data is collected by using an `event-sender -> event listener` model. -//! -//! The tracker uses a [`Sender`](crate::core::statistics::event::sender::Sender) -//! instance to send an event. -//! -//! The [`statistics::keeper::Keeper`](crate::core::statistics::keeper::Keeper) listens to new -//! events and uses the [`statistics::repository::Repository`](crate::core::statistics::repository::Repository) to -//! upgrade and store metrics. -//! -//! See the [`statistics::event::Event`](crate::core::statistics::event::Event) enum to check -//! which events are available. -pub mod event; -pub mod keeper; -pub mod metrics; -pub mod repository; -pub mod services; -pub mod setup; diff --git a/packages/tracker-core/src/statistics/services.rs b/packages/tracker-core/src/statistics/services.rs deleted file mode 100644 index 196c6b340..000000000 --- a/packages/tracker-core/src/statistics/services.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Statistics services. -//! -//! It includes: -//! -//! - A [`factory`](crate::statistics::setup::factory) function to build the structs needed to collect the tracker metrics. -//! - A [`get_metrics`] service to get the tracker [`metrics`](crate::core::statistics::metrics::Metrics). -//! -//! Tracker metrics are collected using a Publisher-Subscribe pattern. -//! -//! The factory function builds two structs: -//! -//! - An statistics event [`Sender`](crate::core::statistics::event::sender::Sender) -//! - An statistics [`Repository`] -//! -//! ```text -//! let (stats_event_sender, stats_repository) = factory(tracker_usage_statistics); -//! ``` -//! -//! The statistics repository is responsible for storing the metrics in memory. -//! The statistics event sender allows sending events related to metrics. -//! There is an event listener that is receiving all the events and processing them with an event handler. -//! Then, the event handler updates the metrics depending on the received event. -//! -//! For example, if you send the event [`Event::Udp4Connect`](crate::core::statistics::event::Event::Udp4Connect): -//! -//! ```text -//! let result = event_sender.send_event(Event::Udp4Connect).await; -//! ``` -//! -//! Eventually the counter for UDP connections from IPv4 peers will be increased. -//! -//! ```rust,no_run -//! pub struct Metrics { -//! // ... -//! pub udp4_connections_handled: u64, // This will be incremented -//! // ... -//! } -//! ``` -use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; - -use crate::statistics::metrics::Metrics; - -/// All the metrics collected by the tracker. -#[derive(Debug, PartialEq)] -pub struct TrackerMetrics { - /// Domain level metrics. - /// - /// General metrics for all torrents (number of seeders, leechers, etcetera) - pub torrents_metrics: TorrentsMetrics, - - /// Application level metrics. Usage statistics/metrics. - /// - /// Metrics about how the tracker is been used (number of udp announce requests, number of http scrape requests, etcetera) - pub protocol_metrics: Metrics, -} diff --git a/src/bootstrap/app.rs b/src/bootstrap/app.rs index f7506800e..93bbfe290 100644 --- a/src/bootstrap/app.rs +++ b/src/bootstrap/app.rs @@ -20,7 +20,6 @@ use bittorrent_tracker_core::authentication::key::repository::persisted::Databas use bittorrent_tracker_core::authentication::service; use bittorrent_tracker_core::databases::setup::initialize_database; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; -use bittorrent_tracker_core::statistics; use bittorrent_tracker_core::torrent::manager::TorrentsManager; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; @@ -36,6 +35,7 @@ use tracing::instrument; use super::config::initialize_configuration; use crate::bootstrap; use crate::container::AppContainer; +use crate::packages::{http_tracker_core, udp_tracker_core}; use crate::servers::udp::server::banning::BanService; use crate::servers::udp::server::launcher::MAX_CONNECTION_ID_ERRORS_PER_IP; use crate::shared::crypto::ephemeral_instance_keys; @@ -90,9 +90,19 @@ pub fn initialize_global_services(configuration: &Configuration) { #[instrument(skip())] pub fn initialize_app_container(configuration: &Configuration) -> AppContainer { let core_config = Arc::new(configuration.core.clone()); - let (stats_event_sender, stats_repository) = statistics::setup::factory(configuration.core.tracker_usage_statistics); - let stats_event_sender = Arc::new(stats_event_sender); - let stats_repository = Arc::new(stats_repository); + + // HTTP stats + let (http_stats_event_sender, http_stats_repository) = + http_tracker_core::statistics::setup::factory(configuration.core.tracker_usage_statistics); + let http_stats_event_sender = Arc::new(http_stats_event_sender); + let http_stats_repository = Arc::new(http_stats_repository); + + // UDP stats + let (udp_stats_event_sender, udp_stats_repository) = + udp_tracker_core::statistics::setup::factory(configuration.core.tracker_usage_statistics); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); + let udp_stats_repository = Arc::new(udp_stats_repository); + let ban_service = Arc::new(RwLock::new(BanService::new(MAX_CONNECTION_ID_ERRORS_PER_IP))); let database = initialize_database(configuration); let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); @@ -133,8 +143,10 @@ pub fn initialize_app_container(configuration: &Configuration) -> AppContainer { authentication_service, whitelist_authorization, ban_service, - stats_event_sender, - stats_repository, + http_stats_event_sender, + udp_stats_event_sender, + http_stats_repository, + udp_stats_repository, whitelist_manager, in_memory_torrent_repository, db_torrent_repository, diff --git a/src/container.rs b/src/container.rs index cae2d07ce..51c55e533 100644 --- a/src/container.rs +++ b/src/container.rs @@ -5,8 +5,6 @@ use bittorrent_tracker_core::authentication::handler::KeysHandler; use bittorrent_tracker_core::authentication::service::AuthenticationService; use bittorrent_tracker_core::databases::Database; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; -use bittorrent_tracker_core::statistics::event::sender::Sender; -use bittorrent_tracker_core::statistics::repository::Repository; use bittorrent_tracker_core::torrent::manager::TorrentsManager; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; @@ -15,6 +13,7 @@ use bittorrent_tracker_core::whitelist::manager::WhitelistManager; use tokio::sync::RwLock; use torrust_tracker_configuration::{Core, HttpApi, HttpTracker, UdpTracker}; +use crate::packages::{http_tracker_core, udp_tracker_core}; use crate::servers::udp::server::banning::BanService; pub struct AppContainer { @@ -26,8 +25,10 @@ pub struct AppContainer { pub authentication_service: Arc, pub whitelist_authorization: Arc, pub ban_service: Arc>, - pub stats_event_sender: Arc>>, - pub stats_repository: Arc, + pub http_stats_event_sender: Arc>>, + pub udp_stats_event_sender: Arc>>, + pub http_stats_repository: Arc, + pub udp_stats_repository: Arc, pub whitelist_manager: Arc, pub in_memory_torrent_repository: Arc, pub db_torrent_repository: Arc, @@ -40,7 +41,7 @@ pub struct UdpTrackerContainer { pub announce_handler: Arc, pub scrape_handler: Arc, pub whitelist_authorization: Arc, - pub stats_event_sender: Arc>>, + pub udp_stats_event_sender: Arc>>, pub ban_service: Arc>, } @@ -53,7 +54,7 @@ impl UdpTrackerContainer { announce_handler: app_container.announce_handler.clone(), scrape_handler: app_container.scrape_handler.clone(), whitelist_authorization: app_container.whitelist_authorization.clone(), - stats_event_sender: app_container.stats_event_sender.clone(), + udp_stats_event_sender: app_container.udp_stats_event_sender.clone(), ban_service: app_container.ban_service.clone(), } } @@ -65,7 +66,7 @@ pub struct HttpTrackerContainer { pub announce_handler: Arc, pub scrape_handler: Arc, pub whitelist_authorization: Arc, - pub stats_event_sender: Arc>>, + pub http_stats_event_sender: Arc>>, pub authentication_service: Arc, } @@ -78,7 +79,7 @@ impl HttpTrackerContainer { announce_handler: app_container.announce_handler.clone(), scrape_handler: app_container.scrape_handler.clone(), whitelist_authorization: app_container.whitelist_authorization.clone(), - stats_event_sender: app_container.stats_event_sender.clone(), + http_stats_event_sender: app_container.http_stats_event_sender.clone(), authentication_service: app_container.authentication_service.clone(), } } @@ -91,8 +92,8 @@ pub struct HttpApiContainer { pub keys_handler: Arc, pub whitelist_manager: Arc, pub ban_service: Arc>, - pub stats_event_sender: Arc>>, - pub stats_repository: Arc, + pub http_stats_repository: Arc, + pub udp_stats_repository: Arc, } impl HttpApiContainer { @@ -105,8 +106,8 @@ impl HttpApiContainer { keys_handler: app_container.keys_handler.clone(), whitelist_manager: app_container.whitelist_manager.clone(), ban_service: app_container.ban_service.clone(), - stats_event_sender: app_container.stats_event_sender.clone(), - stats_repository: app_container.stats_repository.clone(), + http_stats_repository: app_container.http_stats_repository.clone(), + udp_stats_repository: app_container.udp_stats_repository.clone(), } } } diff --git a/src/lib.rs b/src/lib.rs index 212430605..b9ab402ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -494,7 +494,7 @@ pub mod app; pub mod bootstrap; pub mod console; pub mod container; -pub mod core; +pub mod packages; pub mod servers; pub mod shared; diff --git a/src/core/mod.rs b/src/packages/http_tracker_core/mod.rs similarity index 100% rename from src/core/mod.rs rename to src/packages/http_tracker_core/mod.rs diff --git a/src/packages/http_tracker_core/statistics/event/handler.rs b/src/packages/http_tracker_core/statistics/event/handler.rs new file mode 100644 index 000000000..caaf5d375 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/event/handler.rs @@ -0,0 +1,123 @@ +use crate::packages::http_tracker_core::statistics::event::Event; +use crate::packages::http_tracker_core::statistics::repository::Repository; + +pub async fn handle_event(event: Event, stats_repository: &Repository) { + match event { + // TCP4 + Event::Tcp4Announce => { + stats_repository.increase_tcp4_announces().await; + stats_repository.increase_tcp4_connections().await; + } + Event::Tcp4Scrape => { + stats_repository.increase_tcp4_scrapes().await; + stats_repository.increase_tcp4_connections().await; + } + + // TCP6 + Event::Tcp6Announce => { + stats_repository.increase_tcp6_announces().await; + stats_repository.increase_tcp6_connections().await; + } + Event::Tcp6Scrape => { + stats_repository.increase_tcp6_scrapes().await; + stats_repository.increase_tcp6_connections().await; + } + } + + tracing::debug!("stats: {:?}", stats_repository.get_stats().await); +} + +#[cfg(test)] +mod tests { + use crate::packages::http_tracker_core::statistics::event::handler::handle_event; + use crate::packages::http_tracker_core::statistics::event::Event; + use crate::packages::http_tracker_core::statistics::repository::Repository; + + #[tokio::test] + async fn should_increase_the_tcp4_announces_counter_when_it_receives_a_tcp4_announce_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp4Announce, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp4_announces_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp4_connections_counter_when_it_receives_a_tcp4_announce_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp4Announce, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp4_connections_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp4_scrapes_counter_when_it_receives_a_tcp4_scrape_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp4Scrape, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp4_scrapes_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp4_connections_counter_when_it_receives_a_tcp4_scrape_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp4Scrape, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp4_connections_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp6_announces_counter_when_it_receives_a_tcp6_announce_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp6Announce, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp6_announces_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp6_connections_counter_when_it_receives_a_tcp6_announce_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp6Announce, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp6_connections_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp6_scrapes_counter_when_it_receives_a_tcp6_scrape_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp6Scrape, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp6_scrapes_handled, 1); + } + + #[tokio::test] + async fn should_increase_the_tcp6_connections_counter_when_it_receives_a_tcp6_scrape_event() { + let stats_repository = Repository::new(); + + handle_event(Event::Tcp6Scrape, &stats_repository).await; + + let stats = stats_repository.get_stats().await; + + assert_eq!(stats.tcp6_connections_handled, 1); + } +} diff --git a/src/packages/http_tracker_core/statistics/event/listener.rs b/src/packages/http_tracker_core/statistics/event/listener.rs new file mode 100644 index 000000000..ed574a36b --- /dev/null +++ b/src/packages/http_tracker_core/statistics/event/listener.rs @@ -0,0 +1,11 @@ +use tokio::sync::mpsc; + +use super::handler::handle_event; +use super::Event; +use crate::packages::http_tracker_core::statistics::repository::Repository; + +pub async fn dispatch_events(mut receiver: mpsc::Receiver, stats_repository: Repository) { + while let Some(event) = receiver.recv().await { + handle_event(event, &stats_repository).await; + } +} diff --git a/src/packages/http_tracker_core/statistics/event/mod.rs b/src/packages/http_tracker_core/statistics/event/mod.rs new file mode 100644 index 000000000..e25148666 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/event/mod.rs @@ -0,0 +1,21 @@ +pub mod handler; +pub mod listener; +pub mod sender; + +/// An statistics event. It is used to collect tracker metrics. +/// +/// - `Tcp` prefix means the event was triggered by the HTTP tracker +/// - `Udp` prefix means the event was triggered by the UDP tracker +/// - `4` or `6` prefixes means the IP version used by the peer +/// - Finally the event suffix is the type of request: `announce`, `scrape` or `connection` +/// +/// > NOTE: HTTP trackers do not use `connection` requests. +#[derive(Debug, PartialEq, Eq)] +pub enum Event { + // code-review: consider one single event for request type with data: Event::Announce { scheme: HTTPorUDP, ip_version: V4orV6 } + // Attributes are enums too. + Tcp4Announce, + Tcp4Scrape, + Tcp6Announce, + Tcp6Scrape, +} diff --git a/src/packages/http_tracker_core/statistics/event/sender.rs b/src/packages/http_tracker_core/statistics/event/sender.rs new file mode 100644 index 000000000..279d50962 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/event/sender.rs @@ -0,0 +1,29 @@ +use futures::future::BoxFuture; +use futures::FutureExt; +#[cfg(test)] +use mockall::{automock, predicate::str}; +use tokio::sync::mpsc; +use tokio::sync::mpsc::error::SendError; + +use super::Event; + +/// A trait to allow sending statistics events +#[cfg_attr(test, automock)] +pub trait Sender: Sync + Send { + fn send_event(&self, event: Event) -> BoxFuture<'_, Option>>>; +} + +/// An [`statistics::EventSender`](crate::packages::http_tracker_core::statistics::event::sender::Sender) implementation. +/// +/// It uses a channel sender to send the statistic events. The channel is created by a +/// [`statistics::Keeper`](crate::packages::http_tracker_core::statistics::keeper::Keeper) +#[allow(clippy::module_name_repetitions)] +pub struct ChannelSender { + pub(crate) sender: mpsc::Sender, +} + +impl Sender for ChannelSender { + fn send_event(&self, event: Event) -> BoxFuture<'_, Option>>> { + async move { Some(self.sender.send(event).await) }.boxed() + } +} diff --git a/packages/tracker-core/src/statistics/keeper.rs b/src/packages/http_tracker_core/statistics/keeper.rs similarity index 86% rename from packages/tracker-core/src/statistics/keeper.rs rename to src/packages/http_tracker_core/statistics/keeper.rs index a3d4542f7..01ae5e6b3 100644 --- a/packages/tracker-core/src/statistics/keeper.rs +++ b/src/packages/http_tracker_core/statistics/keeper.rs @@ -51,9 +51,9 @@ impl Keeper { #[cfg(test)] mod tests { - use crate::statistics::event::Event; - use crate::statistics::keeper::Keeper; - use crate::statistics::metrics::Metrics; + use crate::packages::http_tracker_core::statistics::event::Event; + use crate::packages::http_tracker_core::statistics::keeper::Keeper; + use crate::packages::http_tracker_core::statistics::metrics::Metrics; #[tokio::test] async fn should_contain_the_tracker_statistics() { @@ -70,7 +70,7 @@ mod tests { let event_sender = stats_tracker.run_event_listener(); - let result = event_sender.send_event(Event::Udp4Connect).await; + let result = event_sender.send_event(Event::Tcp4Announce).await; assert!(result.is_some()); } diff --git a/src/packages/http_tracker_core/statistics/metrics.rs b/src/packages/http_tracker_core/statistics/metrics.rs new file mode 100644 index 000000000..ae4db9704 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/metrics.rs @@ -0,0 +1,30 @@ +/// Metrics collected by the tracker. +/// +/// - Number of connections handled +/// - Number of `announce` requests handled +/// - Number of `scrape` request handled +/// +/// These metrics are collected for each connection type: UDP and HTTP +/// and also for each IP version used by the peers: IPv4 and IPv6. +#[derive(Debug, PartialEq, Default)] +pub struct Metrics { + /// Total number of TCP (HTTP tracker) connections from IPv4 peers. + /// Since the HTTP tracker spec does not require a handshake, this metric + /// increases for every HTTP request. + pub tcp4_connections_handled: u64, + + /// Total number of TCP (HTTP tracker) `announce` requests from IPv4 peers. + pub tcp4_announces_handled: u64, + + /// Total number of TCP (HTTP tracker) `scrape` requests from IPv4 peers. + pub tcp4_scrapes_handled: u64, + + /// Total number of TCP (HTTP tracker) connections from IPv6 peers. + pub tcp6_connections_handled: u64, + + /// Total number of TCP (HTTP tracker) `announce` requests from IPv6 peers. + pub tcp6_announces_handled: u64, + + /// Total number of TCP (HTTP tracker) `scrape` requests from IPv6 peers. + pub tcp6_scrapes_handled: u64, +} diff --git a/src/packages/http_tracker_core/statistics/mod.rs b/src/packages/http_tracker_core/statistics/mod.rs new file mode 100644 index 000000000..939a41061 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/mod.rs @@ -0,0 +1,6 @@ +pub mod event; +pub mod keeper; +pub mod metrics; +pub mod repository; +pub mod services; +pub mod setup; diff --git a/src/packages/http_tracker_core/statistics/repository.rs b/src/packages/http_tracker_core/statistics/repository.rs new file mode 100644 index 000000000..41f048e29 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/repository.rs @@ -0,0 +1,66 @@ +use std::sync::Arc; + +use tokio::sync::{RwLock, RwLockReadGuard}; + +use super::metrics::Metrics; + +/// A repository for the tracker metrics. +#[derive(Clone)] +pub struct Repository { + pub stats: Arc>, +} + +impl Default for Repository { + fn default() -> Self { + Self::new() + } +} + +impl Repository { + #[must_use] + pub fn new() -> Self { + Self { + stats: Arc::new(RwLock::new(Metrics::default())), + } + } + + pub async fn get_stats(&self) -> RwLockReadGuard<'_, Metrics> { + self.stats.read().await + } + + pub async fn increase_tcp4_announces(&self) { + let mut stats_lock = self.stats.write().await; + stats_lock.tcp4_announces_handled += 1; + drop(stats_lock); + } + + pub async fn increase_tcp4_connections(&self) { + let mut stats_lock = self.stats.write().await; + stats_lock.tcp4_connections_handled += 1; + drop(stats_lock); + } + + pub async fn increase_tcp4_scrapes(&self) { + let mut stats_lock = self.stats.write().await; + stats_lock.tcp4_scrapes_handled += 1; + drop(stats_lock); + } + + pub async fn increase_tcp6_announces(&self) { + let mut stats_lock = self.stats.write().await; + stats_lock.tcp6_announces_handled += 1; + drop(stats_lock); + } + + pub async fn increase_tcp6_connections(&self) { + let mut stats_lock = self.stats.write().await; + stats_lock.tcp6_connections_handled += 1; + drop(stats_lock); + } + + pub async fn increase_tcp6_scrapes(&self) { + let mut stats_lock = self.stats.write().await; + stats_lock.tcp6_scrapes_handled += 1; + drop(stats_lock); + } +} diff --git a/src/packages/http_tracker_core/statistics/services.rs b/src/packages/http_tracker_core/statistics/services.rs new file mode 100644 index 000000000..51065bf63 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/services.rs @@ -0,0 +1,106 @@ +//! Statistics services. +//! +//! It includes: +//! +//! - A [`factory`](crate::packages::http_tracker_core::statistics::setup::factory) function to build the structs needed to collect the tracker metrics. +//! - A [`get_metrics`] service to get the tracker [`metrics`](crate::packages::http_tracker_core::statistics::metrics::Metrics). +//! +//! Tracker metrics are collected using a Publisher-Subscribe pattern. +//! +//! The factory function builds two structs: +//! +//! - An statistics event [`Sender`](crate::packages::http_tracker_core::statistics::event::sender::Sender) +//! - An statistics [`Repository`] +//! +//! ```text +//! let (stats_event_sender, stats_repository) = factory(tracker_usage_statistics); +//! ``` +//! +//! The statistics repository is responsible for storing the metrics in memory. +//! The statistics event sender allows sending events related to metrics. +//! There is an event listener that is receiving all the events and processing them with an event handler. +//! Then, the event handler updates the metrics depending on the received event. +use std::sync::Arc; + +use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; +use packages::http_tracker_core::statistics::metrics::Metrics; +use packages::http_tracker_core::statistics::repository::Repository; +use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; + +use crate::packages; + +/// All the metrics collected by the tracker. +#[derive(Debug, PartialEq)] +pub struct TrackerMetrics { + /// Domain level metrics. + /// + /// General metrics for all torrents (number of seeders, leechers, etcetera) + pub torrents_metrics: TorrentsMetrics, + + /// Application level metrics. Usage statistics/metrics. + /// + /// Metrics about how the tracker is been used (number of number of http scrape requests, etcetera) + pub protocol_metrics: Metrics, +} + +/// It returns all the [`TrackerMetrics`] +pub async fn get_metrics( + in_memory_torrent_repository: Arc, + stats_repository: Arc, +) -> TrackerMetrics { + let torrents_metrics = in_memory_torrent_repository.get_torrents_metrics(); + let stats = stats_repository.get_stats().await; + + TrackerMetrics { + torrents_metrics, + protocol_metrics: Metrics { + // TCPv4 + tcp4_connections_handled: stats.tcp4_connections_handled, + tcp4_announces_handled: stats.tcp4_announces_handled, + tcp4_scrapes_handled: stats.tcp4_scrapes_handled, + // TCPv6 + tcp6_connections_handled: stats.tcp6_connections_handled, + tcp6_announces_handled: stats.tcp6_announces_handled, + tcp6_scrapes_handled: stats.tcp6_scrapes_handled, + }, + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; + use bittorrent_tracker_core::{self}; + use torrust_tracker_configuration::Configuration; + use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; + use torrust_tracker_test_helpers::configuration; + + use crate::packages::http_tracker_core::statistics::services::{get_metrics, TrackerMetrics}; + use crate::packages::http_tracker_core::{self, statistics}; + + pub fn tracker_configuration() -> Configuration { + configuration::ephemeral() + } + + #[tokio::test] + async fn the_statistics_service_should_return_the_tracker_metrics() { + let config = tracker_configuration(); + + let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); + + let (_http_stats_event_sender, http_stats_repository) = + http_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let http_stats_repository = Arc::new(http_stats_repository); + + let tracker_metrics = get_metrics(in_memory_torrent_repository.clone(), http_stats_repository.clone()).await; + + assert_eq!( + tracker_metrics, + TrackerMetrics { + torrents_metrics: TorrentsMetrics::default(), + protocol_metrics: statistics::metrics::Metrics::default(), + } + ); + } +} diff --git a/src/packages/http_tracker_core/statistics/setup.rs b/src/packages/http_tracker_core/statistics/setup.rs new file mode 100644 index 000000000..009f157d5 --- /dev/null +++ b/src/packages/http_tracker_core/statistics/setup.rs @@ -0,0 +1,54 @@ +//! Setup for the tracker statistics. +//! +//! The [`factory`] function builds the structs needed for handling the tracker metrics. +use crate::packages::http_tracker_core::statistics; + +/// It builds the structs needed for handling the tracker metrics. +/// +/// It returns: +/// +/// - An statistics event [`Sender`](crate::packages::http_tracker_core::statistics::event::sender::Sender) that allows you to send events related to statistics. +/// - An statistics [`Repository`](crate::packages::http_tracker_core::statistics::repository::Repository) which is an in-memory repository for the tracker metrics. +/// +/// When the input argument `tracker_usage_statistics`is false the setup does not run the event listeners, consequently the statistics +/// events are sent are received but not dispatched to the handler. +#[must_use] +pub fn factory( + tracker_usage_statistics: bool, +) -> ( + Option>, + statistics::repository::Repository, +) { + let mut stats_event_sender = None; + + let mut stats_tracker = statistics::keeper::Keeper::new(); + + if tracker_usage_statistics { + stats_event_sender = Some(stats_tracker.run_event_listener()); + } + + (stats_event_sender, stats_tracker.repository) +} + +#[cfg(test)] +mod test { + use super::factory; + + #[tokio::test] + async fn should_not_send_any_event_when_statistics_are_disabled() { + let tracker_usage_statistics = false; + + let (stats_event_sender, _stats_repository) = factory(tracker_usage_statistics); + + assert!(stats_event_sender.is_none()); + } + + #[tokio::test] + async fn should_send_events_when_statistics_are_enabled() { + let tracker_usage_statistics = true; + + let (stats_event_sender, _stats_repository) = factory(tracker_usage_statistics); + + assert!(stats_event_sender.is_some()); + } +} diff --git a/src/packages/mod.rs b/src/packages/mod.rs new file mode 100644 index 000000000..453c3d533 --- /dev/null +++ b/src/packages/mod.rs @@ -0,0 +1,6 @@ +//! This module contains logic pending to be extracted into workspace packages. +//! +//! It will be moved to the directory `packages`. +pub mod http_tracker_core; +pub mod tracker_api_core; +pub mod udp_tracker_core; diff --git a/src/packages/tracker_api_core/mod.rs b/src/packages/tracker_api_core/mod.rs new file mode 100644 index 000000000..3449ec7b4 --- /dev/null +++ b/src/packages/tracker_api_core/mod.rs @@ -0,0 +1 @@ +pub mod statistics; diff --git a/packages/tracker-core/src/statistics/metrics.rs b/src/packages/tracker_api_core/statistics/metrics.rs similarity index 100% rename from packages/tracker-core/src/statistics/metrics.rs rename to src/packages/tracker_api_core/statistics/metrics.rs diff --git a/src/core/statistics/mod.rs b/src/packages/tracker_api_core/statistics/mod.rs similarity index 51% rename from src/core/statistics/mod.rs rename to src/packages/tracker_api_core/statistics/mod.rs index 4e379ae78..a3c8a4b0e 100644 --- a/src/core/statistics/mod.rs +++ b/src/packages/tracker_api_core/statistics/mod.rs @@ -1 +1,2 @@ +pub mod metrics; pub mod services; diff --git a/src/packages/tracker_api_core/statistics/services.rs b/src/packages/tracker_api_core/statistics/services.rs new file mode 100644 index 000000000..bb8e71ab8 --- /dev/null +++ b/src/packages/tracker_api_core/statistics/services.rs @@ -0,0 +1,127 @@ +use std::sync::Arc; + +use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; +use packages::tracker_api_core::statistics::metrics::Metrics; +use tokio::sync::RwLock; +use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; + +use crate::packages::{self, http_tracker_core, udp_tracker_core}; +use crate::servers::udp::server::banning::BanService; + +/// All the metrics collected by the tracker. +#[derive(Debug, PartialEq)] +pub struct TrackerMetrics { + /// Domain level metrics. + /// + /// General metrics for all torrents (number of seeders, leechers, etcetera) + pub torrents_metrics: TorrentsMetrics, + + /// Application level metrics. Usage statistics/metrics. + /// + /// Metrics about how the tracker is been used (number of udp announce requests, number of http scrape requests, etcetera) + pub protocol_metrics: Metrics, +} + +/// It returns all the [`TrackerMetrics`] +pub async fn get_metrics( + in_memory_torrent_repository: Arc, + ban_service: Arc>, + http_stats_repository: Arc, + udp_stats_repository: Arc, +) -> TrackerMetrics { + let torrents_metrics = in_memory_torrent_repository.get_torrents_metrics(); + let udp_banned_ips_total = ban_service.read().await.get_banned_ips_total(); + let http_stats = http_stats_repository.get_stats().await; + let udp_stats = udp_stats_repository.get_stats().await; + + TrackerMetrics { + torrents_metrics, + protocol_metrics: Metrics { + // TCPv4 + tcp4_connections_handled: http_stats.tcp4_connections_handled, + tcp4_announces_handled: http_stats.tcp4_announces_handled, + tcp4_scrapes_handled: http_stats.tcp4_scrapes_handled, + // TCPv6 + tcp6_connections_handled: http_stats.tcp6_connections_handled, + tcp6_announces_handled: http_stats.tcp6_announces_handled, + tcp6_scrapes_handled: http_stats.tcp6_scrapes_handled, + // UDP + udp_requests_aborted: udp_stats.udp_requests_aborted, + udp_requests_banned: udp_stats.udp_requests_banned, + udp_banned_ips_total: udp_banned_ips_total as u64, + udp_avg_connect_processing_time_ns: udp_stats.udp_avg_connect_processing_time_ns, + udp_avg_announce_processing_time_ns: udp_stats.udp_avg_announce_processing_time_ns, + udp_avg_scrape_processing_time_ns: udp_stats.udp_avg_scrape_processing_time_ns, + // UDPv4 + udp4_requests: udp_stats.udp4_requests, + udp4_connections_handled: udp_stats.udp4_connections_handled, + udp4_announces_handled: udp_stats.udp4_announces_handled, + udp4_scrapes_handled: udp_stats.udp4_scrapes_handled, + udp4_responses: udp_stats.udp4_responses, + udp4_errors_handled: udp_stats.udp4_errors_handled, + // UDPv6 + udp6_requests: udp_stats.udp6_requests, + udp6_connections_handled: udp_stats.udp6_connections_handled, + udp6_announces_handled: udp_stats.udp6_announces_handled, + udp6_scrapes_handled: udp_stats.udp6_scrapes_handled, + udp6_responses: udp_stats.udp6_responses, + udp6_errors_handled: udp_stats.udp6_errors_handled, + }, + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; + use bittorrent_tracker_core::{self}; + use tokio::sync::RwLock; + use torrust_tracker_configuration::Configuration; + use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; + use torrust_tracker_test_helpers::configuration; + + use crate::packages::tracker_api_core::statistics::metrics::Metrics; + use crate::packages::tracker_api_core::statistics::services::{get_metrics, TrackerMetrics}; + use crate::packages::{http_tracker_core, udp_tracker_core}; + use crate::servers::udp::server::banning::BanService; + use crate::servers::udp::server::launcher::MAX_CONNECTION_ID_ERRORS_PER_IP; + + pub fn tracker_configuration() -> Configuration { + configuration::ephemeral() + } + + #[tokio::test] + async fn the_statistics_service_should_return_the_tracker_metrics() { + let config = tracker_configuration(); + + let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); + let ban_service = Arc::new(RwLock::new(BanService::new(MAX_CONNECTION_ID_ERRORS_PER_IP))); + + // HTTP stats + let (_http_stats_event_sender, http_stats_repository) = + http_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let http_stats_repository = Arc::new(http_stats_repository); + + // UDP stats + let (_udp_stats_event_sender, udp_stats_repository) = + udp_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let udp_stats_repository = Arc::new(udp_stats_repository); + + let tracker_metrics = get_metrics( + in_memory_torrent_repository.clone(), + ban_service.clone(), + http_stats_repository.clone(), + udp_stats_repository.clone(), + ) + .await; + + assert_eq!( + tracker_metrics, + TrackerMetrics { + torrents_metrics: TorrentsMetrics::default(), + protocol_metrics: Metrics::default(), + } + ); + } +} diff --git a/src/packages/udp_tracker_core/mod.rs b/src/packages/udp_tracker_core/mod.rs new file mode 100644 index 000000000..3449ec7b4 --- /dev/null +++ b/src/packages/udp_tracker_core/mod.rs @@ -0,0 +1 @@ +pub mod statistics; diff --git a/packages/tracker-core/src/statistics/event/handler.rs b/src/packages/udp_tracker_core/statistics/event/handler.rs similarity index 55% rename from packages/tracker-core/src/statistics/event/handler.rs rename to src/packages/udp_tracker_core/statistics/event/handler.rs index 93ac05dde..d696951d3 100644 --- a/packages/tracker-core/src/statistics/event/handler.rs +++ b/src/packages/udp_tracker_core/statistics/event/handler.rs @@ -1,28 +1,8 @@ -use crate::statistics::event::{Event, UdpResponseKind}; -use crate::statistics::repository::Repository; +use crate::packages::udp_tracker_core::statistics::event::{Event, UdpResponseKind}; +use crate::packages::udp_tracker_core::statistics::repository::Repository; pub async fn handle_event(event: Event, stats_repository: &Repository) { match event { - // TCP4 - Event::Tcp4Announce => { - stats_repository.increase_tcp4_announces().await; - stats_repository.increase_tcp4_connections().await; - } - Event::Tcp4Scrape => { - stats_repository.increase_tcp4_scrapes().await; - stats_repository.increase_tcp4_connections().await; - } - - // TCP6 - Event::Tcp6Announce => { - stats_repository.increase_tcp6_announces().await; - stats_repository.increase_tcp6_connections().await; - } - Event::Tcp6Scrape => { - stats_repository.increase_tcp6_scrapes().await; - stats_repository.increase_tcp6_connections().await; - } - // UDP Event::UdpRequestAborted => { stats_repository.increase_udp_requests_aborted().await; @@ -102,97 +82,9 @@ pub async fn handle_event(event: Event, stats_repository: &Repository) { #[cfg(test)] mod tests { - use crate::statistics::event::handler::handle_event; - use crate::statistics::event::Event; - use crate::statistics::repository::Repository; - - #[tokio::test] - async fn should_increase_the_tcp4_announces_counter_when_it_receives_a_tcp4_announce_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp4Announce, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp4_announces_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp4_connections_counter_when_it_receives_a_tcp4_announce_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp4Announce, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp4_connections_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp4_scrapes_counter_when_it_receives_a_tcp4_scrape_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp4Scrape, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp4_scrapes_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp4_connections_counter_when_it_receives_a_tcp4_scrape_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp4Scrape, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp4_connections_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp6_announces_counter_when_it_receives_a_tcp6_announce_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp6Announce, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp6_announces_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp6_connections_counter_when_it_receives_a_tcp6_announce_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp6Announce, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp6_connections_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp6_scrapes_counter_when_it_receives_a_tcp6_scrape_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp6Scrape, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp6_scrapes_handled, 1); - } - - #[tokio::test] - async fn should_increase_the_tcp6_connections_counter_when_it_receives_a_tcp6_scrape_event() { - let stats_repository = Repository::new(); - - handle_event(Event::Tcp6Scrape, &stats_repository).await; - - let stats = stats_repository.get_stats().await; - - assert_eq!(stats.tcp6_connections_handled, 1); - } + use crate::packages::udp_tracker_core::statistics::event::handler::handle_event; + use crate::packages::udp_tracker_core::statistics::event::Event; + use crate::packages::udp_tracker_core::statistics::repository::Repository; #[tokio::test] async fn should_increase_the_udp4_connections_counter_when_it_receives_a_udp4_connect_event() { diff --git a/packages/tracker-core/src/statistics/event/listener.rs b/src/packages/udp_tracker_core/statistics/event/listener.rs similarity index 79% rename from packages/tracker-core/src/statistics/event/listener.rs rename to src/packages/udp_tracker_core/statistics/event/listener.rs index f1a2e25de..6a84fbaa5 100644 --- a/packages/tracker-core/src/statistics/event/listener.rs +++ b/src/packages/udp_tracker_core/statistics/event/listener.rs @@ -2,7 +2,7 @@ use tokio::sync::mpsc; use super::handler::handle_event; use super::Event; -use crate::statistics::repository::Repository; +use crate::packages::udp_tracker_core::statistics::repository::Repository; pub async fn dispatch_events(mut receiver: mpsc::Receiver, stats_repository: Repository) { while let Some(event) = receiver.recv().await { diff --git a/packages/tracker-core/src/statistics/event/mod.rs b/src/packages/udp_tracker_core/statistics/event/mod.rs similarity index 94% rename from packages/tracker-core/src/statistics/event/mod.rs rename to src/packages/udp_tracker_core/statistics/event/mod.rs index 905aa0372..6a5343933 100644 --- a/packages/tracker-core/src/statistics/event/mod.rs +++ b/src/packages/udp_tracker_core/statistics/event/mod.rs @@ -16,10 +16,6 @@ pub mod sender; pub enum Event { // code-review: consider one single event for request type with data: Event::Announce { scheme: HTTPorUDP, ip_version: V4orV6 } // Attributes are enums too. - Tcp4Announce, - Tcp4Scrape, - Tcp6Announce, - Tcp6Scrape, UdpRequestAborted, UdpRequestBanned, Udp4Request, diff --git a/packages/tracker-core/src/statistics/event/sender.rs b/src/packages/udp_tracker_core/statistics/event/sender.rs similarity index 79% rename from packages/tracker-core/src/statistics/event/sender.rs rename to src/packages/udp_tracker_core/statistics/event/sender.rs index 1b663b5d1..68e197eca 100644 --- a/packages/tracker-core/src/statistics/event/sender.rs +++ b/src/packages/udp_tracker_core/statistics/event/sender.rs @@ -13,10 +13,10 @@ pub trait Sender: Sync + Send { fn send_event(&self, event: Event) -> BoxFuture<'_, Option>>>; } -/// An [`statistics::EventSender`](crate::core::statistics::event::sender::Sender) implementation. +/// An [`statistics::EventSender`](crate::packages::udp_tracker_core::statistics::event::sender::Sender) implementation. /// /// It uses a channel sender to send the statistic events. The channel is created by a -/// [`statistics::Keeper`](crate::core::statistics::keeper::Keeper) +/// [`statistics::Keeper`](crate::packages::udp_tracker_core::statistics::keeper::Keeper) #[allow(clippy::module_name_repetitions)] pub struct ChannelSender { pub(crate) sender: mpsc::Sender, diff --git a/src/packages/udp_tracker_core/statistics/keeper.rs b/src/packages/udp_tracker_core/statistics/keeper.rs new file mode 100644 index 000000000..9bd290145 --- /dev/null +++ b/src/packages/udp_tracker_core/statistics/keeper.rs @@ -0,0 +1,77 @@ +use tokio::sync::mpsc; + +use super::event::listener::dispatch_events; +use super::event::sender::{ChannelSender, Sender}; +use super::event::Event; +use super::repository::Repository; + +const CHANNEL_BUFFER_SIZE: usize = 65_535; + +/// The service responsible for keeping tracker metrics (listening to statistics events and handle them). +/// +/// It actively listen to new statistics events. When it receives a new event +/// it accordingly increases the counters. +pub struct Keeper { + pub repository: Repository, +} + +impl Default for Keeper { + fn default() -> Self { + Self::new() + } +} + +impl Keeper { + #[must_use] + pub fn new() -> Self { + Self { + repository: Repository::new(), + } + } + + #[must_use] + pub fn new_active_instance() -> (Box, Repository) { + let mut stats_tracker = Self::new(); + + let stats_event_sender = stats_tracker.run_event_listener(); + + (stats_event_sender, stats_tracker.repository) + } + + pub fn run_event_listener(&mut self) -> Box { + let (sender, receiver) = mpsc::channel::(CHANNEL_BUFFER_SIZE); + + let stats_repository = self.repository.clone(); + + tokio::spawn(async move { dispatch_events(receiver, stats_repository).await }); + + Box::new(ChannelSender { sender }) + } +} + +#[cfg(test)] +mod tests { + use crate::packages::udp_tracker_core::statistics::event::Event; + use crate::packages::udp_tracker_core::statistics::keeper::Keeper; + use crate::packages::udp_tracker_core::statistics::metrics::Metrics; + + #[tokio::test] + async fn should_contain_the_tracker_statistics() { + let stats_tracker = Keeper::new(); + + let stats = stats_tracker.repository.get_stats().await; + + assert_eq!(stats.udp4_announces_handled, Metrics::default().udp4_announces_handled); + } + + #[tokio::test] + async fn should_create_an_event_sender_to_send_statistical_events() { + let mut stats_tracker = Keeper::new(); + + let event_sender = stats_tracker.run_event_listener(); + + let result = event_sender.send_event(Event::Udp4Connect).await; + + assert!(result.is_some()); + } +} diff --git a/src/packages/udp_tracker_core/statistics/metrics.rs b/src/packages/udp_tracker_core/statistics/metrics.rs new file mode 100644 index 000000000..23357aab6 --- /dev/null +++ b/src/packages/udp_tracker_core/statistics/metrics.rs @@ -0,0 +1,67 @@ +/// Metrics collected by the tracker. +/// +/// - Number of connections handled +/// - Number of `announce` requests handled +/// - Number of `scrape` request handled +/// +/// These metrics are collected for each connection type: UDP and HTTP +/// and also for each IP version used by the peers: IPv4 and IPv6. +#[derive(Debug, PartialEq, Default)] +pub struct Metrics { + // UDP + /// Total number of UDP (UDP tracker) requests aborted. + pub udp_requests_aborted: u64, + + /// Total number of UDP (UDP tracker) requests banned. + pub udp_requests_banned: u64, + + /// Total number of banned IPs. + pub udp_banned_ips_total: u64, + + /// Average rounded time spent processing UDP connect requests. + pub udp_avg_connect_processing_time_ns: u64, + + /// Average rounded time spent processing UDP announce requests. + pub udp_avg_announce_processing_time_ns: u64, + + /// Average rounded time spent processing UDP scrape requests. + pub udp_avg_scrape_processing_time_ns: u64, + + // UDPv4 + /// Total number of UDP (UDP tracker) requests from IPv4 peers. + pub udp4_requests: u64, + + /// Total number of UDP (UDP tracker) connections from IPv4 peers. + pub udp4_connections_handled: u64, + + /// Total number of UDP (UDP tracker) `announce` requests from IPv4 peers. + pub udp4_announces_handled: u64, + + /// Total number of UDP (UDP tracker) `scrape` requests from IPv4 peers. + pub udp4_scrapes_handled: u64, + + /// Total number of UDP (UDP tracker) responses from IPv4 peers. + pub udp4_responses: u64, + + /// Total number of UDP (UDP tracker) `error` requests from IPv4 peers. + pub udp4_errors_handled: u64, + + // UDPv6 + /// Total number of UDP (UDP tracker) requests from IPv6 peers. + pub udp6_requests: u64, + + /// Total number of UDP (UDP tracker) `connection` requests from IPv6 peers. + pub udp6_connections_handled: u64, + + /// Total number of UDP (UDP tracker) `announce` requests from IPv6 peers. + pub udp6_announces_handled: u64, + + /// Total number of UDP (UDP tracker) `scrape` requests from IPv6 peers. + pub udp6_scrapes_handled: u64, + + /// Total number of UDP (UDP tracker) responses from IPv6 peers. + pub udp6_responses: u64, + + /// Total number of UDP (UDP tracker) `error` requests from IPv6 peers. + pub udp6_errors_handled: u64, +} diff --git a/src/packages/udp_tracker_core/statistics/mod.rs b/src/packages/udp_tracker_core/statistics/mod.rs new file mode 100644 index 000000000..939a41061 --- /dev/null +++ b/src/packages/udp_tracker_core/statistics/mod.rs @@ -0,0 +1,6 @@ +pub mod event; +pub mod keeper; +pub mod metrics; +pub mod repository; +pub mod services; +pub mod setup; diff --git a/packages/tracker-core/src/statistics/repository.rs b/src/packages/udp_tracker_core/statistics/repository.rs similarity index 83% rename from packages/tracker-core/src/statistics/repository.rs rename to src/packages/udp_tracker_core/statistics/repository.rs index ec5100073..22e793036 100644 --- a/packages/tracker-core/src/statistics/repository.rs +++ b/src/packages/udp_tracker_core/statistics/repository.rs @@ -29,42 +29,6 @@ impl Repository { self.stats.read().await } - pub async fn increase_tcp4_announces(&self) { - let mut stats_lock = self.stats.write().await; - stats_lock.tcp4_announces_handled += 1; - drop(stats_lock); - } - - pub async fn increase_tcp4_connections(&self) { - let mut stats_lock = self.stats.write().await; - stats_lock.tcp4_connections_handled += 1; - drop(stats_lock); - } - - pub async fn increase_tcp4_scrapes(&self) { - let mut stats_lock = self.stats.write().await; - stats_lock.tcp4_scrapes_handled += 1; - drop(stats_lock); - } - - pub async fn increase_tcp6_announces(&self) { - let mut stats_lock = self.stats.write().await; - stats_lock.tcp6_announces_handled += 1; - drop(stats_lock); - } - - pub async fn increase_tcp6_connections(&self) { - let mut stats_lock = self.stats.write().await; - stats_lock.tcp6_connections_handled += 1; - drop(stats_lock); - } - - pub async fn increase_tcp6_scrapes(&self) { - let mut stats_lock = self.stats.write().await; - stats_lock.tcp6_scrapes_handled += 1; - drop(stats_lock); - } - pub async fn increase_udp_requests_aborted(&self) { let mut stats_lock = self.stats.write().await; stats_lock.udp_requests_aborted += 1; diff --git a/src/core/statistics/services.rs b/src/packages/udp_tracker_core/statistics/services.rs similarity index 71% rename from src/core/statistics/services.rs rename to src/packages/udp_tracker_core/statistics/services.rs index a4bcc411e..80e1d8fb5 100644 --- a/src/core/statistics/services.rs +++ b/src/packages/udp_tracker_core/statistics/services.rs @@ -2,14 +2,14 @@ //! //! It includes: //! -//! - A [`factory`](bittorrent_tracker_core::statistics::setup::factory) function to build the structs needed to collect the tracker metrics. -//! - A [`get_metrics`] service to get the tracker [`metrics`](bittorrent_tracker_core::statistics::metrics::Metrics). +//! - A [`factory`](crate::packages::udp_tracker_core::statistics::setup::factory) function to build the structs needed to collect the tracker metrics. +//! - A [`get_metrics`] service to get the tracker [`metrics`](crate::packages::udp_tracker_core::statistics::metrics::Metrics). //! //! Tracker metrics are collected using a Publisher-Subscribe pattern. //! //! The factory function builds two structs: //! -//! - An statistics event [`Sender`](bittorrent_tracker_core::statistics::event::sender::Sender) +//! - An statistics event [`Sender`](crate::packages::udp_tracker_core::statistics::event::sender::Sender) //! - An statistics [`Repository`] //! //! ```text @@ -21,7 +21,7 @@ //! There is an event listener that is receiving all the events and processing them with an event handler. //! Then, the event handler updates the metrics depending on the received event. //! -//! For example, if you send the event [`Event::Udp4Connect`](bittorrent_tracker_core::statistics::event::Event::Udp4Connect): +//! For example, if you send the event [`Event::Udp4Connect`](crate::packages::udp_tracker_core::statistics::event::Event::Udp4Connect): //! //! ```text //! let result = event_sender.send_event(Event::Udp4Connect).await; @@ -38,14 +38,29 @@ //! ``` use std::sync::Arc; -use bittorrent_tracker_core::statistics::metrics::Metrics; -use bittorrent_tracker_core::statistics::repository::Repository; -use bittorrent_tracker_core::statistics::services::TrackerMetrics; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; +use packages::udp_tracker_core::statistics::metrics::Metrics; +use packages::udp_tracker_core::statistics::repository::Repository; use tokio::sync::RwLock; +use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; +use crate::packages; use crate::servers::udp::server::banning::BanService; +/// All the metrics collected by the tracker. +#[derive(Debug, PartialEq)] +pub struct TrackerMetrics { + /// Domain level metrics. + /// + /// General metrics for all torrents (number of seeders, leechers, etcetera) + pub torrents_metrics: TorrentsMetrics, + + /// Application level metrics. Usage statistics/metrics. + /// + /// Metrics about how the tracker is been used (number of udp announce requests, etcetera) + pub protocol_metrics: Metrics, +} + /// It returns all the [`TrackerMetrics`] pub async fn get_metrics( in_memory_torrent_repository: Arc, @@ -59,14 +74,6 @@ pub async fn get_metrics( TrackerMetrics { torrents_metrics, protocol_metrics: Metrics { - // TCPv4 - tcp4_connections_handled: stats.tcp4_connections_handled, - tcp4_announces_handled: stats.tcp4_announces_handled, - tcp4_scrapes_handled: stats.tcp4_scrapes_handled, - // TCPv6 - tcp6_connections_handled: stats.tcp6_connections_handled, - tcp6_announces_handled: stats.tcp6_announces_handled, - tcp6_scrapes_handled: stats.tcp6_scrapes_handled, // UDP udp_requests_aborted: stats.udp_requests_aborted, udp_requests_banned: stats.udp_requests_banned, @@ -96,15 +103,16 @@ pub async fn get_metrics( mod tests { use std::sync::Arc; - use bittorrent_tracker_core::statistics::services::TrackerMetrics; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; - use bittorrent_tracker_core::{self, statistics}; + use bittorrent_tracker_core::{self}; use tokio::sync::RwLock; use torrust_tracker_configuration::Configuration; use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_test_helpers::configuration; - use crate::core::statistics::services::get_metrics; + use crate::packages::udp_tracker_core; + use crate::packages::udp_tracker_core::statistics; + use crate::packages::udp_tracker_core::statistics::services::{get_metrics, TrackerMetrics}; use crate::servers::udp::server::banning::BanService; use crate::servers::udp::server::launcher::MAX_CONNECTION_ID_ERRORS_PER_IP; @@ -117,14 +125,16 @@ mod tests { let config = tracker_configuration(); let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); - let (_stats_event_sender, stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - let stats_repository = Arc::new(stats_repository); let ban_service = Arc::new(RwLock::new(BanService::new(MAX_CONNECTION_ID_ERRORS_PER_IP))); + let (_udp_stats_event_sender, udp_stats_repository) = + udp_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let udp_stats_repository = Arc::new(udp_stats_repository); + let tracker_metrics = get_metrics( in_memory_torrent_repository.clone(), ban_service.clone(), - stats_repository.clone(), + udp_stats_repository.clone(), ) .await; diff --git a/packages/tracker-core/src/statistics/setup.rs b/src/packages/udp_tracker_core/statistics/setup.rs similarity index 79% rename from packages/tracker-core/src/statistics/setup.rs rename to src/packages/udp_tracker_core/statistics/setup.rs index 701392176..c85c715a2 100644 --- a/packages/tracker-core/src/statistics/setup.rs +++ b/src/packages/udp_tracker_core/statistics/setup.rs @@ -1,14 +1,14 @@ //! Setup for the tracker statistics. //! //! The [`factory`] function builds the structs needed for handling the tracker metrics. -use crate::statistics; +use crate::packages::udp_tracker_core::statistics; /// It builds the structs needed for handling the tracker metrics. /// /// It returns: /// -/// - An statistics event [`Sender`](crate::core::statistics::event::sender::Sender) that allows you to send events related to statistics. -/// - An statistics [`Repository`](crate::core::statistics::repository::Repository) which is an in-memory repository for the tracker metrics. +/// - An statistics event [`Sender`](crate::packages::udp_tracker_core::statistics::event::sender::Sender) that allows you to send events related to statistics. +/// - An statistics [`Repository`](crate::packages::udp_tracker_core::statistics::repository::Repository) which is an in-memory repository for the tracker metrics. /// /// When the input argument `tracker_usage_statistics`is false the setup does not run the event listeners, consequently the statistics /// events are sent are received but not dispatched to the handler. diff --git a/src/servers/apis/v1/context/stats/handlers.rs b/src/servers/apis/v1/context/stats/handlers.rs index b4ead78ea..820f39909 100644 --- a/src/servers/apis/v1/context/stats/handlers.rs +++ b/src/servers/apis/v1/context/stats/handlers.rs @@ -5,13 +5,13 @@ use std::sync::Arc; use axum::extract::State; use axum::response::Response; use axum_extra::extract::Query; -use bittorrent_tracker_core::statistics::repository::Repository; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use serde::Deserialize; use tokio::sync::RwLock; use super::responses::{metrics_response, stats_response}; -use crate::core::statistics::services::get_metrics; +use crate::packages::tracker_api_core::statistics::services::get_metrics; +use crate::packages::{http_tracker_core, udp_tracker_core}; use crate::servers::udp::server::banning::BanService; #[derive(Deserialize, Debug, Default)] @@ -40,10 +40,15 @@ pub struct QueryParams { /// for more information about this endpoint. #[allow(clippy::type_complexity)] pub async fn get_stats_handler( - State(state): State<(Arc, Arc>, Arc)>, + State(state): State<( + Arc, + Arc>, + Arc, + Arc, + )>, params: Query, ) -> Response { - let metrics = get_metrics(state.0.clone(), state.1.clone(), state.2.clone()).await; + let metrics = get_metrics(state.0.clone(), state.1.clone(), state.2.clone(), state.3.clone()).await; match params.0.format { Some(format) => match format { diff --git a/src/servers/apis/v1/context/stats/resources.rs b/src/servers/apis/v1/context/stats/resources.rs index d4a0ec7ec..8477ca5cb 100644 --- a/src/servers/apis/v1/context/stats/resources.rs +++ b/src/servers/apis/v1/context/stats/resources.rs @@ -1,8 +1,9 @@ //! API resources for the [`stats`](crate::servers::apis::v1::context::stats) //! API context. -use bittorrent_tracker_core::statistics::services::TrackerMetrics; use serde::{Deserialize, Serialize}; +use crate::packages::tracker_api_core::statistics::services::TrackerMetrics; + /// It contains all the statistics generated by the tracker. #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct Stats { @@ -117,11 +118,12 @@ impl From for Stats { #[cfg(test)] mod tests { - use bittorrent_tracker_core::statistics::metrics::Metrics; - use bittorrent_tracker_core::statistics::services::TrackerMetrics; + use packages::tracker_api_core::statistics::metrics::Metrics; use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use super::Stats; + use crate::packages::tracker_api_core::statistics::services::TrackerMetrics; + use crate::packages::{self}; #[test] fn stats_resource_should_be_converted_from_tracker_metrics() { diff --git a/src/servers/apis/v1/context/stats/responses.rs b/src/servers/apis/v1/context/stats/responses.rs index fc74b5f8d..5a71c4235 100644 --- a/src/servers/apis/v1/context/stats/responses.rs +++ b/src/servers/apis/v1/context/stats/responses.rs @@ -1,9 +1,9 @@ //! API responses for the [`stats`](crate::servers::apis::v1::context::stats) //! API context. use axum::response::{IntoResponse, Json, Response}; -use bittorrent_tracker_core::statistics::services::TrackerMetrics; use super::resources::Stats; +use crate::packages::tracker_api_core::statistics::services::TrackerMetrics; /// `200` response that contains the [`Stats`] resource as json. #[must_use] diff --git a/src/servers/apis/v1/context/stats/routes.rs b/src/servers/apis/v1/context/stats/routes.rs index 4c80f110d..e660005ec 100644 --- a/src/servers/apis/v1/context/stats/routes.rs +++ b/src/servers/apis/v1/context/stats/routes.rs @@ -18,7 +18,8 @@ pub fn add(prefix: &str, router: Router, http_api_container: &Arc, Arc, Arc, - Arc>>, + Arc>>, )>, ExtractRequest(announce_request): ExtractRequest, ExtractClientIpSources(client_ip_sources): ExtractClientIpSources, @@ -75,7 +75,7 @@ pub async fn handle_with_key( Arc, Arc, Arc, - Arc>>, + Arc>>, )>, ExtractRequest(announce_request): ExtractRequest, ExtractClientIpSources(client_ip_sources): ExtractClientIpSources, @@ -106,7 +106,7 @@ async fn handle( announce_handler: &Arc, authentication_service: &Arc, whitelist_authorization: &Arc, - opt_stats_event_sender: &Arc>>, + opt_http_stats_event_sender: &Arc>>, announce_request: &Announce, client_ip_sources: &ClientIpSources, maybe_key: Option, @@ -116,7 +116,7 @@ async fn handle( announce_handler, authentication_service, whitelist_authorization, - opt_stats_event_sender, + opt_http_stats_event_sender, announce_request, client_ip_sources, maybe_key, @@ -141,7 +141,7 @@ async fn handle_announce( announce_handler: &Arc, authentication_service: &Arc, whitelist_authorization: &Arc, - opt_stats_event_sender: &Arc>>, + opt_http_stats_event_sender: &Arc>>, announce_request: &Announce, client_ip_sources: &ClientIpSources, maybe_key: Option, @@ -180,7 +180,7 @@ async fn handle_announce( let announce_data = services::announce::invoke( announce_handler.clone(), - opt_stats_event_sender.clone(), + opt_http_stats_event_sender.clone(), announce_request.info_hash, &mut peer, &peers_wanted, @@ -256,8 +256,6 @@ mod tests { use bittorrent_tracker_core::authentication::service::AuthenticationService; use bittorrent_tracker_core::core_tests::sample_info_hash; use bittorrent_tracker_core::databases::setup::initialize_database; - use bittorrent_tracker_core::statistics; - use bittorrent_tracker_core::statistics::event::sender::Sender; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; use bittorrent_tracker_core::whitelist::authorization::WhitelistAuthorization; @@ -265,31 +263,36 @@ mod tests { use torrust_tracker_configuration::{Configuration, Core}; use torrust_tracker_test_helpers::configuration; + use crate::packages::http_tracker_core; + struct CoreTrackerServices { pub core_config: Arc, pub announce_handler: Arc, - pub stats_event_sender: Arc>>, pub whitelist_authorization: Arc, pub authentication_service: Arc, } - fn initialize_private_tracker() -> CoreTrackerServices { + struct CoreHttpTrackerServices { + pub http_stats_event_sender: Arc>>, + } + + fn initialize_private_tracker() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_private()) } - fn initialize_listed_tracker() -> CoreTrackerServices { + fn initialize_listed_tracker() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_listed()) } - fn initialize_tracker_on_reverse_proxy() -> CoreTrackerServices { + fn initialize_tracker_on_reverse_proxy() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_with_reverse_proxy()) } - fn initialize_tracker_not_on_reverse_proxy() -> CoreTrackerServices { + fn initialize_tracker_not_on_reverse_proxy() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_without_reverse_proxy()) } - fn initialize_core_tracker_services(config: &Configuration) -> CoreTrackerServices { + fn initialize_core_tracker_services(config: &Configuration) -> (CoreTrackerServices, CoreHttpTrackerServices) { let core_config = Arc::new(config.core.clone()); let database = initialize_database(config); let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); @@ -298,21 +301,27 @@ mod tests { let authentication_service = Arc::new(AuthenticationService::new(&config.core, &in_memory_key_repository)); let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); let db_torrent_repository = Arc::new(DatabasePersistentTorrentRepository::new(&database)); - let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - let stats_event_sender = Arc::new(stats_event_sender); let announce_handler = Arc::new(AnnounceHandler::new( &config.core, &in_memory_torrent_repository, &db_torrent_repository, )); - CoreTrackerServices { - core_config, - announce_handler, - stats_event_sender, - whitelist_authorization, - authentication_service, - } + // HTTP stats + let (http_stats_event_sender, http_stats_repository) = + http_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let http_stats_event_sender = Arc::new(http_stats_event_sender); + let _http_stats_repository = Arc::new(http_stats_repository); + + ( + CoreTrackerServices { + core_config, + announce_handler, + whitelist_authorization, + authentication_service, + }, + CoreHttpTrackerServices { http_stats_event_sender }, + ) } fn sample_announce_request() -> Announce { @@ -355,7 +364,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_authentication_key_is_missing() { - let core_tracker_services = initialize_private_tracker(); + let (core_tracker_services, http_core_tracker_services) = initialize_private_tracker(); let maybe_key = None; @@ -364,7 +373,7 @@ mod tests { &core_tracker_services.announce_handler, &core_tracker_services.authentication_service, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &http_core_tracker_services.http_stats_event_sender, &sample_announce_request(), &sample_client_ip_sources(), maybe_key, @@ -380,7 +389,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_authentication_key_is_invalid() { - let core_tracker_services = initialize_private_tracker(); + let (core_tracker_services, http_core_tracker_services) = initialize_private_tracker(); let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(); @@ -391,7 +400,7 @@ mod tests { &core_tracker_services.announce_handler, &core_tracker_services.authentication_service, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &http_core_tracker_services.http_stats_event_sender, &sample_announce_request(), &sample_client_ip_sources(), maybe_key, @@ -411,7 +420,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_announced_torrent_is_not_whitelisted() { - let core_tracker_services = initialize_listed_tracker(); + let (core_tracker_services, http_core_tracker_services) = initialize_listed_tracker(); let announce_request = sample_announce_request(); @@ -420,7 +429,7 @@ mod tests { &core_tracker_services.announce_handler, &core_tracker_services.authentication_service, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &http_core_tracker_services.http_stats_event_sender, &announce_request, &sample_client_ip_sources(), None, @@ -448,7 +457,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_right_most_x_forwarded_for_header_ip_is_not_available() { - let core_tracker_services = initialize_tracker_on_reverse_proxy(); + let (core_tracker_services, http_core_tracker_services) = initialize_tracker_on_reverse_proxy(); let client_ip_sources = ClientIpSources { right_most_x_forwarded_for: None, @@ -460,7 +469,7 @@ mod tests { &core_tracker_services.announce_handler, &core_tracker_services.authentication_service, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &http_core_tracker_services.http_stats_event_sender, &sample_announce_request(), &client_ip_sources, None, @@ -485,7 +494,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_client_ip_from_the_connection_info_is_not_available() { - let core_tracker_services = initialize_tracker_not_on_reverse_proxy(); + let (core_tracker_services, http_core_tracker_services) = initialize_tracker_not_on_reverse_proxy(); let client_ip_sources = ClientIpSources { right_most_x_forwarded_for: None, @@ -497,7 +506,7 @@ mod tests { &core_tracker_services.announce_handler, &core_tracker_services.authentication_service, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &http_core_tracker_services.http_stats_event_sender, &sample_announce_request(), &client_ip_sources, None, diff --git a/src/servers/http/v1/handlers/scrape.rs b/src/servers/http/v1/handlers/scrape.rs index 1b9196e25..09af385fb 100644 --- a/src/servers/http/v1/handlers/scrape.rs +++ b/src/servers/http/v1/handlers/scrape.rs @@ -15,11 +15,11 @@ use bittorrent_http_protocol::v1::services::peer_ip_resolver::{self, ClientIpSou use bittorrent_tracker_core::authentication::service::AuthenticationService; use bittorrent_tracker_core::authentication::Key; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; -use bittorrent_tracker_core::statistics::event::sender::Sender; use hyper::StatusCode; use torrust_tracker_configuration::Core; use torrust_tracker_primitives::core::ScrapeData; +use crate::packages::http_tracker_core; use crate::servers::http::v1::extractors::authentication_key::Extract as ExtractKey; use crate::servers::http::v1::extractors::client_ip_sources::Extract as ExtractClientIpSources; use crate::servers::http::v1::extractors::scrape_request::ExtractRequest; @@ -34,7 +34,7 @@ pub async fn handle_without_key( Arc, Arc, Arc, - Arc>>, + Arc>>, )>, ExtractRequest(scrape_request): ExtractRequest, ExtractClientIpSources(client_ip_sources): ExtractClientIpSources, @@ -64,7 +64,7 @@ pub async fn handle_with_key( Arc, Arc, Arc, - Arc>>, + Arc>>, )>, ExtractRequest(scrape_request): ExtractRequest, ExtractClientIpSources(client_ip_sources): ExtractClientIpSources, @@ -89,7 +89,7 @@ async fn handle( core_config: &Arc, scrape_handler: &Arc, authentication_service: &Arc, - stats_event_sender: &Arc>>, + http_stats_event_sender: &Arc>>, scrape_request: &Scrape, client_ip_sources: &ClientIpSources, maybe_key: Option, @@ -98,7 +98,7 @@ async fn handle( core_config, scrape_handler, authentication_service, - stats_event_sender, + http_stats_event_sender, scrape_request, client_ip_sources, maybe_key, @@ -122,7 +122,7 @@ async fn handle_scrape( core_config: &Arc, scrape_handler: &Arc, authentication_service: &Arc, - opt_stats_event_sender: &Arc>>, + opt_http_stats_event_sender: &Arc>>, scrape_request: &Scrape, client_ip_sources: &ClientIpSources, maybe_key: Option, @@ -149,9 +149,15 @@ async fn handle_scrape( }; if return_real_scrape_data { - Ok(services::scrape::invoke(scrape_handler, opt_stats_event_sender, &scrape_request.info_hashes, &peer_ip).await) + Ok(services::scrape::invoke( + scrape_handler, + opt_http_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) + Ok(services::scrape::fake(opt_http_stats_event_sender, &scrape_request.info_hashes, &peer_ip).await) } } @@ -174,53 +180,62 @@ mod tests { use bittorrent_tracker_core::authentication::key::repository::in_memory::InMemoryKeyRepository; use bittorrent_tracker_core::authentication::service::AuthenticationService; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; - use bittorrent_tracker_core::statistics; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::whitelist::authorization::WhitelistAuthorization; use bittorrent_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist; use torrust_tracker_configuration::{Configuration, Core}; use torrust_tracker_test_helpers::configuration; + use crate::packages::http_tracker_core; + struct CoreTrackerServices { pub core_config: Arc, pub scrape_handler: Arc, - pub stats_event_sender: Arc>>, pub authentication_service: Arc, } - fn initialize_private_tracker() -> CoreTrackerServices { + struct CoreHttpTrackerServices { + pub http_stats_event_sender: Arc>>, + } + + fn initialize_private_tracker() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_private()) } - fn initialize_listed_tracker() -> CoreTrackerServices { + fn initialize_listed_tracker() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_listed()) } - fn initialize_tracker_on_reverse_proxy() -> CoreTrackerServices { + fn initialize_tracker_on_reverse_proxy() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_with_reverse_proxy()) } - fn initialize_tracker_not_on_reverse_proxy() -> CoreTrackerServices { + fn initialize_tracker_not_on_reverse_proxy() -> (CoreTrackerServices, CoreHttpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_without_reverse_proxy()) } - fn initialize_core_tracker_services(config: &Configuration) -> CoreTrackerServices { + fn initialize_core_tracker_services(config: &Configuration) -> (CoreTrackerServices, CoreHttpTrackerServices) { let core_config = Arc::new(config.core.clone()); let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); let whitelist_authorization = Arc::new(WhitelistAuthorization::new(&config.core, &in_memory_whitelist.clone())); let in_memory_key_repository = Arc::new(InMemoryKeyRepository::default()); let authentication_service = Arc::new(AuthenticationService::new(&config.core, &in_memory_key_repository)); let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); - let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - let stats_event_sender = Arc::new(stats_event_sender); let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); - CoreTrackerServices { - core_config, - scrape_handler, - stats_event_sender, - authentication_service, - } + // HTTP stats + let (http_stats_event_sender, _http_stats_repository) = + http_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let http_stats_event_sender = Arc::new(http_stats_event_sender); + + ( + CoreTrackerServices { + core_config, + scrape_handler, + authentication_service, + }, + CoreHttpTrackerServices { http_stats_event_sender }, + ) } fn sample_scrape_request() -> Scrape { @@ -254,7 +269,7 @@ mod tests { #[tokio::test] async fn it_should_return_zeroed_swarm_metadata_when_the_authentication_key_is_missing() { - let core_tracker_services = initialize_private_tracker(); + let (core_tracker_services, core_http_tracker_services) = initialize_private_tracker(); let scrape_request = sample_scrape_request(); let maybe_key = None; @@ -263,7 +278,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.scrape_handler, &core_tracker_services.authentication_service, - &core_tracker_services.stats_event_sender, + &core_http_tracker_services.http_stats_event_sender, &scrape_request, &sample_client_ip_sources(), maybe_key, @@ -278,7 +293,7 @@ mod tests { #[tokio::test] async fn it_should_return_zeroed_swarm_metadata_when_the_authentication_key_is_invalid() { - let core_tracker_services = initialize_private_tracker(); + let (core_tracker_services, core_http_tracker_services) = initialize_private_tracker(); let scrape_request = sample_scrape_request(); let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(); @@ -288,7 +303,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.scrape_handler, &core_tracker_services.authentication_service, - &core_tracker_services.stats_event_sender, + &core_http_tracker_services.http_stats_event_sender, &scrape_request, &sample_client_ip_sources(), maybe_key, @@ -311,7 +326,7 @@ mod tests { #[tokio::test] async fn it_should_return_zeroed_swarm_metadata_when_the_torrent_is_not_whitelisted() { - let core_tracker_services = initialize_listed_tracker(); + let (core_tracker_services, core_http_tracker_services) = initialize_listed_tracker(); let scrape_request = sample_scrape_request(); @@ -319,7 +334,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.scrape_handler, &core_tracker_services.authentication_service, - &core_tracker_services.stats_event_sender, + &core_http_tracker_services.http_stats_event_sender, &scrape_request, &sample_client_ip_sources(), None, @@ -343,7 +358,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_right_most_x_forwarded_for_header_ip_is_not_available() { - let core_tracker_services = initialize_tracker_on_reverse_proxy(); + let (core_tracker_services, core_http_tracker_services) = initialize_tracker_on_reverse_proxy(); let client_ip_sources = ClientIpSources { right_most_x_forwarded_for: None, @@ -354,7 +369,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.scrape_handler, &core_tracker_services.authentication_service, - &core_tracker_services.stats_event_sender, + &core_http_tracker_services.http_stats_event_sender, &sample_scrape_request(), &client_ip_sources, None, @@ -379,7 +394,7 @@ mod tests { #[tokio::test] async fn it_should_fail_when_the_client_ip_from_the_connection_info_is_not_available() { - let core_tracker_services = initialize_tracker_not_on_reverse_proxy(); + let (core_tracker_services, core_http_tracker_services) = initialize_tracker_not_on_reverse_proxy(); let client_ip_sources = ClientIpSources { right_most_x_forwarded_for: None, @@ -390,7 +405,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.scrape_handler, &core_tracker_services.authentication_service, - &core_tracker_services.stats_event_sender, + &core_http_tracker_services.http_stats_event_sender, &sample_scrape_request(), &client_ip_sources, None, diff --git a/src/servers/http/v1/routes.rs b/src/servers/http/v1/routes.rs index ed9aa05e6..73f4e5f29 100644 --- a/src/servers/http/v1/routes.rs +++ b/src/servers/http/v1/routes.rs @@ -43,7 +43,7 @@ pub fn router(http_tracker_container: Arc, server_socket_a http_tracker_container.announce_handler.clone(), http_tracker_container.authentication_service.clone(), http_tracker_container.whitelist_authorization.clone(), - http_tracker_container.stats_event_sender.clone(), + http_tracker_container.http_stats_event_sender.clone(), )), ) .route( @@ -53,7 +53,7 @@ pub fn router(http_tracker_container: Arc, server_socket_a http_tracker_container.announce_handler.clone(), http_tracker_container.authentication_service.clone(), http_tracker_container.whitelist_authorization.clone(), - http_tracker_container.stats_event_sender.clone(), + http_tracker_container.http_stats_event_sender.clone(), )), ) // Scrape request @@ -63,7 +63,7 @@ pub fn router(http_tracker_container: Arc, server_socket_a http_tracker_container.core_config.clone(), http_tracker_container.scrape_handler.clone(), http_tracker_container.authentication_service.clone(), - http_tracker_container.stats_event_sender.clone(), + http_tracker_container.http_stats_event_sender.clone(), )), ) .route( @@ -72,7 +72,7 @@ pub fn router(http_tracker_container: Arc, server_socket_a http_tracker_container.core_config.clone(), http_tracker_container.scrape_handler.clone(), http_tracker_container.authentication_service.clone(), - http_tracker_container.stats_event_sender.clone(), + http_tracker_container.http_stats_event_sender.clone(), )), ) // Add extension to get the client IP from the connection info diff --git a/src/servers/http/v1/services/announce.rs b/src/servers/http/v1/services/announce.rs index 9e74ab8a5..bc21657af 100644 --- a/src/servers/http/v1/services/announce.rs +++ b/src/servers/http/v1/services/announce.rs @@ -5,18 +5,18 @@ //! It delegates the `announce` logic to the [`AnnounceHandler`] and it returns //! the [`AnnounceData`]. //! -//! It also sends an [`statistics::event::Event`] +//! It also sends an [`http_tracker_core::statistics::event::Event`] //! because events are specific for the HTTP tracker. use std::net::IpAddr; use std::sync::Arc; use bittorrent_primitives::info_hash::InfoHash; use bittorrent_tracker_core::announce_handler::{AnnounceHandler, PeersWanted}; -use bittorrent_tracker_core::statistics; -use bittorrent_tracker_core::statistics::event::sender::Sender; use torrust_tracker_primitives::core::AnnounceData; use torrust_tracker_primitives::peer; +use crate::packages::http_tracker_core; + /// The HTTP tracker `announce` service. /// /// The service sends an statistics event that increments: @@ -29,7 +29,7 @@ use torrust_tracker_primitives::peer; /// > each `announce` request. pub async fn invoke( announce_handler: Arc, - opt_stats_event_sender: Arc>>, + opt_http_stats_event_sender: Arc>>, info_hash: InfoHash, peer: &mut peer::Peer, peers_wanted: &PeersWanted, @@ -39,13 +39,17 @@ pub async fn invoke( // The tracker could change the original peer ip let announce_data = announce_handler.announce(&info_hash, peer, &original_peer_ip, peers_wanted); - if let Some(stats_event_sender) = opt_stats_event_sender.as_deref() { + if let Some(http_stats_event_sender) = opt_http_stats_event_sender.as_deref() { match original_peer_ip { IpAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Tcp4Announce).await; + http_stats_event_sender + .send_event(http_tracker_core::statistics::event::Event::Tcp4Announce) + .await; } IpAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Tcp6Announce).await; + http_stats_event_sender + .send_event(http_tracker_core::statistics::event::Event::Tcp6Announce) + .await; } } } @@ -61,8 +65,6 @@ mod tests { use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId}; use bittorrent_tracker_core::announce_handler::AnnounceHandler; use bittorrent_tracker_core::databases::setup::initialize_database; - use bittorrent_tracker_core::statistics; - use bittorrent_tracker_core::statistics::event::sender::Sender; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; use torrust_tracker_configuration::Core; @@ -72,29 +74,39 @@ mod tests { struct CoreTrackerServices { pub core_config: Arc, pub announce_handler: Arc, - pub stats_event_sender: Arc>>, } - fn initialize_core_tracker_services() -> CoreTrackerServices { + struct CoreHttpTrackerServices { + pub http_stats_event_sender: Arc>>, + } + + fn initialize_core_tracker_services() -> (CoreTrackerServices, CoreHttpTrackerServices) { let config = configuration::ephemeral_public(); let core_config = Arc::new(config.core.clone()); let database = initialize_database(&config); let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); let db_torrent_repository = Arc::new(DatabasePersistentTorrentRepository::new(&database)); - let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - let stats_event_sender = Arc::new(stats_event_sender); + let announce_handler = Arc::new(AnnounceHandler::new( &config.core, &in_memory_torrent_repository, &db_torrent_repository, )); - CoreTrackerServices { - core_config, - announce_handler, - stats_event_sender, - } + // HTTP stats + let (http_stats_event_sender, http_stats_repository) = + http_tracker_core::statistics::setup::factory(config.core.tracker_usage_statistics); + let http_stats_event_sender = Arc::new(http_stats_event_sender); + let _http_stats_repository = Arc::new(http_stats_repository); + + ( + CoreTrackerServices { + core_config, + announce_handler, + }, + CoreHttpTrackerServices { http_stats_event_sender }, + ) } fn sample_peer_using_ipv4() -> peer::Peer { @@ -122,15 +134,16 @@ mod tests { } } - use bittorrent_tracker_core::statistics::event::Event; use futures::future::BoxFuture; use mockall::mock; use tokio::sync::mpsc::error::SendError; + use crate::packages::http_tracker_core; + mock! { - StatsEventSender {} - impl Sender for StatsEventSender { - fn send_event(&self, event: Event) -> BoxFuture<'static,Option > > > ; + HttpStatsEventSender {} + impl http_tracker_core::statistics::event::sender::Sender for HttpStatsEventSender { + fn send_event(&self, event: http_tracker_core::statistics::event::Event) -> BoxFuture<'static,Option > > > ; } } @@ -142,7 +155,6 @@ mod tests { use bittorrent_tracker_core::announce_handler::{AnnounceHandler, PeersWanted}; use bittorrent_tracker_core::core_tests::sample_info_hash; use bittorrent_tracker_core::databases::setup::initialize_database; - use bittorrent_tracker_core::statistics; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; use mockall::predicate::eq; @@ -152,9 +164,10 @@ mod tests { use torrust_tracker_test_helpers::configuration; use super::{sample_peer_using_ipv4, sample_peer_using_ipv6}; + use crate::packages::http_tracker_core; use crate::servers::http::v1::services::announce::invoke; use crate::servers::http::v1::services::announce::tests::{ - initialize_core_tracker_services, sample_peer, MockStatsEventSender, + initialize_core_tracker_services, sample_peer, MockHttpStatsEventSender, }; fn initialize_announce_handler() -> Arc { @@ -173,13 +186,13 @@ mod tests { #[tokio::test] async fn it_should_return_the_announce_data() { - let core_tracker_services = initialize_core_tracker_services(); + let (core_tracker_services, core_http_tracker_services) = initialize_core_tracker_services(); let mut peer = sample_peer(); let announce_data = invoke( core_tracker_services.announce_handler.clone(), - core_tracker_services.stats_event_sender.clone(), + core_http_tracker_services.http_stats_event_sender.clone(), sample_info_hash(), &mut peer, &PeersWanted::All, @@ -201,14 +214,14 @@ mod tests { #[tokio::test] async fn it_should_send_the_tcp_4_announce_event_when_the_peer_uses_ipv4() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp4Announce)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp4Announce)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let announce_handler = initialize_announce_handler(); @@ -216,7 +229,7 @@ mod tests { let _announce_data = invoke( announce_handler, - stats_event_sender, + http_stats_event_sender, sample_info_hash(), &mut peer, &PeersWanted::All, @@ -246,14 +259,14 @@ mod tests { // Tracker changes the peer IP to the tracker external IP when the peer is using the loopback IP. // Assert that the event sent is a TCP4 event - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp4Announce)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp4Announce)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let mut peer = peer_with_the_ipv4_loopback_ip(); @@ -261,7 +274,7 @@ mod tests { let _announce_data = invoke( announce_handler, - stats_event_sender, + http_stats_event_sender, sample_info_hash(), &mut peer, &PeersWanted::All, @@ -272,14 +285,14 @@ mod tests { #[tokio::test] async fn it_should_send_the_tcp_6_announce_event_when_the_peer_uses_ipv6_even_if_the_tracker_changes_the_peer_ip_to_ipv4() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp6Announce)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp6Announce)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let announce_handler = initialize_announce_handler(); @@ -287,7 +300,7 @@ mod tests { let _announce_data = invoke( announce_handler, - stats_event_sender, + http_stats_event_sender, sample_info_hash(), &mut peer, &PeersWanted::All, diff --git a/src/servers/http/v1/services/scrape.rs b/src/servers/http/v1/services/scrape.rs index 59a7d34c7..5325b188b 100644 --- a/src/servers/http/v1/services/scrape.rs +++ b/src/servers/http/v1/services/scrape.rs @@ -5,17 +5,17 @@ //! It delegates the `scrape` logic to the [`ScrapeHandler`] and it returns the //! [`ScrapeData`]. //! -//! It also sends an [`statistics::event::Event`] +//! It also sends an [`http_tracker_core::statistics::event::Event`] //! because events are specific for the HTTP tracker. use std::net::IpAddr; use std::sync::Arc; use bittorrent_primitives::info_hash::InfoHash; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; -use bittorrent_tracker_core::statistics::event::sender::Sender; -use bittorrent_tracker_core::statistics::{self}; use torrust_tracker_primitives::core::ScrapeData; +use crate::packages::http_tracker_core; + /// The HTTP tracker `scrape` service. /// /// The service sends an statistics event that increments: @@ -28,13 +28,13 @@ use torrust_tracker_primitives::core::ScrapeData; /// > each `scrape` request. pub async fn invoke( scrape_handler: &Arc, - opt_stats_event_sender: &Arc>>, + opt_http_stats_event_sender: &Arc>>, info_hashes: &Vec, original_peer_ip: &IpAddr, ) -> ScrapeData { let scrape_data = scrape_handler.scrape(info_hashes).await; - send_scrape_event(original_peer_ip, opt_stats_event_sender).await; + send_scrape_event(original_peer_ip, opt_http_stats_event_sender).await; scrape_data } @@ -46,23 +46,30 @@ pub async fn invoke( /// /// > **NOTICE**: tracker statistics are not updated in this case. pub async fn fake( - opt_stats_event_sender: &Arc>>, + opt_http_stats_event_sender: &Arc>>, info_hashes: &Vec, original_peer_ip: &IpAddr, ) -> ScrapeData { - send_scrape_event(original_peer_ip, opt_stats_event_sender).await; + send_scrape_event(original_peer_ip, opt_http_stats_event_sender).await; ScrapeData::zeroed(info_hashes) } -async fn send_scrape_event(original_peer_ip: &IpAddr, opt_stats_event_sender: &Arc>>) { - if let Some(stats_event_sender) = opt_stats_event_sender.as_deref() { +async fn send_scrape_event( + original_peer_ip: &IpAddr, + opt_http_stats_event_sender: &Arc>>, +) { + if let Some(http_stats_event_sender) = opt_http_stats_event_sender.as_deref() { match original_peer_ip { IpAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Tcp4Scrape).await; + http_stats_event_sender + .send_event(http_tracker_core::statistics::event::Event::Tcp4Scrape) + .await; } IpAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Tcp6Scrape).await; + http_stats_event_sender + .send_event(http_tracker_core::statistics::event::Event::Tcp6Scrape) + .await; } } } @@ -80,8 +87,6 @@ mod tests { use bittorrent_tracker_core::core_tests::sample_info_hash; use bittorrent_tracker_core::databases::setup::initialize_database; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; - use bittorrent_tracker_core::statistics::event::sender::Sender; - use bittorrent_tracker_core::statistics::event::Event; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; use bittorrent_tracker_core::whitelist::authorization::WhitelistAuthorization; @@ -92,6 +97,8 @@ mod tests { use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch}; use torrust_tracker_test_helpers::configuration; + use crate::packages::http_tracker_core; + fn initialize_announce_and_scrape_handlers_for_public_tracker() -> (Arc, Arc) { let config = configuration::ephemeral_public(); @@ -137,9 +144,9 @@ mod tests { } mock! { - StatsEventSender {} - impl Sender for StatsEventSender { - fn send_event(&self, event: Event) -> BoxFuture<'static,Option > > > ; + HttpStatsEventSender {} + impl http_tracker_core::statistics::event::sender::Sender for HttpStatsEventSender { + fn send_event(&self, event: http_tracker_core::statistics::event::Event) -> BoxFuture<'static,Option > > > ; } } @@ -150,21 +157,22 @@ mod tests { use std::sync::Arc; use bittorrent_tracker_core::announce_handler::PeersWanted; - use bittorrent_tracker_core::statistics; use mockall::predicate::eq; use torrust_tracker_primitives::core::ScrapeData; use torrust_tracker_primitives::swarm_metadata::SwarmMetadata; + use crate::packages::{self, http_tracker_core}; use crate::servers::http::v1::services::scrape::invoke; use crate::servers::http::v1::services::scrape::tests::{ initialize_announce_and_scrape_handlers_for_public_tracker, initialize_scrape_handler, sample_info_hash, - sample_info_hashes, sample_peer, MockStatsEventSender, + sample_info_hashes, sample_peer, MockHttpStatsEventSender, }; #[tokio::test] async fn it_should_return_the_scrape_data_for_a_torrent() { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (http_stats_event_sender, _http_stats_repository) = + packages::http_tracker_core::statistics::setup::factory(false); + let http_stats_event_sender = Arc::new(http_stats_event_sender); let (announce_handler, scrape_handler) = initialize_announce_and_scrape_handlers_for_public_tracker(); @@ -176,7 +184,7 @@ mod tests { let original_peer_ip = peer.ip(); announce_handler.announce(&info_hash, &mut peer, &original_peer_ip, &PeersWanted::All); - let scrape_data = invoke(&scrape_handler, &stats_event_sender, &info_hashes, &original_peer_ip).await; + let scrape_data = invoke(&scrape_handler, &http_stats_event_sender, &info_hashes, &original_peer_ip).await; let mut expected_scrape_data = ScrapeData::empty(); expected_scrape_data.add_file( @@ -193,38 +201,38 @@ mod tests { #[tokio::test] async fn it_should_send_the_tcp_4_scrape_event_when_the_peer_uses_ipv4() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp4Scrape)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp4Scrape)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let scrape_handler = initialize_scrape_handler(); let peer_ip = IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)); - invoke(&scrape_handler, &stats_event_sender, &sample_info_hashes(), &peer_ip).await; + invoke(&scrape_handler, &http_stats_event_sender, &sample_info_hashes(), &peer_ip).await; } #[tokio::test] async fn it_should_send_the_tcp_6_scrape_event_when_the_peer_uses_ipv6() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp6Scrape)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp6Scrape)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let scrape_handler = initialize_scrape_handler(); let peer_ip = IpAddr::V6(Ipv6Addr::new(0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969)); - invoke(&scrape_handler, &stats_event_sender, &sample_info_hashes(), &peer_ip).await; + invoke(&scrape_handler, &http_stats_event_sender, &sample_info_hashes(), &peer_ip).await; } } @@ -235,20 +243,21 @@ mod tests { use std::sync::Arc; use bittorrent_tracker_core::announce_handler::PeersWanted; - use bittorrent_tracker_core::statistics; use mockall::predicate::eq; use torrust_tracker_primitives::core::ScrapeData; + use crate::packages::{self, http_tracker_core}; use crate::servers::http::v1::services::scrape::fake; use crate::servers::http::v1::services::scrape::tests::{ initialize_announce_and_scrape_handlers_for_public_tracker, sample_info_hash, sample_info_hashes, sample_peer, - MockStatsEventSender, + MockHttpStatsEventSender, }; #[tokio::test] async fn it_should_always_return_the_zeroed_scrape_data_for_a_torrent() { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (http_stats_event_sender, _http_stats_repository) = + packages::http_tracker_core::statistics::setup::factory(false); + let http_stats_event_sender = Arc::new(http_stats_event_sender); let (announce_handler, _scrape_handler) = initialize_announce_and_scrape_handlers_for_public_tracker(); @@ -260,7 +269,7 @@ mod tests { let original_peer_ip = peer.ip(); announce_handler.announce(&info_hash, &mut peer, &original_peer_ip, &PeersWanted::All); - let scrape_data = fake(&stats_event_sender, &info_hashes, &original_peer_ip).await; + let scrape_data = fake(&http_stats_event_sender, &info_hashes, &original_peer_ip).await; let expected_scrape_data = ScrapeData::zeroed(&info_hashes); @@ -269,34 +278,34 @@ mod tests { #[tokio::test] async fn it_should_send_the_tcp_4_scrape_event_when_the_peer_uses_ipv4() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp4Scrape)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp4Scrape)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let peer_ip = IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)); - fake(&stats_event_sender, &sample_info_hashes(), &peer_ip).await; + fake(&http_stats_event_sender, &sample_info_hashes(), &peer_ip).await; } #[tokio::test] async fn it_should_send_the_tcp_6_scrape_event_when_the_peer_uses_ipv6() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut http_stats_event_sender_mock = MockHttpStatsEventSender::new(); + http_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Tcp6Scrape)) + .with(eq(http_tracker_core::statistics::event::Event::Tcp6Scrape)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let http_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(http_stats_event_sender_mock))); let peer_ip = IpAddr::V6(Ipv6Addr::new(0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969)); - fake(&stats_event_sender, &sample_info_hashes(), &peer_ip).await; + fake(&http_stats_event_sender, &sample_info_hashes(), &peer_ip).await; } } } diff --git a/src/servers/udp/handlers.rs b/src/servers/udp/handlers.rs index 84b2f1db2..59833b715 100644 --- a/src/servers/udp/handlers.rs +++ b/src/servers/udp/handlers.rs @@ -13,8 +13,7 @@ use aquatic_udp_protocol::{ use bittorrent_primitives::info_hash::InfoHash; use bittorrent_tracker_core::announce_handler::{AnnounceHandler, PeersWanted}; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; -use bittorrent_tracker_core::statistics::event::sender::Sender; -use bittorrent_tracker_core::{statistics, whitelist}; +use bittorrent_tracker_core::whitelist; use torrust_tracker_clock::clock::Time as _; use torrust_tracker_configuration::Core; use tracing::{instrument, Level}; @@ -24,6 +23,7 @@ use zerocopy::network_endian::I32; use super::connection_cookie::{check, make}; use super::RawRequest; use crate::container::UdpTrackerContainer; +use crate::packages::udp_tracker_core; use crate::servers::udp::error::Error; use crate::servers::udp::{peer_builder, UDP_TRACKER_LOG_TARGET}; use crate::shared::bit_torrent::common::MAX_SCRAPE_TORRENTS; @@ -97,7 +97,7 @@ pub(crate) async fn handle_packet( udp_request.from, local_addr, request_id, - &udp_tracker_container.stats_event_sender, + &udp_tracker_container.udp_stats_event_sender, cookie_time_values.valid_range.clone(), &e, Some(transaction_id), @@ -110,7 +110,7 @@ pub(crate) async fn handle_packet( udp_request.from, local_addr, request_id, - &udp_tracker_container.stats_event_sender, + &udp_tracker_container.udp_stats_event_sender, cookie_time_values.valid_range.clone(), &e, None, @@ -143,7 +143,7 @@ pub async fn handle_request( Request::Connect(connect_request) => Ok(handle_connect( remote_addr, &connect_request, - &udp_tracker_container.stats_event_sender, + &udp_tracker_container.udp_stats_event_sender, cookie_time_values.issue_time, ) .await), @@ -154,7 +154,7 @@ pub async fn handle_request( &udp_tracker_container.core_config, &udp_tracker_container.announce_handler, &udp_tracker_container.whitelist_authorization, - &udp_tracker_container.stats_event_sender, + &udp_tracker_container.udp_stats_event_sender, cookie_time_values.valid_range, ) .await @@ -164,7 +164,7 @@ pub async fn handle_request( remote_addr, &scrape_request, &udp_tracker_container.scrape_handler, - &udp_tracker_container.stats_event_sender, + &udp_tracker_container.udp_stats_event_sender, cookie_time_values.valid_range, ) .await @@ -178,11 +178,11 @@ pub async fn handle_request( /// # Errors /// /// This function does not ever return an error. -#[instrument(fields(transaction_id), skip(opt_stats_event_sender), ret(level = Level::TRACE))] +#[instrument(fields(transaction_id), skip(opt_udp_stats_event_sender), ret(level = Level::TRACE))] pub async fn handle_connect( remote_addr: SocketAddr, request: &ConnectRequest, - opt_stats_event_sender: &Arc>>, + opt_udp_stats_event_sender: &Arc>>, cookie_issue_time: f64, ) -> Response { tracing::Span::current().record("transaction_id", request.transaction_id.0.to_string()); @@ -196,13 +196,17 @@ pub async fn handle_connect( connection_id, }; - if let Some(stats_event_sender) = opt_stats_event_sender.as_deref() { + if let Some(udp_stats_event_sender) = opt_udp_stats_event_sender.as_deref() { match remote_addr { SocketAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp4Connect).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp4Connect) + .await; } SocketAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp6Connect).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp6Connect) + .await; } } } @@ -217,14 +221,14 @@ pub async fn handle_connect( /// /// If a error happens in the `handle_announce` function, it will just return the `ServerError`. #[allow(clippy::too_many_arguments)] -#[instrument(fields(transaction_id, connection_id, info_hash), skip(announce_handler, whitelist_authorization, opt_stats_event_sender), ret(level = Level::TRACE))] +#[instrument(fields(transaction_id, connection_id, info_hash), skip(announce_handler, whitelist_authorization, opt_udp_stats_event_sender), ret(level = Level::TRACE))] pub async fn handle_announce( remote_addr: SocketAddr, request: &AnnounceRequest, core_config: &Arc, announce_handler: &Arc, whitelist_authorization: &Arc, - opt_stats_event_sender: &Arc>>, + opt_udp_stats_event_sender: &Arc>>, cookie_valid_range: Range, ) -> Result { tracing::Span::current() @@ -258,13 +262,17 @@ pub async fn handle_announce( let response = announce_handler.announce(&info_hash, &mut peer, &remote_client_ip, &peers_wanted); - if let Some(stats_event_sender) = opt_stats_event_sender.as_deref() { + if let Some(udp_stats_event_sender) = opt_udp_stats_event_sender.as_deref() { match remote_client_ip { IpAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp4Announce).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp4Announce) + .await; } IpAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp6Announce).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp6Announce) + .await; } } } @@ -329,12 +337,12 @@ pub async fn handle_announce( /// # Errors /// /// This function does not ever return an error. -#[instrument(fields(transaction_id, connection_id), skip(scrape_handler, opt_stats_event_sender), ret(level = Level::TRACE))] +#[instrument(fields(transaction_id, connection_id), skip(scrape_handler, opt_udp_stats_event_sender), ret(level = Level::TRACE))] pub async fn handle_scrape( remote_addr: SocketAddr, request: &ScrapeRequest, scrape_handler: &Arc, - opt_stats_event_sender: &Arc>>, + opt_udp_stats_event_sender: &Arc>>, cookie_valid_range: Range, ) -> Result { tracing::Span::current() @@ -375,13 +383,17 @@ pub async fn handle_scrape( torrent_stats.push(scrape_entry); } - if let Some(stats_event_sender) = opt_stats_event_sender.as_deref() { + if let Some(udp_stats_event_sender) = opt_udp_stats_event_sender.as_deref() { match remote_addr { SocketAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp4Scrape).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp4Scrape) + .await; } SocketAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp6Scrape).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp6Scrape) + .await; } } } @@ -394,12 +406,13 @@ pub async fn handle_scrape( Ok(Response::from(response)) } -#[instrument(fields(transaction_id), skip(opt_stats_event_sender), ret(level = Level::TRACE))] +#[allow(clippy::too_many_arguments)] +#[instrument(fields(transaction_id), skip(opt_udp_stats_event_sender), ret(level = Level::TRACE))] async fn handle_error( remote_addr: SocketAddr, local_addr: SocketAddr, request_id: Uuid, - opt_stats_event_sender: &Arc>>, + opt_udp_stats_event_sender: &Arc>>, cookie_valid_range: Range, e: &Error, transaction_id: Option, @@ -436,13 +449,17 @@ async fn handle_error( }; if e.1.is_some() { - if let Some(stats_event_sender) = opt_stats_event_sender.as_deref() { + if let Some(udp_stats_event_sender) = opt_udp_stats_event_sender.as_deref() { match remote_addr { SocketAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp4Error).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp4Error) + .await; } SocketAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp6Error).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp6Error) + .await; } } } @@ -471,13 +488,11 @@ mod tests { use bittorrent_tracker_core::announce_handler::AnnounceHandler; use bittorrent_tracker_core::databases::setup::initialize_database; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; - use bittorrent_tracker_core::statistics::event::sender::Sender; - use bittorrent_tracker_core::statistics::event::Event; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; + use bittorrent_tracker_core::whitelist; use bittorrent_tracker_core::whitelist::authorization::WhitelistAuthorization; use bittorrent_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist; - use bittorrent_tracker_core::{statistics, whitelist}; use futures::future::BoxFuture; use mockall::mock; use tokio::sync::mpsc::error::SendError; @@ -487,43 +502,45 @@ mod tests { use torrust_tracker_test_helpers::configuration; use super::gen_remote_fingerprint; - use crate::CurrentClock; + use crate::packages::udp_tracker_core; + use crate::{packages, CurrentClock}; struct CoreTrackerServices { pub core_config: Arc, pub announce_handler: Arc, pub scrape_handler: Arc, pub in_memory_torrent_repository: Arc, - pub stats_event_sender: Arc>>, pub in_memory_whitelist: Arc, pub whitelist_authorization: Arc, } + struct CoreUdpTrackerServices { + pub udp_stats_event_sender: Arc>>, + } + fn default_testing_tracker_configuration() -> Configuration { configuration::ephemeral() } - fn initialize_core_tracker_services_for_default_tracker_configuration() -> CoreTrackerServices { + fn initialize_core_tracker_services_for_default_tracker_configuration() -> (CoreTrackerServices, CoreUdpTrackerServices) { initialize_core_tracker_services(&default_testing_tracker_configuration()) } - fn initialize_core_tracker_services_for_public_tracker() -> CoreTrackerServices { + fn initialize_core_tracker_services_for_public_tracker() -> (CoreTrackerServices, CoreUdpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_public()) } - fn initialize_core_tracker_services_for_listed_tracker() -> CoreTrackerServices { + fn initialize_core_tracker_services_for_listed_tracker() -> (CoreTrackerServices, CoreUdpTrackerServices) { initialize_core_tracker_services(&configuration::ephemeral_listed()) } - fn initialize_core_tracker_services(config: &Configuration) -> CoreTrackerServices { + fn initialize_core_tracker_services(config: &Configuration) -> (CoreTrackerServices, CoreUdpTrackerServices) { let core_config = Arc::new(config.core.clone()); let database = initialize_database(config); let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); let whitelist_authorization = Arc::new(WhitelistAuthorization::new(&config.core, &in_memory_whitelist.clone())); let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); let db_torrent_repository = Arc::new(DatabasePersistentTorrentRepository::new(&database)); - let (stats_event_sender, _stats_repository) = statistics::setup::factory(config.core.tracker_usage_statistics); - let stats_event_sender = Arc::new(stats_event_sender); let announce_handler = Arc::new(AnnounceHandler::new( &config.core, &in_memory_torrent_repository, @@ -531,15 +548,20 @@ mod tests { )); let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); - CoreTrackerServices { - core_config, - announce_handler, - scrape_handler, - in_memory_torrent_repository, - stats_event_sender, - in_memory_whitelist, - whitelist_authorization, - } + let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); + + ( + CoreTrackerServices { + core_config, + announce_handler, + scrape_handler, + in_memory_torrent_repository, + in_memory_whitelist, + whitelist_authorization, + }, + CoreUdpTrackerServices { udp_stats_event_sender }, + ) } fn sample_ipv4_remote_addr() -> SocketAddr { @@ -637,9 +659,9 @@ mod tests { } mock! { - StatsEventSender {} - impl Sender for StatsEventSender { - fn send_event(&self, event: Event) -> BoxFuture<'static,Option > > > ; + UdpStatsEventSender {} + impl udp_tracker_core::statistics::event::sender::Sender for UdpStatsEventSender { + fn send_event(&self, event: udp_tracker_core::statistics::event::Event) -> BoxFuture<'static,Option > > > ; } } @@ -649,15 +671,15 @@ mod tests { use std::sync::Arc; use aquatic_udp_protocol::{ConnectRequest, ConnectResponse, Response, TransactionId}; - use bittorrent_tracker_core::statistics; use mockall::predicate::eq; use super::{sample_ipv4_socket_address, sample_ipv6_remote_addr}; + use crate::packages::{self, udp_tracker_core}; use crate::servers::udp::connection_cookie::make; use crate::servers::udp::handlers::handle_connect; use crate::servers::udp::handlers::tests::{ sample_ipv4_remote_addr, sample_ipv4_remote_addr_fingerprint, sample_ipv6_remote_addr_fingerprint, sample_issue_time, - MockStatsEventSender, + MockUdpStatsEventSender, }; fn sample_connect_request() -> ConnectRequest { @@ -668,14 +690,20 @@ mod tests { #[tokio::test] async fn a_connect_response_should_contain_the_same_transaction_id_as_the_connect_request() { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); let request = ConnectRequest { transaction_id: TransactionId(0i32.into()), }; - let response = handle_connect(sample_ipv4_remote_addr(), &request, &stats_event_sender, sample_issue_time()).await; + let response = handle_connect( + sample_ipv4_remote_addr(), + &request, + &udp_stats_event_sender, + sample_issue_time(), + ) + .await; assert_eq!( response, @@ -688,14 +716,20 @@ mod tests { #[tokio::test] async fn a_connect_response_should_contain_a_new_connection_id() { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); let request = ConnectRequest { transaction_id: TransactionId(0i32.into()), }; - let response = handle_connect(sample_ipv4_remote_addr(), &request, &stats_event_sender, sample_issue_time()).await; + let response = handle_connect( + sample_ipv4_remote_addr(), + &request, + &udp_stats_event_sender, + sample_issue_time(), + ) + .await; assert_eq!( response, @@ -708,14 +742,20 @@ mod tests { #[tokio::test] async fn a_connect_response_should_contain_a_new_connection_id_ipv6() { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); let request = ConnectRequest { transaction_id: TransactionId(0i32.into()), }; - let response = handle_connect(sample_ipv6_remote_addr(), &request, &stats_event_sender, sample_issue_time()).await; + let response = handle_connect( + sample_ipv6_remote_addr(), + &request, + &udp_stats_event_sender, + sample_issue_time(), + ) + .await; assert_eq!( response, @@ -728,21 +768,21 @@ mod tests { #[tokio::test] async fn it_should_send_the_upd4_connect_event_when_a_client_tries_to_connect_using_a_ip4_socket_address() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp4Connect)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp4Connect)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); let client_socket_address = sample_ipv4_socket_address(); handle_connect( client_socket_address, &sample_connect_request(), - &stats_event_sender, + &udp_stats_event_sender, sample_issue_time(), ) .await; @@ -750,19 +790,19 @@ mod tests { #[tokio::test] async fn it_should_send_the_upd6_connect_event_when_a_client_tries_to_connect_using_a_ip6_socket_address() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp6Connect)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp6Connect)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); handle_connect( sample_ipv6_remote_addr(), &sample_connect_request(), - &stats_event_sender, + &udp_stats_event_sender, sample_issue_time(), ) .await; @@ -854,22 +894,23 @@ mod tests { }; use bittorrent_tracker_core::announce_handler::AnnounceHandler; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; - use bittorrent_tracker_core::{statistics, whitelist}; + use bittorrent_tracker_core::whitelist; use mockall::predicate::eq; use torrust_tracker_configuration::Core; + use crate::packages::{self, udp_tracker_core}; use crate::servers::udp::connection_cookie::make; use crate::servers::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::servers::udp::handlers::tests::{ gen_remote_fingerprint, initialize_core_tracker_services_for_default_tracker_configuration, initialize_core_tracker_services_for_public_tracker, sample_cookie_valid_range, sample_ipv4_socket_address, - sample_issue_time, MockStatsEventSender, TorrentPeerBuilder, + sample_issue_time, MockUdpStatsEventSender, TorrentPeerBuilder, }; use crate::servers::udp::handlers::{handle_announce, AnnounceResponseFixedData}; #[tokio::test] async fn an_announced_peer_should_be_added_to_the_tracker() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let client_ip = Ipv4Addr::new(126, 0, 0, 1); let client_port = 8080; @@ -892,7 +933,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -912,7 +953,7 @@ mod tests { #[tokio::test] async fn the_announced_peer_should_not_be_included_in_the_response() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080); @@ -926,7 +967,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -953,7 +994,7 @@ mod tests { // From the BEP 15 (https://www.bittorrent.org/beps/bep_0015.html): // "Do note that most trackers will only honor the IP address field under limited circumstances." - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let info_hash = AquaticInfoHash([0u8; 20]); let peer_id = AquaticPeerId([255u8; 20]); @@ -979,7 +1020,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1013,8 +1054,9 @@ mod tests { announce_handler: Arc, whitelist_authorization: Arc, ) -> Response { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (udp_stats_event_sender, _udp_stats_repository) = + packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080); let request = AnnounceRequestBuilder::default() @@ -1027,7 +1069,7 @@ mod tests { &core_config, &announce_handler, &whitelist_authorization, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1036,7 +1078,7 @@ mod tests { #[tokio::test] async fn when_the_announce_request_comes_from_a_client_using_ipv4_the_response_should_not_include_peers_using_ipv6() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, _core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); add_a_torrent_peer_using_ipv6(&core_tracker_services.in_memory_torrent_repository); @@ -1058,16 +1100,17 @@ mod tests { #[tokio::test] async fn should_send_the_upd4_announce_event() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp4Announce)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp4Announce)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); - let core_tracker_services = initialize_core_tracker_services_for_default_tracker_configuration(); + let (core_tracker_services, _core_udp_tracker_services) = + initialize_core_tracker_services_for_default_tracker_configuration(); handle_announce( sample_ipv4_socket_address(), @@ -1075,7 +1118,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1098,7 +1141,8 @@ mod tests { #[tokio::test] async fn the_peer_ip_should_be_changed_to_the_external_ip_in_the_tracker_configuration_if_defined() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = + initialize_core_tracker_services_for_public_tracker(); let client_ip = Ipv4Addr::new(127, 0, 0, 1); let client_port = 8080; @@ -1121,7 +1165,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1155,22 +1199,23 @@ mod tests { }; use bittorrent_tracker_core::announce_handler::AnnounceHandler; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; - use bittorrent_tracker_core::{statistics, whitelist}; + use bittorrent_tracker_core::whitelist; use mockall::predicate::eq; use torrust_tracker_configuration::Core; + use crate::packages::{self, udp_tracker_core}; use crate::servers::udp::connection_cookie::make; use crate::servers::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::servers::udp::handlers::tests::{ gen_remote_fingerprint, initialize_core_tracker_services_for_default_tracker_configuration, initialize_core_tracker_services_for_public_tracker, sample_cookie_valid_range, sample_ipv6_remote_addr, - sample_issue_time, MockStatsEventSender, TorrentPeerBuilder, + sample_issue_time, MockUdpStatsEventSender, TorrentPeerBuilder, }; use crate::servers::udp::handlers::{handle_announce, AnnounceResponseFixedData}; #[tokio::test] async fn an_announced_peer_should_be_added_to_the_tracker() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let client_ip_v4 = Ipv4Addr::new(126, 0, 0, 1); let client_ip_v6 = client_ip_v4.to_ipv6_compatible(); @@ -1194,7 +1239,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1214,7 +1259,7 @@ mod tests { #[tokio::test] async fn the_announced_peer_should_not_be_included_in_the_response() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let client_ip_v4 = Ipv4Addr::new(126, 0, 0, 1); let client_ip_v6 = client_ip_v4.to_ipv6_compatible(); @@ -1231,7 +1276,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1258,7 +1303,7 @@ mod tests { // From the BEP 15 (https://www.bittorrent.org/beps/bep_0015.html): // "Do note that most trackers will only honor the IP address field under limited circumstances." - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let info_hash = AquaticInfoHash([0u8; 20]); let peer_id = AquaticPeerId([255u8; 20]); @@ -1284,7 +1329,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1318,8 +1363,9 @@ mod tests { announce_handler: Arc, whitelist_authorization: Arc, ) -> Response { - let (stats_event_sender, _stats_repository) = bittorrent_tracker_core::statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (udp_stats_event_sender, _udp_stats_repository) = + packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); let client_ip_v4 = Ipv4Addr::new(126, 0, 0, 1); let client_ip_v6 = client_ip_v4.to_ipv6_compatible(); @@ -1335,7 +1381,7 @@ mod tests { &core_config, &announce_handler, &whitelist_authorization, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1344,7 +1390,7 @@ mod tests { #[tokio::test] async fn when_the_announce_request_comes_from_a_client_using_ipv6_the_response_should_not_include_peers_using_ipv4() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, _core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); add_a_torrent_peer_using_ipv4(&core_tracker_services.in_memory_torrent_repository); @@ -1366,16 +1412,17 @@ mod tests { #[tokio::test] async fn should_send_the_upd6_announce_event() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp6Announce)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp6Announce)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); - let core_tracker_services = initialize_core_tracker_services_for_default_tracker_configuration(); + let (core_tracker_services, _core_udp_tracker_services) = + initialize_core_tracker_services_for_default_tracker_configuration(); let remote_addr = sample_ipv6_remote_addr(); @@ -1389,7 +1436,7 @@ mod tests { &core_tracker_services.core_config, &core_tracker_services.announce_handler, &core_tracker_services.whitelist_authorization, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1404,18 +1451,18 @@ mod tests { use aquatic_udp_protocol::{InfoHash as AquaticInfoHash, PeerId as AquaticPeerId}; use bittorrent_tracker_core::announce_handler::AnnounceHandler; use bittorrent_tracker_core::databases::setup::initialize_database; - use bittorrent_tracker_core::statistics; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; use bittorrent_tracker_core::whitelist::authorization::WhitelistAuthorization; use bittorrent_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist; use mockall::predicate::eq; + use crate::packages::udp_tracker_core; use crate::servers::udp::connection_cookie::make; use crate::servers::udp::handlers::handle_announce; use crate::servers::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::servers::udp::handlers::tests::{ - gen_remote_fingerprint, sample_cookie_valid_range, sample_issue_time, MockStatsEventSender, + gen_remote_fingerprint, sample_cookie_valid_range, sample_issue_time, MockUdpStatsEventSender, TrackerConfigurationBuilder, }; @@ -1430,14 +1477,14 @@ mod tests { let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); let db_torrent_repository = Arc::new(DatabasePersistentTorrentRepository::new(&database)); - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp6Announce)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp6Announce)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); let announce_handler = Arc::new(AnnounceHandler::new( &config.core, @@ -1473,7 +1520,7 @@ mod tests { &core_config, &announce_handler, &whitelist_authorization, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1505,10 +1552,10 @@ mod tests { TransactionId, }; use bittorrent_tracker_core::scrape_handler::ScrapeHandler; - use bittorrent_tracker_core::statistics; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use super::{gen_remote_fingerprint, TorrentPeerBuilder}; + use crate::packages; use crate::servers::udp::connection_cookie::make; use crate::servers::udp::handlers::handle_scrape; use crate::servers::udp::handlers::tests::{ @@ -1526,7 +1573,7 @@ mod tests { #[tokio::test] async fn should_return_no_stats_when_the_tracker_does_not_have_any_torrent() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let remote_addr = sample_ipv4_remote_addr(); @@ -1543,7 +1590,7 @@ mod tests { remote_addr, &request, &core_tracker_services.scrape_handler, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1590,8 +1637,8 @@ mod tests { in_memory_torrent_repository: Arc, scrape_handler: Arc, ) -> Response { - let (stats_event_sender, _stats_repository) = statistics::setup::factory(false); - let stats_event_sender = Arc::new(stats_event_sender); + let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false); + let udp_stats_event_sender = Arc::new(udp_stats_event_sender); let remote_addr = sample_ipv4_remote_addr(); let info_hash = InfoHash([0u8; 20]); @@ -1604,7 +1651,7 @@ mod tests { remote_addr, &request, &scrape_handler, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1626,7 +1673,7 @@ mod tests { #[tokio::test] async fn should_return_torrent_statistics_when_the_tracker_has_the_requested_torrent() { - let core_tracker_services = initialize_core_tracker_services_for_public_tracker(); + let (core_tracker_services, _core_udp_tracker_services) = initialize_core_tracker_services_for_public_tracker(); let torrent_stats = match_scrape_response( add_a_sample_seeder_and_scrape( @@ -1659,7 +1706,7 @@ mod tests { #[tokio::test] async fn should_return_the_torrent_statistics_when_the_requested_torrent_is_whitelisted() { - let core_tracker_services = initialize_core_tracker_services_for_listed_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_listed_tracker(); let remote_addr = sample_ipv4_remote_addr(); let info_hash = InfoHash([0u8; 20]); @@ -1680,7 +1727,7 @@ mod tests { remote_addr, &request, &core_tracker_services.scrape_handler, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1699,7 +1746,7 @@ mod tests { #[tokio::test] async fn should_return_zeroed_statistics_when_the_requested_torrent_is_not_whitelisted() { - let core_tracker_services = initialize_core_tracker_services_for_listed_tracker(); + let (core_tracker_services, core_udp_tracker_services) = initialize_core_tracker_services_for_listed_tracker(); let remote_addr = sample_ipv4_remote_addr(); let info_hash = InfoHash([0u8; 20]); @@ -1718,7 +1765,7 @@ mod tests { remote_addr, &request, &core_tracker_services.scrape_handler, - &core_tracker_services.stats_event_sender, + &core_udp_tracker_services.udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1747,36 +1794,37 @@ mod tests { use std::future; use std::sync::Arc; - use bittorrent_tracker_core::statistics; use mockall::predicate::eq; use super::sample_scrape_request; + use crate::packages::udp_tracker_core; use crate::servers::udp::handlers::handle_scrape; use crate::servers::udp::handlers::tests::{ initialize_core_tracker_services_for_default_tracker_configuration, sample_cookie_valid_range, - sample_ipv4_remote_addr, MockStatsEventSender, + sample_ipv4_remote_addr, MockUdpStatsEventSender, }; #[tokio::test] async fn should_send_the_upd4_scrape_event() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp4Scrape)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp4Scrape)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); let remote_addr = sample_ipv4_remote_addr(); - let core_tracker_services = initialize_core_tracker_services_for_default_tracker_configuration(); + let (core_tracker_services, _core_udp_tracker_services) = + initialize_core_tracker_services_for_default_tracker_configuration(); handle_scrape( remote_addr, &sample_scrape_request(&remote_addr), &core_tracker_services.scrape_handler, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await @@ -1788,36 +1836,37 @@ mod tests { use std::future; use std::sync::Arc; - use bittorrent_tracker_core::statistics; use mockall::predicate::eq; use super::sample_scrape_request; + use crate::packages::udp_tracker_core; use crate::servers::udp::handlers::handle_scrape; use crate::servers::udp::handlers::tests::{ initialize_core_tracker_services_for_default_tracker_configuration, sample_cookie_valid_range, - sample_ipv6_remote_addr, MockStatsEventSender, + sample_ipv6_remote_addr, MockUdpStatsEventSender, }; #[tokio::test] async fn should_send_the_upd6_scrape_event() { - let mut stats_event_sender_mock = MockStatsEventSender::new(); - stats_event_sender_mock + let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new(); + udp_stats_event_sender_mock .expect_send_event() - .with(eq(statistics::event::Event::Udp6Scrape)) + .with(eq(udp_tracker_core::statistics::event::Event::Udp6Scrape)) .times(1) .returning(|_| Box::pin(future::ready(Some(Ok(()))))); - let stats_event_sender: Arc>> = - Arc::new(Some(Box::new(stats_event_sender_mock))); + let udp_stats_event_sender: Arc>> = + Arc::new(Some(Box::new(udp_stats_event_sender_mock))); let remote_addr = sample_ipv6_remote_addr(); - let core_tracker_services = initialize_core_tracker_services_for_default_tracker_configuration(); + let (core_tracker_services, _core_udp_tracker_services) = + initialize_core_tracker_services_for_default_tracker_configuration(); handle_scrape( remote_addr, &sample_scrape_request(&remote_addr), &core_tracker_services.scrape_handler, - &stats_event_sender, + &udp_stats_event_sender, sample_cookie_valid_range(), ) .await diff --git a/src/servers/udp/server/launcher.rs b/src/servers/udp/server/launcher.rs index bbf2718ff..e640749c6 100644 --- a/src/servers/udp/server/launcher.rs +++ b/src/servers/udp/server/launcher.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use std::time::Duration; use bittorrent_tracker_client::udp::client::check; -use bittorrent_tracker_core::statistics; use derive_more::Constructor; use futures_util::StreamExt; use tokio::select; @@ -14,6 +13,7 @@ use tracing::instrument; use super::request_buffer::ActiveRequests; use crate::bootstrap::jobs::Started; use crate::container::UdpTrackerContainer; +use crate::packages::udp_tracker_core; use crate::servers::logging::STARTED_ON; use crate::servers::registar::ServiceHealthCheckJob; use crate::servers::signals::{shutdown_signal_with_message, Halted}; @@ -162,13 +162,17 @@ impl Launcher { } }; - if let Some(stats_event_sender) = udp_tracker_container.stats_event_sender.as_deref() { + if let Some(udp_stats_event_sender) = udp_tracker_container.udp_stats_event_sender.as_deref() { match req.from.ip() { IpAddr::V4(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp4Request).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp4Request) + .await; } IpAddr::V6(_) => { - stats_event_sender.send_event(statistics::event::Event::Udp6Request).await; + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp6Request) + .await; } } } @@ -176,9 +180,9 @@ impl Launcher { if udp_tracker_container.ban_service.read().await.is_banned(&req.from.ip()) { tracing::debug!(target: UDP_TRACKER_LOG_TARGET, local_addr, "Udp::run_udp_server::loop continue: (banned ip)"); - if let Some(stats_event_sender) = udp_tracker_container.stats_event_sender.as_deref() { - stats_event_sender - .send_event(statistics::event::Event::UdpRequestBanned) + if let Some(udp_stats_event_sender) = udp_tracker_container.udp_stats_event_sender.as_deref() { + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::UdpRequestBanned) .await; } @@ -209,9 +213,9 @@ impl Launcher { if old_request_aborted { // Evicted task from active requests buffer was aborted. - if let Some(stats_event_sender) = udp_tracker_container.stats_event_sender.as_deref() { - stats_event_sender - .send_event(statistics::event::Event::UdpRequestAborted) + if let Some(udp_stats_event_sender) = udp_tracker_container.udp_stats_event_sender.as_deref() { + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::UdpRequestAborted) .await; } } diff --git a/src/servers/udp/server/processor.rs b/src/servers/udp/server/processor.rs index db444a04c..dc55833c2 100644 --- a/src/servers/udp/server/processor.rs +++ b/src/servers/udp/server/processor.rs @@ -4,13 +4,12 @@ use std::sync::Arc; use std::time::Duration; use aquatic_udp_protocol::Response; -use bittorrent_tracker_core::statistics; -use bittorrent_tracker_core::statistics::event::UdpResponseKind; use tokio::time::Instant; use tracing::{instrument, Level}; use super::bound_socket::BoundSocket; use crate::container::UdpTrackerContainer; +use crate::packages::udp_tracker_core; use crate::servers::udp::handlers::CookieTimeValues; use crate::servers::udp::{handlers, RawRequest}; @@ -60,11 +59,13 @@ impl Processor { Response::Error(e) => format!("Error: {e:?}"), }; - let response_kind = match &response { - Response::Connect(_) => UdpResponseKind::Connect, - Response::AnnounceIpv4(_) | Response::AnnounceIpv6(_) => UdpResponseKind::Announce, - Response::Scrape(_) => UdpResponseKind::Scrape, - Response::Error(_e) => UdpResponseKind::Error, + let udp_response_kind = match &response { + Response::Connect(_) => udp_tracker_core::statistics::event::UdpResponseKind::Connect, + Response::AnnounceIpv4(_) | Response::AnnounceIpv6(_) => { + udp_tracker_core::statistics::event::UdpResponseKind::Announce + } + Response::Scrape(_) => udp_tracker_core::statistics::event::UdpResponseKind::Scrape, + Response::Error(_e) => udp_tracker_core::statistics::event::UdpResponseKind::Error, }; let mut writer = Cursor::new(Vec::with_capacity(200)); @@ -82,20 +83,20 @@ impl Processor { tracing::debug!(%bytes_count, %sent_bytes, "sent {response_type}"); } - if let Some(stats_event_sender) = self.udp_tracker_container.stats_event_sender.as_deref() { + if let Some(udp_stats_event_sender) = self.udp_tracker_container.udp_stats_event_sender.as_deref() { match target.ip() { IpAddr::V4(_) => { - stats_event_sender - .send_event(statistics::event::Event::Udp4Response { - kind: response_kind, + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp4Response { + kind: udp_response_kind, req_processing_time, }) .await; } IpAddr::V6(_) => { - stats_event_sender - .send_event(statistics::event::Event::Udp6Response { - kind: response_kind, + udp_stats_event_sender + .send_event(udp_tracker_core::statistics::event::Event::Udp6Response { + kind: udp_response_kind, req_processing_time, }) .await; diff --git a/tests/servers/api/environment.rs b/tests/servers/api/environment.rs index 219c28b6e..61351024d 100644 --- a/tests/servers/api/environment.rs +++ b/tests/servers/api/environment.rs @@ -61,8 +61,8 @@ impl Environment { keys_handler: app_container.keys_handler.clone(), whitelist_manager: app_container.whitelist_manager.clone(), ban_service: app_container.ban_service.clone(), - stats_event_sender: app_container.stats_event_sender.clone(), - stats_repository: app_container.stats_repository.clone(), + http_stats_repository: app_container.http_stats_repository.clone(), + udp_stats_repository: app_container.udp_stats_repository.clone(), }); Self { diff --git a/tests/servers/http/environment.rs b/tests/servers/http/environment.rs index c91be1544..97ca13e95 100644 --- a/tests/servers/http/environment.rs +++ b/tests/servers/http/environment.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use bittorrent_primitives::info_hash::InfoHash; use bittorrent_tracker_core::authentication::handler::KeysHandler; use bittorrent_tracker_core::databases::Database; -use bittorrent_tracker_core::statistics::repository::Repository; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use bittorrent_tracker_core::whitelist::manager::WhitelistManager; use futures::executor::block_on; @@ -11,6 +10,7 @@ use torrust_tracker_configuration::Configuration; use torrust_tracker_lib::bootstrap::app::{initialize_app_container, initialize_global_services}; use torrust_tracker_lib::bootstrap::jobs::make_rust_tls; use torrust_tracker_lib::container::HttpTrackerContainer; +use torrust_tracker_lib::packages::http_tracker_core; use torrust_tracker_lib::servers::http::server::{HttpServer, Launcher, Running, Stopped}; use torrust_tracker_lib::servers::registar::Registar; use torrust_tracker_primitives::peer; @@ -21,7 +21,7 @@ pub struct Environment { pub database: Arc>, pub in_memory_torrent_repository: Arc, pub keys_handler: Arc, - pub stats_repository: Arc, + pub http_stats_repository: Arc, pub whitelist_manager: Arc, pub registar: Registar, @@ -60,7 +60,7 @@ impl Environment { announce_handler: app_container.announce_handler.clone(), scrape_handler: app_container.scrape_handler.clone(), whitelist_authorization: app_container.whitelist_authorization.clone(), - stats_event_sender: app_container.stats_event_sender.clone(), + http_stats_event_sender: app_container.http_stats_event_sender.clone(), authentication_service: app_container.authentication_service.clone(), }); @@ -70,7 +70,7 @@ impl Environment { database: app_container.database.clone(), in_memory_torrent_repository: app_container.in_memory_torrent_repository.clone(), keys_handler: app_container.keys_handler.clone(), - stats_repository: app_container.stats_repository.clone(), + http_stats_repository: app_container.http_stats_repository.clone(), whitelist_manager: app_container.whitelist_manager.clone(), registar: Registar::default(), @@ -86,7 +86,7 @@ impl Environment { database: self.database.clone(), in_memory_torrent_repository: self.in_memory_torrent_repository.clone(), keys_handler: self.keys_handler.clone(), - stats_repository: self.stats_repository.clone(), + http_stats_repository: self.http_stats_repository.clone(), whitelist_manager: self.whitelist_manager.clone(), registar: self.registar.clone(), @@ -111,7 +111,7 @@ impl Environment { database: self.database, in_memory_torrent_repository: self.in_memory_torrent_repository, keys_handler: self.keys_handler, - stats_repository: self.stats_repository, + http_stats_repository: self.http_stats_repository, whitelist_manager: self.whitelist_manager, registar: Registar::default(), diff --git a/tests/servers/http/v1/contract.rs b/tests/servers/http/v1/contract.rs index be603161a..48c98fa02 100644 --- a/tests/servers/http/v1/contract.rs +++ b/tests/servers/http/v1/contract.rs @@ -680,7 +680,7 @@ mod for_all_config_modes { .announce(&QueryBuilder::default().query()) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp4_connections_handled, 1); @@ -706,7 +706,7 @@ mod for_all_config_modes { .announce(&QueryBuilder::default().query()) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp6_connections_handled, 1); @@ -731,7 +731,7 @@ mod for_all_config_modes { ) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp6_connections_handled, 0); @@ -750,7 +750,7 @@ mod for_all_config_modes { .announce(&QueryBuilder::default().query()) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp4_announces_handled, 1); @@ -776,7 +776,7 @@ mod for_all_config_modes { .announce(&QueryBuilder::default().query()) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp6_announces_handled, 1); @@ -801,7 +801,7 @@ mod for_all_config_modes { ) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp6_announces_handled, 0); @@ -1173,7 +1173,7 @@ mod for_all_config_modes { ) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp4_scrapes_handled, 1); @@ -1205,7 +1205,7 @@ mod for_all_config_modes { ) .await; - let stats = env.stats_repository.get_stats().await; + let stats = env.http_stats_repository.get_stats().await; assert_eq!(stats.tcp6_scrapes_handled, 1); diff --git a/tests/servers/udp/contract.rs b/tests/servers/udp/contract.rs index d38356ef4..f6e0589f8 100644 --- a/tests/servers/udp/contract.rs +++ b/tests/servers/udp/contract.rs @@ -270,7 +270,7 @@ mod receiving_an_announce_request { info_hash, ); - let udp_requests_banned_before = env.stats_repository.get_stats().await.udp_requests_banned; + let udp_requests_banned_before = env.udp_stats_repository.get_stats().await.udp_requests_banned; // This should return a timeout error match client.send(announce_request.into()).await { @@ -280,7 +280,7 @@ mod receiving_an_announce_request { assert!(client.receive().await.is_err()); - let udp_requests_banned_after = env.stats_repository.get_stats().await.udp_requests_banned; + let udp_requests_banned_after = env.udp_stats_repository.get_stats().await.udp_requests_banned; let udp_banned_ips_total_after = ban_service.read().await.get_banned_ips_total(); // UDP counter for banned requests should be increased by 1 diff --git a/tests/servers/udp/environment.rs b/tests/servers/udp/environment.rs index 1483e1e5f..24ce7bab2 100644 --- a/tests/servers/udp/environment.rs +++ b/tests/servers/udp/environment.rs @@ -3,11 +3,11 @@ use std::sync::Arc; use bittorrent_primitives::info_hash::InfoHash; use bittorrent_tracker_core::databases::Database; -use bittorrent_tracker_core::statistics::repository::Repository; use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; use torrust_tracker_configuration::{Configuration, DEFAULT_TIMEOUT}; use torrust_tracker_lib::bootstrap::app::{initialize_app_container, initialize_global_services}; use torrust_tracker_lib::container::UdpTrackerContainer; +use torrust_tracker_lib::packages::udp_tracker_core; use torrust_tracker_lib::servers::registar::Registar; use torrust_tracker_lib::servers::udp::server::spawner::Spawner; use torrust_tracker_lib::servers::udp::server::states::{Running, Stopped}; @@ -22,7 +22,7 @@ where pub database: Arc>, pub in_memory_torrent_repository: Arc, - pub stats_repository: Arc, + pub udp_stats_repository: Arc, pub registar: Registar, pub server: Server, @@ -60,7 +60,7 @@ impl Environment { announce_handler: app_container.announce_handler.clone(), scrape_handler: app_container.scrape_handler.clone(), whitelist_authorization: app_container.whitelist_authorization.clone(), - stats_event_sender: app_container.stats_event_sender.clone(), + udp_stats_event_sender: app_container.udp_stats_event_sender.clone(), ban_service: app_container.ban_service.clone(), }); @@ -69,7 +69,7 @@ impl Environment { database: app_container.database.clone(), in_memory_torrent_repository: app_container.in_memory_torrent_repository.clone(), - stats_repository: app_container.stats_repository.clone(), + udp_stats_repository: app_container.udp_stats_repository.clone(), registar: Registar::default(), server, @@ -85,7 +85,7 @@ impl Environment { database: self.database.clone(), in_memory_torrent_repository: self.in_memory_torrent_repository.clone(), - stats_repository: self.stats_repository.clone(), + udp_stats_repository: self.udp_stats_repository.clone(), registar: self.registar.clone(), server: self @@ -115,7 +115,7 @@ impl Environment { database: self.database, in_memory_torrent_repository: self.in_memory_torrent_repository, - stats_repository: self.stats_repository, + udp_stats_repository: self.udp_stats_repository, registar: Registar::default(), server: stopped.expect("it stop the udp tracker service"),