Skip to content

Commit

Permalink
refactor: [#852] extract Core configuration type
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed May 10, 2024
1 parent 7519ecc commit b545b33
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 118 deletions.
4 changes: 2 additions & 2 deletions packages/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module contains the configuration data structures for the
//! Torrust Tracker, which is a `BitTorrent` tracker server.
//!
//! The current version for configuration is [`v1`](crate::v1).
//! The current version for configuration is [`v1`].
pub mod v1;

use std::collections::HashMap;
Expand Down Expand Up @@ -172,7 +172,7 @@ pub struct TslConfig {
pub ssl_key_path: Option<Utf8PathBuf>,
}

#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
#[serde(rename_all = "lowercase")]
pub enum LogLevel {
/// A level lower than all log levels.
Expand Down
88 changes: 88 additions & 0 deletions packages/configuration/src/v1/core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::net::{IpAddr, Ipv4Addr};

use serde::{Deserialize, Serialize};
use torrust_tracker_primitives::{DatabaseDriver, TrackerMode};

use crate::{AnnouncePolicy, LogLevel};

#[allow(clippy::struct_excessive_bools)]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct Core {
/// Logging level. Possible values are: `Off`, `Error`, `Warn`, `Info`,
/// `Debug` and `Trace`. Default is `Info`.
pub log_level: Option<LogLevel>,
/// Tracker mode. See [`TrackerMode`] for more information.
pub mode: TrackerMode,

// Database configuration
/// Database driver. Possible values are: `Sqlite3`, and `MySQL`.
pub db_driver: DatabaseDriver,
/// Database connection string. The format depends on the database driver.
/// For `Sqlite3`, the format is `path/to/database.db`, for example:
/// `./storage/tracker/lib/database/sqlite3.db`.
/// For `Mysql`, the format is `mysql://db_user:db_user_password:port/db_name`, for
/// example: `root:password@localhost:3306/torrust`.
pub db_path: String,

/// See [`AnnouncePolicy::interval`]
pub announce_interval: u32,

/// See [`AnnouncePolicy::interval_min`]
pub min_announce_interval: u32,
/// Weather the tracker is behind a reverse proxy or not.
/// If the tracker is behind a reverse proxy, the `X-Forwarded-For` header
/// sent from the proxy will be used to get the client's IP address.
pub on_reverse_proxy: bool,
/// The external IP address of the tracker. If the client is using a
/// loopback IP address, this IP address will be used instead. If the peer
/// is using a loopback IP address, the tracker assumes that the peer is
/// in the same network as the tracker and will use the tracker's IP
/// address instead.
pub external_ip: Option<IpAddr>,
/// Weather the tracker should collect statistics about tracker usage.
/// If enabled, the tracker will collect statistics like the number of
/// connections handled, the number of announce requests handled, etc.
/// Refer to the [`Tracker`](https://docs.rs/torrust-tracker) for more
/// information about the collected metrics.
pub tracker_usage_statistics: bool,
/// If enabled the tracker will persist the number of completed downloads.
/// That's how many times a torrent has been downloaded completely.
pub persistent_torrent_completed_stat: bool,

// Cleanup job configuration
/// Maximum time in seconds that a peer can be inactive before being
/// considered an inactive peer. If a peer is inactive for more than this
/// time, it will be removed from the torrent peer list.
pub max_peer_timeout: u32,
/// Interval in seconds that the cleanup job will run to remove inactive
/// peers from the torrent peer list.
pub inactive_peer_cleanup_interval: u64,
/// If enabled, the tracker will remove torrents that have no peers.
/// The clean up torrent job runs every `inactive_peer_cleanup_interval`
/// seconds and it removes inactive peers. Eventually, the peer list of a
/// torrent could be empty and the torrent will be removed if this option is
/// enabled.
pub remove_peerless_torrents: bool,
}

impl Default for Core {
fn default() -> Self {
let announce_policy = AnnouncePolicy::default();

Self {
log_level: Some(LogLevel::Info),
mode: TrackerMode::Public,
db_driver: DatabaseDriver::Sqlite3,
db_path: String::from("./storage/tracker/lib/database/sqlite3.db"),
announce_interval: announce_policy.interval,
min_announce_interval: announce_policy.interval_min,
max_peer_timeout: 900,
on_reverse_proxy: false,
external_ip: Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))),
tracker_usage_statistics: true,
persistent_torrent_completed_stat: false,
inactive_peer_cleanup_interval: 600,
remove_peerless_torrents: true,
}
}
}
101 changes: 15 additions & 86 deletions packages/configuration/src/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
//!
//! Alternatively, you could setup a reverse proxy like Nginx or Apache to
//! handle the SSL/TLS part and forward the requests to the tracker. If you do
//! that, you should set [`on_reverse_proxy`](crate::Configuration::on_reverse_proxy)
//! that, you should set [`on_reverse_proxy`](crate::v1::core::Core::on_reverse_proxy)
//! to `true` in the configuration file. It's out of scope for this
//! documentation to explain in detail how to setup a reverse proxy, but the
//! configuration file should be something like this:
Expand Down Expand Up @@ -230,86 +230,32 @@
//! [health_check_api]
//! bind_address = "127.0.0.1:1313"
//!```
pub mod core;
pub mod health_check_api;
pub mod http_tracker;
pub mod tracker_api;
pub mod udp_tracker;

use std::fs;
use std::net::{IpAddr, Ipv4Addr};
use std::net::IpAddr;

use figment::providers::{Env, Format, Serialized, Toml};
use figment::Figment;
use serde::{Deserialize, Serialize};
use torrust_tracker_primitives::{DatabaseDriver, TrackerMode};

use self::core::Core;
use self::health_check_api::HealthCheckApi;
use self::http_tracker::HttpTracker;
use self::tracker_api::HttpApi;
use self::udp_tracker::UdpTracker;
use crate::{AnnouncePolicy, Error, Info, LogLevel};
use crate::{Error, Info};

/// Core configuration for the tracker.
#[allow(clippy::struct_excessive_bools)]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct Configuration {
/// Logging level. Possible values are: `Off`, `Error`, `Warn`, `Info`,
/// `Debug` and `Trace`. Default is `Info`.
pub log_level: Option<LogLevel>,
/// Tracker mode. See [`TrackerMode`] for more information.
pub mode: TrackerMode,

// Database configuration
/// Database driver. Possible values are: `Sqlite3`, and `MySQL`.
pub db_driver: DatabaseDriver,
/// Database connection string. The format depends on the database driver.
/// For `Sqlite3`, the format is `path/to/database.db`, for example:
/// `./storage/tracker/lib/database/sqlite3.db`.
/// For `Mysql`, the format is `mysql://db_user:db_user_password:port/db_name`, for
/// example: `root:password@localhost:3306/torrust`.
pub db_path: String,

/// See [`AnnouncePolicy::interval`]
pub announce_interval: u32,

/// See [`AnnouncePolicy::interval_min`]
pub min_announce_interval: u32,
/// Weather the tracker is behind a reverse proxy or not.
/// If the tracker is behind a reverse proxy, the `X-Forwarded-For` header
/// sent from the proxy will be used to get the client's IP address.
pub on_reverse_proxy: bool,
/// The external IP address of the tracker. If the client is using a
/// loopback IP address, this IP address will be used instead. If the peer
/// is using a loopback IP address, the tracker assumes that the peer is
/// in the same network as the tracker and will use the tracker's IP
/// address instead.
pub external_ip: Option<IpAddr>,
/// Weather the tracker should collect statistics about tracker usage.
/// If enabled, the tracker will collect statistics like the number of
/// connections handled, the number of announce requests handled, etc.
/// Refer to the [`Tracker`](https://docs.rs/torrust-tracker) for more
/// information about the collected metrics.
pub tracker_usage_statistics: bool,
/// If enabled the tracker will persist the number of completed downloads.
/// That's how many times a torrent has been downloaded completely.
pub persistent_torrent_completed_stat: bool,

// Cleanup job configuration
/// Maximum time in seconds that a peer can be inactive before being
/// considered an inactive peer. If a peer is inactive for more than this
/// time, it will be removed from the torrent peer list.
pub max_peer_timeout: u32,
/// Interval in seconds that the cleanup job will run to remove inactive
/// peers from the torrent peer list.
pub inactive_peer_cleanup_interval: u64,
/// If enabled, the tracker will remove torrents that have no peers.
/// The clean up torrent job runs every `inactive_peer_cleanup_interval`
/// seconds and it removes inactive peers. Eventually, the peer list of a
/// torrent could be empty and the torrent will be removed if this option is
/// enabled.
pub remove_peerless_torrents: bool,

// Server jobs configuration
/// Core configuration.
#[serde(flatten)]
pub core: Core,
/// The list of UDP trackers the tracker is running. Each UDP tracker
/// represents a UDP server that the tracker is running and it has its own
/// configuration.
Expand All @@ -326,30 +272,13 @@ pub struct Configuration {

impl Default for Configuration {
fn default() -> Self {
let announce_policy = AnnouncePolicy::default();

let mut configuration = Configuration {
log_level: Some(LogLevel::Info),
mode: TrackerMode::Public,
db_driver: DatabaseDriver::Sqlite3,
db_path: String::from("./storage/tracker/lib/database/sqlite3.db"),
announce_interval: announce_policy.interval,
min_announce_interval: announce_policy.interval_min,
max_peer_timeout: 900,
on_reverse_proxy: false,
external_ip: Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))),
tracker_usage_statistics: true,
persistent_torrent_completed_stat: false,
inactive_peer_cleanup_interval: 600,
remove_peerless_torrents: true,
udp_trackers: Vec::new(),
http_trackers: Vec::new(),
Self {
core: Core::default(),
udp_trackers: vec![UdpTracker::default()],
http_trackers: vec![HttpTracker::default()],
http_api: HttpApi::default(),
health_check_api: HealthCheckApi::default(),
};
configuration.udp_trackers.push(UdpTracker::default());
configuration.http_trackers.push(HttpTracker::default());
configuration
}
}
}

Expand All @@ -362,7 +291,7 @@ impl Configuration {
/// and `None` otherwise.
#[must_use]
pub fn get_ext_ip(&self) -> Option<IpAddr> {
self.external_ip.as_ref().map(|external_ip| *external_ip)
self.core.external_ip.as_ref().map(|external_ip| *external_ip)
}

/// Saves the default configuration at the given path.
Expand Down Expand Up @@ -490,7 +419,7 @@ mod tests {
fn configuration_should_contain_the_external_ip() {
let configuration = Configuration::default();

assert_eq!(configuration.external_ip, Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))));
assert_eq!(configuration.core.external_ip, Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))));
}

#[test]
Expand Down
23 changes: 11 additions & 12 deletions packages/test-helpers/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ pub fn ephemeral() -> Configuration {
// todo: disable services that are not needed.
// For example: a test for the UDP tracker should disable the API and HTTP tracker.

let mut config = Configuration {
log_level: Some(LogLevel::Off), // Change to `debug` for tests debugging
..Default::default()
};
let mut config = Configuration::default();

config.core.log_level = Some(LogLevel::Off); // Change to `debug` for tests debugging

// Ephemeral socket address for API
let api_port = 0u16;
Expand All @@ -55,7 +54,7 @@ pub fn ephemeral() -> Configuration {
let temp_directory = env::temp_dir();
let random_db_id = random::string(16);
let temp_file = temp_directory.join(format!("data_{random_db_id}.db"));
temp_file.to_str().unwrap().clone_into(&mut config.db_path);
temp_file.to_str().unwrap().clone_into(&mut config.core.db_path);

config
}
Expand All @@ -65,7 +64,7 @@ pub fn ephemeral() -> Configuration {
pub fn ephemeral_with_reverse_proxy() -> Configuration {
let mut cfg = ephemeral();

cfg.on_reverse_proxy = true;
cfg.core.on_reverse_proxy = true;

cfg
}
Expand All @@ -75,7 +74,7 @@ pub fn ephemeral_with_reverse_proxy() -> Configuration {
pub fn ephemeral_without_reverse_proxy() -> Configuration {
let mut cfg = ephemeral();

cfg.on_reverse_proxy = false;
cfg.core.on_reverse_proxy = false;

cfg
}
Expand All @@ -85,7 +84,7 @@ pub fn ephemeral_without_reverse_proxy() -> Configuration {
pub fn ephemeral_mode_public() -> Configuration {
let mut cfg = ephemeral();

cfg.mode = TrackerMode::Public;
cfg.core.mode = TrackerMode::Public;

cfg
}
Expand All @@ -95,7 +94,7 @@ pub fn ephemeral_mode_public() -> Configuration {
pub fn ephemeral_mode_private() -> Configuration {
let mut cfg = ephemeral();

cfg.mode = TrackerMode::Private;
cfg.core.mode = TrackerMode::Private;

cfg
}
Expand All @@ -105,7 +104,7 @@ pub fn ephemeral_mode_private() -> Configuration {
pub fn ephemeral_mode_whitelisted() -> Configuration {
let mut cfg = ephemeral();

cfg.mode = TrackerMode::Listed;
cfg.core.mode = TrackerMode::Listed;

cfg
}
Expand All @@ -115,7 +114,7 @@ pub fn ephemeral_mode_whitelisted() -> Configuration {
pub fn ephemeral_mode_private_whitelisted() -> Configuration {
let mut cfg = ephemeral();

cfg.mode = TrackerMode::PrivateListed;
cfg.core.mode = TrackerMode::PrivateListed;

Check warning on line 117 in packages/test-helpers/src/configuration.rs

View check run for this annotation

Codecov / codecov/patch

packages/test-helpers/src/configuration.rs#L117

Added line #L117 was not covered by tests

cfg
}
Expand All @@ -125,7 +124,7 @@ pub fn ephemeral_mode_private_whitelisted() -> Configuration {
pub fn ephemeral_with_external_ip(ip: IpAddr) -> Configuration {
let mut cfg = ephemeral();

cfg.external_ip = Some(ip);
cfg.core.external_ip = Some(ip);

cfg
}
Expand Down
6 changes: 3 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub async fn start(config: &Configuration, tracker: Arc<core::Tracker>) -> Vec<J
if tracker.is_private() {
warn!(
"Could not start UDP tracker on: {} while in {:?}. UDP is not safe for private trackers!",
udp_tracker_config.bind_address, config.mode
udp_tracker_config.bind_address, config.core.mode
);
} else {
jobs.push(udp_tracker::start_job(udp_tracker_config, tracker.clone(), registar.give_form()).await);
Expand Down Expand Up @@ -107,8 +107,8 @@ pub async fn start(config: &Configuration, tracker: Arc<core::Tracker>) -> Vec<J
}

// Start runners to remove torrents without peers, every interval
if config.inactive_peer_cleanup_interval > 0 {
jobs.push(torrent_cleanup::start_job(config, &tracker));
if config.core.inactive_peer_cleanup_interval > 0 {
jobs.push(torrent_cleanup::start_job(&config.core, &tracker));

Check warning on line 111 in src/app.rs

View check run for this annotation

Codecov / codecov/patch

src/app.rs#L110-L111

Added lines #L110 - L111 were not covered by tests
}

// Start Health Check API
Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap/jobs/torrent_cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::sync::Arc;
use chrono::Utc;
use log::info;
use tokio::task::JoinHandle;
use torrust_tracker_configuration::Configuration;
use torrust_tracker_configuration::v1::core::Core;

use crate::core;

Expand All @@ -25,7 +25,7 @@ use crate::core;
///
/// Refer to [`torrust-tracker-configuration documentation`](https://docs.rs/torrust-tracker-configuration) for more info about that option.
#[must_use]
pub fn start_job(config: &Configuration, tracker: &Arc<core::Tracker>) -> JoinHandle<()> {
pub fn start_job(config: &Core, tracker: &Arc<core::Tracker>) -> JoinHandle<()> {

Check warning on line 28 in src/bootstrap/jobs/torrent_cleanup.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/torrent_cleanup.rs#L28

Added line #L28 was not covered by tests
let weak_tracker = std::sync::Arc::downgrade(tracker);
let interval = config.inactive_peer_cleanup_interval;

Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ static INIT: Once = Once::new();

/// It redirects the log info to the standard output with the log level defined in the configuration
pub fn setup(cfg: &Configuration) {
let level = config_level_or_default(&cfg.log_level);
let level = config_level_or_default(&cfg.core.log_level);

if level == log::LevelFilter::Off {
return;
Expand Down
Loading

0 comments on commit b545b33

Please sign in to comment.