Skip to content

Commit 765bd6f

Browse files
committed
Merge #1188: Overhaul core Tracker: extract IoC Container
20018ab fix: [#1187] doc link error (Jose Celano) 3d0f4f8 refactor: [#1187] use AppContainer in test environments (Jose Celano) c45a12b refactor: [#1187] rename fn tracker_factory to initialize_tracker (Jose Celano) aa9f1c3 refactor: [#1187] move fn initialize_tracker_dependencies (Jose Celano) a4d8da0 refactor: [#1187] inline fn initialize_tracker (Jose Celano) 36db088 refactor: [#1187] inline fn initialize_globals_and_tracker (Jose Celano) 4aea9db refactor: [#1187] extract fn initialize_app_container (Jose Celano) 747b58d refactor: [#1187] extract one function and rename another one (Jose Celano) 8bea521 refactor: [#1187] extract IoC Container (Jose Celano) Pull request description: Overhaul core Tracker: extract IoC Container ACKs for top commit: josecelano: ACK 20018ab Tree-SHA512: 5bb7d6fc2f3e577547b1532b3267f3f1d7eddd938b883a6a3fb31a3a3bd0e3b8001325e3c6d45261da46c34fd2c4312b627abc0054efd7097e1721375b325b5f
2 parents 5b46cea + 20018ab commit 765bd6f

24 files changed

+205
-187
lines changed

src/app.rs

+21-30
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,23 @@
2121
//! - UDP trackers: the user can enable multiple UDP tracker on several ports.
2222
//! - HTTP trackers: the user can enable multiple HTTP tracker on several ports.
2323
//! - Tracker REST API: the tracker API can be enabled/disabled.
24-
use std::sync::Arc;
25-
26-
use tokio::sync::RwLock;
2724
use tokio::task::JoinHandle;
2825
use torrust_tracker_configuration::Configuration;
2926
use tracing::instrument;
3027

3128
use crate::bootstrap::jobs::{health_check_api, http_tracker, torrent_cleanup, tracker_apis, udp_tracker};
32-
use crate::core::statistics::event::sender::Sender;
33-
use crate::core::statistics::repository::Repository;
29+
use crate::container::AppContainer;
30+
use crate::servers;
3431
use crate::servers::registar::Registar;
35-
use crate::servers::udp::server::banning::BanService;
36-
use crate::{core, servers};
3732

3833
/// # Panics
3934
///
4035
/// Will panic if:
4136
///
4237
/// - Can't retrieve tracker keys from database.
4338
/// - Can't load whitelist from database.
44-
#[instrument(skip(config, tracker, ban_service, stats_event_sender, stats_repository))]
45-
pub async fn start(
46-
config: &Configuration,
47-
tracker: Arc<core::Tracker>,
48-
ban_service: Arc<RwLock<BanService>>,
49-
stats_event_sender: Arc<Option<Box<dyn Sender>>>,
50-
stats_repository: Arc<Repository>,
51-
) -> Vec<JoinHandle<()>> {
39+
#[instrument(skip(config, app_container))]
40+
pub async fn start(config: &Configuration, app_container: &AppContainer) -> Vec<JoinHandle<()>> {
5241
if config.http_api.is_none()
5342
&& (config.udp_trackers.is_none() || config.udp_trackers.as_ref().map_or(true, std::vec::Vec::is_empty))
5443
&& (config.http_trackers.is_none() || config.http_trackers.as_ref().map_or(true, std::vec::Vec::is_empty))
@@ -61,16 +50,18 @@ pub async fn start(
6150
let registar = Registar::default();
6251

6352
// Load peer keys
64-
if tracker.is_private() {
65-
tracker
53+
if app_container.tracker.is_private() {
54+
app_container
55+
.tracker
6656
.load_keys_from_database()
6757
.await
6858
.expect("Could not retrieve keys from database.");
6959
}
7060

7161
// Load whitelisted torrents
72-
if tracker.is_listed() {
73-
tracker
62+
if app_container.tracker.is_listed() {
63+
app_container
64+
.tracker
7465
.whitelist_manager
7566
.load_whitelist_from_database()
7667
.await
@@ -80,7 +71,7 @@ pub async fn start(
8071
// Start the UDP blocks
8172
if let Some(udp_trackers) = &config.udp_trackers {
8273
for udp_tracker_config in udp_trackers {
83-
if tracker.is_private() {
74+
if app_container.tracker.is_private() {
8475
tracing::warn!(
8576
"Could not start UDP tracker on: {} while in private mode. UDP is not safe for private trackers!",
8677
udp_tracker_config.bind_address
@@ -89,9 +80,9 @@ pub async fn start(
8980
jobs.push(
9081
udp_tracker::start_job(
9182
udp_tracker_config,
92-
tracker.clone(),
93-
stats_event_sender.clone(),
94-
ban_service.clone(),
83+
app_container.tracker.clone(),
84+
app_container.stats_event_sender.clone(),
85+
app_container.ban_service.clone(),
9586
registar.give_form(),
9687
)
9788
.await,
@@ -107,8 +98,8 @@ pub async fn start(
10798
for http_tracker_config in http_trackers {
10899
if let Some(job) = http_tracker::start_job(
109100
http_tracker_config,
110-
tracker.clone(),
111-
stats_event_sender.clone(),
101+
app_container.tracker.clone(),
102+
app_container.stats_event_sender.clone(),
112103
registar.give_form(),
113104
servers::http::Version::V1,
114105
)
@@ -125,10 +116,10 @@ pub async fn start(
125116
if let Some(http_api_config) = &config.http_api {
126117
if let Some(job) = tracker_apis::start_job(
127118
http_api_config,
128-
tracker.clone(),
129-
ban_service.clone(),
130-
stats_event_sender.clone(),
131-
stats_repository.clone(),
119+
app_container.tracker.clone(),
120+
app_container.ban_service.clone(),
121+
app_container.stats_event_sender.clone(),
122+
app_container.stats_repository.clone(),
132123
registar.give_form(),
133124
servers::apis::Version::V1,
134125
)
@@ -142,7 +133,7 @@ pub async fn start(
142133

143134
// Start runners to remove torrents without peers, every interval
144135
if config.core.inactive_peer_cleanup_interval > 0 {
145-
jobs.push(torrent_cleanup::start_job(&config.core, &tracker));
136+
jobs.push(torrent_cleanup::start_job(&config.core, &app_container.tracker));
146137
}
147138

148139
// Start Health Check API

src/app_test.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! This file contains only functions used for testing.
2+
use std::sync::Arc;
3+
4+
use torrust_tracker_configuration::Configuration;
5+
6+
use crate::core::databases::Database;
7+
use crate::core::services::{initialize_database, initialize_whitelist};
8+
use crate::core::whitelist::WhiteListManager;
9+
10+
/// Initialize the tracker dependencies.
11+
#[allow(clippy::type_complexity)]
12+
#[must_use]
13+
pub fn initialize_tracker_dependencies(config: &Configuration) -> (Arc<Box<dyn Database>>, Arc<WhiteListManager>) {
14+
let database = initialize_database(config);
15+
let whitelist_manager = initialize_whitelist(database.clone());
16+
17+
(database, whitelist_manager)
18+
}

src/bootstrap/app.rs

+30-52
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,21 @@ use tracing::instrument;
2121

2222
use super::config::initialize_configuration;
2323
use crate::bootstrap;
24-
use crate::core::databases::Database;
25-
use crate::core::services::{initialize_database, initialize_whitelist, statistics, tracker_factory};
26-
use crate::core::statistics::event::sender::Sender;
27-
use crate::core::statistics::repository::Repository;
28-
use crate::core::whitelist::WhiteListManager;
29-
use crate::core::Tracker;
24+
use crate::container::AppContainer;
25+
use crate::core::services::{initialize_database, initialize_tracker, initialize_whitelist, statistics};
3026
use crate::servers::udp::server::banning::BanService;
3127
use crate::servers::udp::server::launcher::MAX_CONNECTION_ID_ERRORS_PER_IP;
3228
use crate::shared::crypto::ephemeral_instance_keys;
3329
use crate::shared::crypto::keys::{self, Keeper as _};
3430

35-
/// It loads the configuration from the environment and builds the main domain [`Tracker`] struct.
31+
/// It loads the configuration from the environment and builds app container.
3632
///
3733
/// # Panics
3834
///
3935
/// Setup can file if the configuration is invalid.
4036
#[must_use]
41-
#[allow(clippy::type_complexity)]
4237
#[instrument(skip())]
43-
pub fn setup() -> (
44-
Configuration,
45-
Arc<Tracker>,
46-
Arc<RwLock<BanService>>,
47-
Arc<Option<Box<dyn Sender>>>,
48-
Arc<Repository>,
49-
) {
38+
pub fn setup() -> (Configuration, AppContainer) {
5039
#[cfg(not(test))]
5140
check_seed();
5241

@@ -56,19 +45,13 @@ pub fn setup() -> (
5645
panic!("Configuration error: {e}");
5746
}
5847

59-
// Initialize services
60-
61-
let (stats_event_sender, stats_repository) = statistics::setup::factory(configuration.core.tracker_usage_statistics);
62-
let stats_event_sender = Arc::new(stats_event_sender);
63-
let stats_repository = Arc::new(stats_repository);
64-
65-
let udp_ban_service = Arc::new(RwLock::new(BanService::new(MAX_CONNECTION_ID_ERRORS_PER_IP)));
66-
67-
let tracker = initialize_with_configuration(&configuration);
48+
initialize_global_services(&configuration);
6849

6950
tracing::info!("Configuration:\n{}", configuration.clone().mask_secrets().to_json());
7051

71-
(configuration, tracker, udp_ban_service, stats_event_sender, stats_repository)
52+
let app_container = initialize_app_container(&configuration);
53+
54+
(configuration, app_container)
7255
}
7356

7457
/// checks if the seed is the instance seed in production.
@@ -83,15 +66,31 @@ pub fn check_seed() {
8366
assert_eq!(seed, instance, "maybe using zeroed seed in production!?");
8467
}
8568

86-
/// It initializes the application with the given configuration.
87-
///
88-
/// The configuration may be obtained from the environment (via config file or env vars).
89-
#[must_use]
69+
/// It initializes the global services.
9070
#[instrument(skip())]
91-
pub fn initialize_with_configuration(configuration: &Configuration) -> Arc<Tracker> {
71+
pub fn initialize_global_services(configuration: &Configuration) {
9272
initialize_static();
9373
initialize_logging(configuration);
94-
Arc::new(initialize_tracker(configuration))
74+
}
75+
76+
/// It initializes the IoC Container.
77+
#[instrument(skip())]
78+
pub fn initialize_app_container(configuration: &Configuration) -> AppContainer {
79+
let (stats_event_sender, stats_repository) = statistics::setup::factory(configuration.core.tracker_usage_statistics);
80+
let stats_event_sender = Arc::new(stats_event_sender);
81+
let stats_repository = Arc::new(stats_repository);
82+
let ban_service = Arc::new(RwLock::new(BanService::new(MAX_CONNECTION_ID_ERRORS_PER_IP)));
83+
let database = initialize_database(configuration);
84+
let whitelist_manager = initialize_whitelist(database.clone());
85+
let tracker = Arc::new(initialize_tracker(configuration, &database, &whitelist_manager));
86+
87+
AppContainer {
88+
tracker,
89+
ban_service,
90+
stats_event_sender,
91+
stats_repository,
92+
whitelist_manager,
93+
}
9594
}
9695

9796
/// It initializes the application static values.
@@ -115,27 +114,6 @@ pub fn initialize_static() {
115114
lazy_static::initialize(&ephemeral_instance_keys::ZEROED_TEST_CIPHER_BLOWFISH);
116115
}
117116

118-
/// It builds the domain tracker
119-
///
120-
/// The tracker is the domain layer service. It's the entrypoint to make requests to the domain layer.
121-
/// It's used by other higher-level components like the UDP and HTTP trackers or the tracker API.
122-
#[must_use]
123-
#[instrument(skip(config))]
124-
pub fn initialize_tracker(config: &Configuration) -> Tracker {
125-
let (database, whitelist_manager) = initialize_tracker_dependencies(config);
126-
127-
tracker_factory(config, &database, &whitelist_manager)
128-
}
129-
130-
#[allow(clippy::type_complexity)]
131-
#[must_use]
132-
pub fn initialize_tracker_dependencies(config: &Configuration) -> (Arc<Box<dyn Database>>, Arc<WhiteListManager>) {
133-
let database = initialize_database(config);
134-
let whitelist_manager = initialize_whitelist(database.clone());
135-
136-
(database, whitelist_manager)
137-
}
138-
139117
/// It initializes the log threshold, format and channel.
140118
///
141119
/// See [the logging setup](crate::bootstrap::logging::setup) for more info about logging.

src/bootstrap/jobs/http_tracker.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ mod tests {
8686

8787
use torrust_tracker_test_helpers::configuration::ephemeral_public;
8888

89-
use crate::bootstrap::app::initialize_with_configuration;
89+
use crate::bootstrap::app::initialize_global_services;
9090
use crate::bootstrap::jobs::http_tracker::start_job;
91-
use crate::core::services::statistics;
91+
use crate::core::services::{initialize_database, initialize_tracker, initialize_whitelist, statistics};
9292
use crate::servers::http::Version;
9393
use crate::servers::registar::Registar;
9494

@@ -97,9 +97,16 @@ mod tests {
9797
let cfg = Arc::new(ephemeral_public());
9898
let http_tracker = cfg.http_trackers.clone().expect("missing HTTP tracker configuration");
9999
let config = &http_tracker[0];
100+
100101
let (stats_event_sender, _stats_repository) = statistics::setup::factory(cfg.core.tracker_usage_statistics);
101102
let stats_event_sender = Arc::new(stats_event_sender);
102-
let tracker = initialize_with_configuration(&cfg);
103+
104+
initialize_global_services(&cfg);
105+
106+
let database = initialize_database(&cfg);
107+
let whitelist_manager = initialize_whitelist(database.clone());
108+
let tracker = Arc::new(initialize_tracker(&cfg, &database, &whitelist_manager));
109+
103110
let version = Version::V1;
104111

105112
start_job(config, tracker, stats_event_sender, Registar::default().give_form(), version)

src/bootstrap/jobs/tracker_apis.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ mod tests {
140140
use tokio::sync::RwLock;
141141
use torrust_tracker_test_helpers::configuration::ephemeral_public;
142142

143-
use crate::bootstrap::app::initialize_with_configuration;
143+
use crate::bootstrap::app::initialize_global_services;
144144
use crate::bootstrap::jobs::tracker_apis::start_job;
145-
use crate::core::services::statistics;
145+
use crate::core::services::{initialize_database, initialize_tracker, initialize_whitelist, statistics};
146146
use crate::servers::apis::Version;
147147
use crate::servers::registar::Registar;
148148
use crate::servers::udp::server::banning::BanService;
@@ -158,7 +158,11 @@ mod tests {
158158
let stats_event_sender = Arc::new(stats_event_sender);
159159
let stats_repository = Arc::new(stats_repository);
160160

161-
let tracker = initialize_with_configuration(&cfg);
161+
initialize_global_services(&cfg);
162+
163+
let database = initialize_database(&cfg);
164+
let whitelist_manager = initialize_whitelist(database.clone());
165+
let tracker = Arc::new(initialize_tracker(&cfg, &database, &whitelist_manager));
162166

163167
let version = Version::V1;
164168

src/console/profiling.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ pub async fn run() {
179179
return;
180180
};
181181

182-
let (config, tracker, ban_service, stats_event_sender, stats_repository) = bootstrap::app::setup();
182+
let (config, app_container) = bootstrap::app::setup();
183183

184-
let jobs = app::start(&config, tracker, ban_service, stats_event_sender, stats_repository).await;
184+
let jobs = app::start(&config, &app_container).await;
185185

186186
// Run the tracker for a fixed duration
187187
let run_duration = sleep(Duration::from_secs(duration_secs));

src/container.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::sync::Arc;
2+
3+
use tokio::sync::RwLock;
4+
5+
use crate::core::statistics::event::sender::Sender;
6+
use crate::core::statistics::repository::Repository;
7+
use crate::core::whitelist::WhiteListManager;
8+
use crate::core::Tracker;
9+
use crate::servers::udp::server::banning::BanService;
10+
11+
pub struct AppContainer {
12+
pub tracker: Arc<Tracker>,
13+
pub ban_service: Arc<RwLock<BanService>>,
14+
pub stats_event_sender: Arc<Option<Box<dyn Sender>>>,
15+
pub stats_repository: Arc<Repository>,
16+
pub whitelist_manager: Arc<WhiteListManager>,
17+
}

src/core/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1080,28 +1080,28 @@ mod tests {
10801080
use torrust_tracker_primitives::DurationSinceUnixEpoch;
10811081
use torrust_tracker_test_helpers::configuration;
10821082

1083-
use crate::bootstrap::app::initialize_tracker_dependencies;
1083+
use crate::app_test::initialize_tracker_dependencies;
10841084
use crate::core::peer::Peer;
1085-
use crate::core::services::tracker_factory;
1085+
use crate::core::services::initialize_tracker;
10861086
use crate::core::whitelist::WhiteListManager;
10871087
use crate::core::{TorrentsMetrics, Tracker};
10881088

10891089
fn public_tracker() -> Tracker {
10901090
let config = configuration::ephemeral_public();
10911091
let (database, whitelist_manager) = initialize_tracker_dependencies(&config);
1092-
tracker_factory(&config, &database, &whitelist_manager)
1092+
initialize_tracker(&config, &database, &whitelist_manager)
10931093
}
10941094

10951095
fn private_tracker() -> Tracker {
10961096
let config = configuration::ephemeral_private();
10971097
let (database, whitelist_manager) = initialize_tracker_dependencies(&config);
1098-
tracker_factory(&config, &database, &whitelist_manager)
1098+
initialize_tracker(&config, &database, &whitelist_manager)
10991099
}
11001100

11011101
fn whitelisted_tracker() -> (Tracker, Arc<WhiteListManager>) {
11021102
let config = configuration::ephemeral_listed();
11031103
let (database, whitelist_manager) = initialize_tracker_dependencies(&config);
1104-
let tracker = tracker_factory(&config, &database, &whitelist_manager);
1104+
let tracker = initialize_tracker(&config, &database, &whitelist_manager);
11051105

11061106
(tracker, whitelist_manager)
11071107
}
@@ -1110,7 +1110,7 @@ mod tests {
11101110
let mut config = configuration::ephemeral_listed();
11111111
config.core.tracker_policy.persistent_torrent_completed_stat = true;
11121112
let (database, whitelist_manager) = initialize_tracker_dependencies(&config);
1113-
tracker_factory(&config, &database, &whitelist_manager)
1113+
initialize_tracker(&config, &database, &whitelist_manager)
11141114
}
11151115

11161116
fn sample_info_hash() -> InfoHash {

0 commit comments

Comments
 (0)