Skip to content

Commit 014ca38

Browse files
committed
Merge #854: Refactor: enrich field types in configuration structs
b545b33 refactor: [#852] extract Core configuration type (Jose Celano) 7519ecc refactor: [#852] enrich field types in Configuration struct (Jose Celano) ceb3074 refactor: [#852] enrich field types in HttpApi config struct (Jose Celano) 3997cfa refactor: [#852] eenrich field types in TslConfig config struct (Jose Celano) a2e718b chore(deps): add dependency camino (Jose Celano) fc191f7 refactor: [#852] enrich field types in HttpTracker config struct (Jose Celano) 1475ead refactor: [#852] eenrich field types in UdpTracker config struct (Jose Celano) 384e9f8 refactor: [#852] eenrich field types in HealthCheckApi config struct (Jose Celano) Pull request description: Relates to: #790 Refactor: enrich field types in configuration structs. This will cause the app to fail earlier while loading invalid configurations and simplify the code by reducing conversions to get the rich type from the primitive when it's used. - [x] `HealthCheckApi` - [x] `UdpTracker` - [x] `HttpTracker` - [x] `HttpApi` - [x] `Configuration` Output example when you provide an invalid socket address: ```output $ cargo run Finished `dev` profile [optimized + debuginfo] target(s) in 0.10s Running `target/debug/torrust-tracker` Loading default configuration file: `./share/default/config/tracker.development.sqlite3.toml` ... thread 'main' panicked at src/bootstrap/config.rs:45:32: called `Result::unwrap()` on an `Err` value: ConfigError { source: LocatedError { source: Error { tag: Tag(Default, 2), profile: Some(Profile(Uncased { string: "default" })), metadata: Some(Metadata { name: "TOML source string", source: None, provide_location: Some(Location { file: "packages/configuration/src/v1/mod.rs", line: 397, col: 14 }), interpolater: }), path: ["health_check_api", "bind_address"], kind: Message("invalid socket address syntax"), prev: None }, location: Location { file: "packages/configuration/src/v1/mod.rs", line: 400, col: 41 } } } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` You get that error proving this config option: ```toml [health_check_api] bind_address = "127.0.0.1-1313" ``` The error contains all the information needed, although it could be more user-friendly. Maybe we can map that error to a simpler explanation like this: ``` Configuration error: invalid socket address provided in toml file PATH in section `health_check_api` option `bind_address`. ``` ACKs for top commit: josecelano: ACK b545b33 Tree-SHA512: 5d4ca16d882447e9eacc882022346e0cd7484f7b5a0d7aa1754e94cde438e6fe486d690d9977df171c9c792ab5ed3cd814bc500f3fac91cfdf76eb76b5306dc7
2 parents a20c9d7 + b545b33 commit 014ca38

33 files changed

+277
-231
lines changed

Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ axum = { version = "0", features = ["macros"] }
3737
axum-client-ip = "0"
3838
axum-extra = { version = "0", features = ["query"] }
3939
axum-server = { version = "0", features = ["tls-rustls"] }
40+
camino = { version = "1.1.6", features = ["serde"] }
4041
chrono = { version = "0", default-features = false, features = ["clock"] }
4142
clap = { version = "4", features = ["derive", "env"] }
4243
crossbeam-skiplist = "0.1"

cSpell.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"Buildx",
2626
"byteorder",
2727
"callgrind",
28+
"camino",
2829
"canonicalize",
2930
"canonicalized",
3031
"certbot",

packages/configuration/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rust-version.workspace = true
1515
version.workspace = true
1616

1717
[dependencies]
18+
camino = { version = "1.1.6", features = ["serde"] }
1819
derive_more = "0"
1920
figment = { version = "0.10.18", features = ["env", "test", "toml"] }
2021
serde = { version = "1", features = ["derive"] }

packages/configuration/src/lib.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
//! This module contains the configuration data structures for the
44
//! Torrust Tracker, which is a `BitTorrent` tracker server.
55
//!
6-
//! The current version for configuration is [`v1`](crate::v1).
6+
//! The current version for configuration is [`v1`].
77
pub mod v1;
88

99
use std::collections::HashMap;
1010
use std::sync::Arc;
1111
use std::{env, fs};
1212

13+
use camino::Utf8PathBuf;
1314
use derive_more::Constructor;
15+
use serde::{Deserialize, Serialize};
16+
use serde_with::{serde_as, NoneAsEmptyString};
1417
use thiserror::Error;
1518
use torrust_tracker_located_error::{DynError, LocatedError};
1619

@@ -157,3 +160,31 @@ impl From<figment::Error> for Error {
157160
}
158161
}
159162
}
163+
164+
#[serde_as]
165+
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)]
166+
pub struct TslConfig {
167+
/// Path to the SSL certificate file.
168+
#[serde_as(as = "NoneAsEmptyString")]
169+
pub ssl_cert_path: Option<Utf8PathBuf>,
170+
/// Path to the SSL key file.
171+
#[serde_as(as = "NoneAsEmptyString")]
172+
pub ssl_key_path: Option<Utf8PathBuf>,
173+
}
174+
175+
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
176+
#[serde(rename_all = "lowercase")]
177+
pub enum LogLevel {
178+
/// A level lower than all log levels.
179+
Off,
180+
/// Corresponds to the `Error` log level.
181+
Error,
182+
/// Corresponds to the `Warn` log level.
183+
Warn,
184+
/// Corresponds to the `Info` log level.
185+
Info,
186+
/// Corresponds to the `Debug` log level.
187+
Debug,
188+
/// Corresponds to the `Trace` log level.
189+
Trace,
190+
}

packages/configuration/src/v1/core.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use std::net::{IpAddr, Ipv4Addr};
2+
3+
use serde::{Deserialize, Serialize};
4+
use torrust_tracker_primitives::{DatabaseDriver, TrackerMode};
5+
6+
use crate::{AnnouncePolicy, LogLevel};
7+
8+
#[allow(clippy::struct_excessive_bools)]
9+
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
10+
pub struct Core {
11+
/// Logging level. Possible values are: `Off`, `Error`, `Warn`, `Info`,
12+
/// `Debug` and `Trace`. Default is `Info`.
13+
pub log_level: Option<LogLevel>,
14+
/// Tracker mode. See [`TrackerMode`] for more information.
15+
pub mode: TrackerMode,
16+
17+
// Database configuration
18+
/// Database driver. Possible values are: `Sqlite3`, and `MySQL`.
19+
pub db_driver: DatabaseDriver,
20+
/// Database connection string. The format depends on the database driver.
21+
/// For `Sqlite3`, the format is `path/to/database.db`, for example:
22+
/// `./storage/tracker/lib/database/sqlite3.db`.
23+
/// For `Mysql`, the format is `mysql://db_user:db_user_password:port/db_name`, for
24+
/// example: `root:password@localhost:3306/torrust`.
25+
pub db_path: String,
26+
27+
/// See [`AnnouncePolicy::interval`]
28+
pub announce_interval: u32,
29+
30+
/// See [`AnnouncePolicy::interval_min`]
31+
pub min_announce_interval: u32,
32+
/// Weather the tracker is behind a reverse proxy or not.
33+
/// If the tracker is behind a reverse proxy, the `X-Forwarded-For` header
34+
/// sent from the proxy will be used to get the client's IP address.
35+
pub on_reverse_proxy: bool,
36+
/// The external IP address of the tracker. If the client is using a
37+
/// loopback IP address, this IP address will be used instead. If the peer
38+
/// is using a loopback IP address, the tracker assumes that the peer is
39+
/// in the same network as the tracker and will use the tracker's IP
40+
/// address instead.
41+
pub external_ip: Option<IpAddr>,
42+
/// Weather the tracker should collect statistics about tracker usage.
43+
/// If enabled, the tracker will collect statistics like the number of
44+
/// connections handled, the number of announce requests handled, etc.
45+
/// Refer to the [`Tracker`](https://docs.rs/torrust-tracker) for more
46+
/// information about the collected metrics.
47+
pub tracker_usage_statistics: bool,
48+
/// If enabled the tracker will persist the number of completed downloads.
49+
/// That's how many times a torrent has been downloaded completely.
50+
pub persistent_torrent_completed_stat: bool,
51+
52+
// Cleanup job configuration
53+
/// Maximum time in seconds that a peer can be inactive before being
54+
/// considered an inactive peer. If a peer is inactive for more than this
55+
/// time, it will be removed from the torrent peer list.
56+
pub max_peer_timeout: u32,
57+
/// Interval in seconds that the cleanup job will run to remove inactive
58+
/// peers from the torrent peer list.
59+
pub inactive_peer_cleanup_interval: u64,
60+
/// If enabled, the tracker will remove torrents that have no peers.
61+
/// The clean up torrent job runs every `inactive_peer_cleanup_interval`
62+
/// seconds and it removes inactive peers. Eventually, the peer list of a
63+
/// torrent could be empty and the torrent will be removed if this option is
64+
/// enabled.
65+
pub remove_peerless_torrents: bool,
66+
}
67+
68+
impl Default for Core {
69+
fn default() -> Self {
70+
let announce_policy = AnnouncePolicy::default();
71+
72+
Self {
73+
log_level: Some(LogLevel::Info),
74+
mode: TrackerMode::Public,
75+
db_driver: DatabaseDriver::Sqlite3,
76+
db_path: String::from("./storage/tracker/lib/database/sqlite3.db"),
77+
announce_interval: announce_policy.interval,
78+
min_announce_interval: announce_policy.interval_min,
79+
max_peer_timeout: 900,
80+
on_reverse_proxy: false,
81+
external_ip: Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))),
82+
tracker_usage_statistics: true,
83+
persistent_torrent_completed_stat: false,
84+
inactive_peer_cleanup_interval: 600,
85+
remove_peerless_torrents: true,
86+
}
87+
}
88+
}

packages/configuration/src/v1/health_check_api.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
2+
13
use serde::{Deserialize, Serialize};
24
use serde_with::serde_as;
35

@@ -9,13 +11,13 @@ pub struct HealthCheckApi {
911
/// The format is `ip:port`, for example `127.0.0.1:1313`. If you want to
1012
/// listen to all interfaces, use `0.0.0.0`. If you want the operating
1113
/// system to choose a random port, use port `0`.
12-
pub bind_address: String,
14+
pub bind_address: SocketAddr,
1315
}
1416

1517
impl Default for HealthCheckApi {
1618
fn default() -> Self {
1719
Self {
18-
bind_address: String::from("127.0.0.1:1313"),
20+
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 1313),
1921
}
2022
}
2123
}
+11-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
2+
13
use serde::{Deserialize, Serialize};
2-
use serde_with::{serde_as, NoneAsEmptyString};
4+
use serde_with::serde_as;
5+
6+
use crate::TslConfig;
37

48
/// Configuration for each HTTP tracker.
59
#[serde_as]
@@ -11,25 +15,21 @@ pub struct HttpTracker {
1115
/// The format is `ip:port`, for example `0.0.0.0:6969`. If you want to
1216
/// listen to all interfaces, use `0.0.0.0`. If you want the operating
1317
/// system to choose a random port, use port `0`.
14-
pub bind_address: String,
18+
pub bind_address: SocketAddr,
1519
/// Weather the HTTP tracker will use SSL or not.
1620
pub ssl_enabled: bool,
17-
/// Path to the SSL certificate file. Only used if `ssl_enabled` is `true`.
18-
#[serde_as(as = "NoneAsEmptyString")]
19-
pub ssl_cert_path: Option<String>,
20-
/// Path to the SSL key file. Only used if `ssl_enabled` is `true`.
21-
#[serde_as(as = "NoneAsEmptyString")]
22-
pub ssl_key_path: Option<String>,
21+
/// TSL config. Only used if `ssl_enabled` is true.
22+
#[serde(flatten)]
23+
pub tsl_config: TslConfig,
2324
}
2425

2526
impl Default for HttpTracker {
2627
fn default() -> Self {
2728
Self {
2829
enabled: false,
29-
bind_address: String::from("0.0.0.0:7070"),
30+
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 7070),
3031
ssl_enabled: false,
31-
ssl_cert_path: None,
32-
ssl_key_path: None,
32+
tsl_config: TslConfig::default(),
3333
}
3434
}
3535
}

0 commit comments

Comments
 (0)