Skip to content

Commit 3b49257

Browse files
committed
dev: extract config from core::tracker
1 parent dde3d8d commit 3b49257

File tree

19 files changed

+202
-184
lines changed

19 files changed

+202
-184
lines changed

packages/configuration/src/lib.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@
229229
//! [health_check_api]
230230
//! bind_address = "127.0.0.1:1313"
231231
//!```
232-
use std::collections::{HashMap, HashSet};
232+
use std::collections::HashMap;
233233
use std::net::IpAddr;
234234
use std::str::FromStr;
235235
use std::sync::Arc;
@@ -337,6 +337,8 @@ pub struct HttpTracker {
337337
pub ssl_key_path: Option<String>,
338338
}
339339

340+
pub type AccessTokens = HashMap<String, String>;
341+
340342
/// Configuration for the HTTP API.
341343
#[serde_as]
342344
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
@@ -360,21 +362,13 @@ pub struct HttpApi {
360362
/// token and the value is the token itself. The token is used to
361363
/// authenticate the user. All tokens are valid for all endpoints and have
362364
/// the all permissions.
363-
pub access_tokens: HashMap<String, String>,
365+
pub access_tokens: AccessTokens,
364366
}
365367

366368
impl HttpApi {
367369
fn override_admin_token(&mut self, api_admin_token: &str) {
368370
self.access_tokens.insert("admin".to_string(), api_admin_token.to_string());
369371
}
370-
371-
/// Checks if the given token is one of the token in the configuration.
372-
#[must_use]
373-
pub fn contains_token(&self, token: &str) -> bool {
374-
let tokens: HashMap<String, String> = self.access_tokens.clone();
375-
let tokens: HashSet<String> = tokens.into_values().collect();
376-
tokens.contains(token)
377-
}
378372
}
379373

380374
/// Configuration for the Health Check API.
@@ -804,7 +798,7 @@ mod tests {
804798
fn http_api_configuration_should_check_if_it_contains_a_token() {
805799
let configuration = Configuration::default();
806800

807-
assert!(configuration.http_api.contains_token("MyAccessToken"));
808-
assert!(!configuration.http_api.contains_token("NonExistingToken"));
801+
assert!(configuration.http_api.access_tokens.values().any(|t| t == "MyAccessToken"));
802+
assert!(!configuration.http_api.access_tokens.values().any(|t| t == "NonExistingToken"));
809803
}
810804
}

src/bootstrap/app.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ use crate::shared::crypto::ephemeral_instance_keys;
2424

2525
/// It loads the configuration from the environment and builds the main domain [`Tracker`] struct.
2626
#[must_use]
27-
pub fn setup() -> (Arc<Configuration>, Arc<Tracker>) {
28-
let configuration = Arc::new(initialize_configuration());
27+
pub fn setup() -> (Configuration, Arc<Tracker>) {
28+
let configuration = initialize_configuration();
2929
let tracker = initialize_with_configuration(&configuration);
3030

3131
(configuration, tracker)
@@ -35,7 +35,7 @@ pub fn setup() -> (Arc<Configuration>, Arc<Tracker>) {
3535
///
3636
/// The configuration may be obtained from the environment (via config file or env vars).
3737
#[must_use]
38-
pub fn initialize_with_configuration(configuration: &Arc<Configuration>) -> Arc<Tracker> {
38+
pub fn initialize_with_configuration(configuration: &Configuration) -> Arc<Tracker> {
3939
initialize_static();
4040
initialize_logging(configuration);
4141
Arc::new(initialize_tracker(configuration))
@@ -60,13 +60,13 @@ pub fn initialize_static() {
6060
/// The tracker is the domain layer service. It's the entrypoint to make requests to the domain layer.
6161
/// It's used by other higher-level components like the UDP and HTTP trackers or the tracker API.
6262
#[must_use]
63-
pub fn initialize_tracker(config: &Arc<Configuration>) -> Tracker {
64-
tracker_factory(config.clone())
63+
pub fn initialize_tracker(config: &Configuration) -> Tracker {
64+
tracker_factory(config)
6565
}
6666

6767
/// It initializes the log level, format and channel.
6868
///
6969
/// See [the logging setup](crate::bootstrap::logging::setup) for more info about logging.
70-
pub fn initialize_logging(config: &Arc<Configuration>) {
70+
pub fn initialize_logging(config: &Configuration) {
7171
bootstrap::logging::setup(config);
7272
}

src/bootstrap/jobs/torrent_cleanup.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::core;
2525
///
2626
/// Refer to [`torrust-tracker-configuration documentation`](https://docs.rs/torrust-tracker-configuration) for more info about that option.
2727
#[must_use]
28-
pub fn start_job(config: &Arc<Configuration>, tracker: &Arc<core::Tracker>) -> JoinHandle<()> {
28+
pub fn start_job(config: &Configuration, tracker: &Arc<core::Tracker>) -> JoinHandle<()> {
2929
let weak_tracker = std::sync::Arc::downgrade(tracker);
3030
let interval = config.inactive_peer_cleanup_interval;
3131

src/bootstrap/jobs/tracker_apis.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::sync::Arc;
2626
use axum_server::tls_rustls::RustlsConfig;
2727
use log::info;
2828
use tokio::task::JoinHandle;
29-
use torrust_tracker_configuration::HttpApi;
29+
use torrust_tracker_configuration::{AccessTokens, HttpApi};
3030

3131
use super::make_rust_tls;
3232
use crate::core;
@@ -64,18 +64,25 @@ pub async fn start_job(config: &HttpApi, tracker: Arc<core::Tracker>, version: V
6464
.await
6565
.map(|tls| tls.expect("it should have a valid tracker api tls configuration"));
6666

67+
let access_tokens = Arc::new(config.access_tokens.clone());
68+
6769
match version {
68-
Version::V1 => Some(start_v1(bind_to, tls, tracker.clone()).await),
70+
Version::V1 => Some(start_v1(bind_to, tls, tracker.clone(), access_tokens).await),
6971
}
7072
} else {
7173
info!("Note: Not loading Http Tracker Service, Not Enabled in Configuration.");
7274
None
7375
}
7476
}
7577

76-
async fn start_v1(socket: SocketAddr, tls: Option<RustlsConfig>, tracker: Arc<core::Tracker>) -> JoinHandle<()> {
78+
async fn start_v1(
79+
socket: SocketAddr,
80+
tls: Option<RustlsConfig>,
81+
tracker: Arc<core::Tracker>,
82+
access_tokens: Arc<AccessTokens>,
83+
) -> JoinHandle<()> {
7784
let server = ApiServer::new(Launcher::new(socket, tls))
78-
.start(tracker)
85+
.start(tracker, access_tokens)
7986
.await
8087
.expect("it should be able to start to the tracker api");
8188

src/core/mod.rs

+50-20
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ use std::time::Duration;
447447

448448
use derive_more::Constructor;
449449
use futures::future::join_all;
450+
use log::debug;
450451
use tokio::sync::mpsc::error::SendError;
451452
use torrust_tracker_configuration::{AnnouncePolicy, Configuration};
452453
use torrust_tracker_primitives::TrackerMode;
@@ -472,17 +473,19 @@ pub const TORRENT_PEERS_LIMIT: usize = 74;
472473
/// Typically, the `Tracker` is used by a higher application service that handles
473474
/// the network layer.
474475
pub struct Tracker {
475-
/// `Tracker` configuration. See [`torrust-tracker-configuration`](torrust_tracker_configuration)
476-
pub config: Arc<Configuration>,
476+
announce_policy: AnnouncePolicy,
477477
/// A database driver implementation: [`Sqlite3`](crate::core::databases::sqlite)
478478
/// or [`MySQL`](crate::core::databases::mysql)
479479
pub database: Arc<Box<dyn Database>>,
480480
mode: TrackerMode,
481+
policy: TrackerPolicy,
481482
keys: tokio::sync::RwLock<std::collections::HashMap<Key, auth::ExpiringKey>>,
482483
whitelist: tokio::sync::RwLock<std::collections::HashSet<InfoHash>>,
483484
pub torrents: Arc<RepositoryAsyncSingle>,
484485
stats_event_sender: Option<Box<dyn statistics::EventSender>>,
485486
stats_repository: statistics::Repo,
487+
external_ip: Option<IpAddr>,
488+
on_reverse_proxy: bool,
486489
}
487490

488491
/// Structure that holds general `Tracker` torrents metrics.
@@ -500,6 +503,12 @@ pub struct TorrentsMetrics {
500503
pub torrents: u64,
501504
}
502505

506+
#[derive(Copy, Clone, Debug, PartialEq, Default, Constructor)]
507+
pub struct TrackerPolicy {
508+
pub remove_peerless_torrents: bool,
509+
pub max_peer_timeout: u32,
510+
pub persistent_torrent_completed_stat: bool,
511+
}
503512
/// Structure that holds the data returned by the `announce` request.
504513
#[derive(Clone, Debug, PartialEq, Constructor, Default)]
505514
pub struct AnnounceData {
@@ -556,7 +565,7 @@ impl Tracker {
556565
///
557566
/// Will return a `databases::error::Error` if unable to connect to database. The `Tracker` is responsible for the persistence.
558567
pub fn new(
559-
config: Arc<Configuration>,
568+
config: &Configuration,
560569
stats_event_sender: Option<Box<dyn statistics::EventSender>>,
561570
stats_repository: statistics::Repo,
562571
) -> Result<Tracker, databases::error::Error> {
@@ -565,14 +574,22 @@ impl Tracker {
565574
let mode = config.mode;
566575

567576
Ok(Tracker {
568-
config,
577+
//config,
578+
announce_policy: AnnouncePolicy::new(config.announce_interval, config.min_announce_interval),
569579
mode,
570580
keys: tokio::sync::RwLock::new(std::collections::HashMap::new()),
571581
whitelist: tokio::sync::RwLock::new(std::collections::HashSet::new()),
572582
torrents: Arc::new(RepositoryAsyncSingle::new()),
573583
stats_event_sender,
574584
stats_repository,
575585
database,
586+
external_ip: config.get_ext_ip(),
587+
policy: TrackerPolicy::new(
588+
config.remove_peerless_torrents,
589+
config.max_peer_timeout,
590+
config.persistent_torrent_completed_stat,
591+
),
592+
on_reverse_proxy: config.on_reverse_proxy,
576593
})
577594
}
578595

@@ -596,6 +613,19 @@ impl Tracker {
596613
self.is_private()
597614
}
598615

616+
/// Returns `true` is the tracker is in whitelisted mode.
617+
pub fn is_behind_reverse_proxy(&self) -> bool {
618+
self.on_reverse_proxy
619+
}
620+
621+
pub fn get_announce_policy(&self) -> AnnouncePolicy {
622+
self.announce_policy
623+
}
624+
625+
pub fn get_maybe_external_ip(&self) -> Option<IpAddr> {
626+
self.external_ip
627+
}
628+
599629
/// It handles an announce request.
600630
///
601631
/// # Context: Tracker
@@ -617,18 +647,19 @@ impl Tracker {
617647
// we are actually handling authentication at the handlers level. So I would extract that
618648
// responsibility into another authentication service.
619649

620-
peer.change_ip(&assign_ip_address_to_peer(remote_client_ip, self.config.get_ext_ip()));
650+
debug!("Before: {peer:?}");
651+
peer.change_ip(&assign_ip_address_to_peer(remote_client_ip, self.external_ip));
652+
debug!("After: {peer:?}");
621653

622-
let swarm_stats = self.update_torrent_with_peer_and_get_stats(info_hash, peer).await;
654+
// we should update the torrent and get the stats before we get the peer list.
655+
let stats = self.update_torrent_with_peer_and_get_stats(info_hash, peer).await;
623656

624657
let peers = self.get_torrent_peers_for_peer(info_hash, peer).await;
625658

626-
let policy = AnnouncePolicy::new(self.config.announce_interval, self.config.min_announce_interval);
627-
628659
AnnounceData {
629660
peers,
630-
stats: swarm_stats,
631-
policy,
661+
stats,
662+
policy: self.get_announce_policy(),
632663
}
633664
}
634665

@@ -727,7 +758,7 @@ impl Tracker {
727758

728759
let (stats, stats_updated) = self.torrents.update_torrent_with_peer_and_get_stats(info_hash, peer).await;
729760

730-
if self.config.persistent_torrent_completed_stat && stats_updated {
761+
if self.policy.persistent_torrent_completed_stat && stats_updated {
731762
let completed = stats.downloaded;
732763
let info_hash = *info_hash;
733764

@@ -788,17 +819,17 @@ impl Tracker {
788819
let mut torrents_lock = self.torrents.get_torrents_mut().await;
789820

790821
// If we don't need to remove torrents we will use the faster iter
791-
if self.config.remove_peerless_torrents {
822+
if self.policy.remove_peerless_torrents {
792823
let mut cleaned_torrents_map: BTreeMap<InfoHash, torrent::Entry> = BTreeMap::new();
793824

794825
for (info_hash, torrent_entry) in &mut *torrents_lock {
795-
torrent_entry.remove_inactive_peers(self.config.max_peer_timeout);
826+
torrent_entry.remove_inactive_peers(self.policy.max_peer_timeout);
796827

797828
if torrent_entry.peers.is_empty() {
798829
continue;
799830
}
800831

801-
if self.config.persistent_torrent_completed_stat && torrent_entry.completed == 0 {
832+
if self.policy.persistent_torrent_completed_stat && torrent_entry.completed == 0 {
802833
continue;
803834
}
804835

@@ -808,7 +839,7 @@ impl Tracker {
808839
*torrents_lock = cleaned_torrents_map;
809840
} else {
810841
for torrent_entry in (*torrents_lock).values_mut() {
811-
torrent_entry.remove_inactive_peers(self.config.max_peer_timeout);
842+
torrent_entry.remove_inactive_peers(self.policy.max_peer_timeout);
812843
}
813844
}
814845
}
@@ -1061,7 +1092,6 @@ mod tests {
10611092

10621093
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
10631094
use std::str::FromStr;
1064-
use std::sync::Arc;
10651095

10661096
use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes};
10671097
use torrust_tracker_test_helpers::configuration;
@@ -1073,21 +1103,21 @@ mod tests {
10731103
use crate::shared::clock::DurationSinceUnixEpoch;
10741104

10751105
fn public_tracker() -> Tracker {
1076-
tracker_factory(configuration::ephemeral_mode_public().into())
1106+
tracker_factory(&configuration::ephemeral_mode_public())
10771107
}
10781108

10791109
fn private_tracker() -> Tracker {
1080-
tracker_factory(configuration::ephemeral_mode_private().into())
1110+
tracker_factory(&configuration::ephemeral_mode_private())
10811111
}
10821112

10831113
fn whitelisted_tracker() -> Tracker {
1084-
tracker_factory(configuration::ephemeral_mode_whitelisted().into())
1114+
tracker_factory(&configuration::ephemeral_mode_whitelisted())
10851115
}
10861116

10871117
pub fn tracker_persisting_torrents_in_database() -> Tracker {
10881118
let mut configuration = configuration::ephemeral();
10891119
configuration.persistent_torrent_completed_stat = true;
1090-
tracker_factory(Arc::new(configuration))
1120+
tracker_factory(&configuration)
10911121
}
10921122

10931123
fn sample_info_hash() -> InfoHash {

src/core/services/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ use crate::core::Tracker;
1919
///
2020
/// Will panic if tracker cannot be instantiated.
2121
#[must_use]
22-
pub fn tracker_factory(config: Arc<Configuration>) -> Tracker {
22+
pub fn tracker_factory(config: &Configuration) -> Tracker {
2323
// Initialize statistics
2424
let (stats_event_sender, stats_repository) = statistics::setup::factory(config.tracker_usage_statistics);
2525

2626
// Initialize Torrust tracker
27-
match Tracker::new(config, stats_event_sender, stats_repository) {
27+
match Tracker::new(&Arc::new(config), stats_event_sender, stats_repository) {
2828
Ok(tracker) => tracker,
2929
Err(error) => {
3030
panic!("{}", error)

src/core/services/statistics/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ mod tests {
9292
use crate::core::services::statistics::{get_metrics, TrackerMetrics};
9393
use crate::core::services::tracker_factory;
9494

95-
pub fn tracker_configuration() -> Arc<Configuration> {
96-
Arc::new(configuration::ephemeral())
95+
pub fn tracker_configuration() -> Configuration {
96+
configuration::ephemeral()
9797
}
9898

9999
#[tokio::test]
100100
async fn the_statistics_service_should_return_the_tracker_metrics() {
101-
let tracker = Arc::new(tracker_factory(tracker_configuration()));
101+
let tracker = Arc::new(tracker_factory(&tracker_configuration()));
102102

103103
let tracker_metrics = get_metrics(tracker.clone()).await;
104104

0 commit comments

Comments
 (0)