torrust_tracker/
app.rs

1//! Torrust Tracker application.
2//!
3//! The tracker application has a global configuration for multiple jobs.
4//! It's basically a container for other services.
5//! It also check constraint and dependencies between services. For example:
6//! It's not safe to run a UDP tracker on top of a core public tracker, as UDP trackers
7//! do not allow private access to the tracker data.
8//!
9//! The application is responsible for:
10//!
11//! - Loading data from the database when it's needed.
12//! - Starting some jobs depending on the configuration.
13//!
14//! Jobs executed always:
15//!
16//! - Health Check API
17//!
18//! Optional jobs:
19//!
20//! - Torrent cleaner: it removes inactive peers and (optionally) peerless torrents.
21//! - UDP trackers: the user can enable multiple UDP tracker on several ports.
22//! - HTTP trackers: the user can enable multiple HTTP tracker on several ports.
23//! - Tracker REST API: the tracker API can be enabled/disabled.
24use std::sync::Arc;
25
26use tokio::task::JoinHandle;
27use torrust_tracker_configuration::Configuration;
28use tracing::instrument;
29
30use crate::bootstrap::jobs::{health_check_api, http_tracker, torrent_cleanup, tracker_apis, udp_tracker};
31use crate::servers::registar::Registar;
32use crate::{core, servers};
33
34/// # Panics
35///
36/// Will panic if:
37///
38/// - Can't retrieve tracker keys from database.
39/// - Can't load whitelist from database.
40#[instrument(skip(config, tracker))]
41pub async fn start(config: &Configuration, tracker: Arc<core::Tracker>) -> Vec<JoinHandle<()>> {
42    if config.http_api.is_none()
43        && (config.udp_trackers.is_none() || config.udp_trackers.as_ref().map_or(true, std::vec::Vec::is_empty))
44        && (config.http_trackers.is_none() || config.http_trackers.as_ref().map_or(true, std::vec::Vec::is_empty))
45    {
46        tracing::warn!("No services enabled in configuration");
47    }
48
49    let mut jobs: Vec<JoinHandle<()>> = Vec::new();
50
51    let registar = Registar::default();
52
53    // Load peer keys
54    if tracker.is_private() {
55        tracker
56            .load_keys_from_database()
57            .await
58            .expect("Could not retrieve keys from database.");
59    }
60
61    // Load whitelisted torrents
62    if tracker.is_listed() {
63        tracker
64            .load_whitelist_from_database()
65            .await
66            .expect("Could not load whitelist from database.");
67    }
68
69    // Start the UDP blocks
70    if let Some(udp_trackers) = &config.udp_trackers {
71        for udp_tracker_config in udp_trackers {
72            if tracker.is_private() {
73                tracing::warn!(
74                    "Could not start UDP tracker on: {} while in private mode. UDP is not safe for private trackers!",
75                    udp_tracker_config.bind_address
76                );
77            } else {
78                jobs.push(udp_tracker::start_job(udp_tracker_config, tracker.clone(), registar.give_form()).await);
79            }
80        }
81    } else {
82        tracing::info!("No UDP blocks in configuration");
83    }
84
85    // Start the HTTP blocks
86    if let Some(http_trackers) = &config.http_trackers {
87        for http_tracker_config in http_trackers {
88            if let Some(job) = http_tracker::start_job(
89                http_tracker_config,
90                tracker.clone(),
91                registar.give_form(),
92                servers::http::Version::V1,
93            )
94            .await
95            {
96                jobs.push(job);
97            };
98        }
99    } else {
100        tracing::info!("No HTTP blocks in configuration");
101    }
102
103    // Start HTTP API
104    if let Some(http_api_config) = &config.http_api {
105        if let Some(job) = tracker_apis::start_job(
106            http_api_config,
107            tracker.clone(),
108            registar.give_form(),
109            servers::apis::Version::V1,
110        )
111        .await
112        {
113            jobs.push(job);
114        };
115    } else {
116        tracing::info!("No API block in configuration");
117    }
118
119    // Start runners to remove torrents without peers, every interval
120    if config.core.inactive_peer_cleanup_interval > 0 {
121        jobs.push(torrent_cleanup::start_job(&config.core, &tracker));
122    }
123
124    // Start Health Check API
125    jobs.push(health_check_api::start_job(&config.health_check_api, registar.entries()).await);
126
127    jobs
128}