Skip to content

Commit

Permalink
refactor: [#589] versioning for configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed May 17, 2024
1 parent d7d6d88 commit 6c98e2b
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 282 deletions.
296 changes: 14 additions & 282 deletions src/config.rs → src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Configuration for the application.
pub mod v1;

use std::sync::Arc;
use std::{env, fs};

Expand All @@ -11,6 +13,18 @@ use tokio::sync::RwLock;
use torrust_index_located_error::{Located, LocatedError};
use url::{ParseError, Url};

pub type TorrustIndex = v1::TorrustIndex;
pub type Api = v1::api::Api;
pub type Auth = v1::auth::Auth;
pub type Database = v1::database::Database;
pub type ImageCache = v1::image_cache::ImageCache;
pub type Mail = v1::mail::Mail;
pub type Network = v1::net::Network;
pub type TrackerStatisticsImporter = v1::tracker_statistics_importer::TrackerStatisticsImporter;
pub type Tracker = v1::tracker::Tracker;
pub type Website = v1::website::Website;
pub type EmailOnSignup = v1::auth::EmailOnSignup;

/// Information required for loading config
#[derive(Debug, Default, Clone)]
pub struct Info {
Expand Down Expand Up @@ -120,21 +134,6 @@ impl From<ConfigError> for Error {
}
}

/// Information displayed to the user in the website.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Website {
/// The name of the website.
pub name: String,
}

impl Default for Website {
fn default() -> Self {
Self {
name: "Torrust".to_string(),
}
}
}

/// See `TrackerMode` in [`torrust-tracker-primitives`](https://docs.rs/torrust-tracker-primitives)
/// crate for more information.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
Expand Down Expand Up @@ -168,235 +167,11 @@ impl TrackerMode {
}
}

/// Configuration for the associated tracker.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Tracker {
/// Connection string for the tracker. For example: `udp://TRACKER_IP:6969`.
pub url: String,
/// The mode of the tracker. For example: `Public`.
/// See `TrackerMode` in [`torrust-tracker-primitives`](https://docs.rs/torrust-tracker-primitives)
/// crate for more information.
pub mode: TrackerMode,
/// The url of the tracker API. For example: `http://localhost:1212`.
pub api_url: String,
/// The token used to authenticate with the tracker API.
pub token: String,
/// The amount of seconds the token is valid.
pub token_valid_seconds: u64,
}

impl Tracker {
fn override_tracker_api_token(&mut self, tracker_api_token: &str) {
self.token = tracker_api_token.to_string();
}
}

impl Default for Tracker {
fn default() -> Self {
Self {
url: "udp://localhost:6969".to_string(),
mode: TrackerMode::default(),
api_url: "http://localhost:1212".to_string(),
token: "MyAccessToken".to_string(),
token_valid_seconds: 7_257_600,
}
}
}

/// Port number representing that the OS will choose one randomly from the available ports.
///
/// It's the port number `0`
pub const FREE_PORT: u16 = 0;

/// The the base URL for the API.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Network {
/// The port to listen on. Default to `3001`.
pub port: u16,
/// The base URL for the API. For example: `http://localhost`.
/// If not set, the base URL will be inferred from the request.
pub base_url: Option<String>,
/// TSL configuration.
pub tsl: Option<Tsl>,
}

impl Default for Network {
fn default() -> Self {
Self {
port: 3001,
base_url: None,
tsl: None,
}
}
}

/// Whether the email is required on signup or not.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum EmailOnSignup {
/// The email is required on signup.
Required,
/// The email is optional on signup.
Optional,
/// The email is not allowed on signup. It will only be ignored if provided.
None, // code-review: rename to `Ignored`?
}

impl Default for EmailOnSignup {
fn default() -> Self {
Self::Optional
}
}

/// Authentication options.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Auth {
/// Whether or not to require an email on signup.
pub email_on_signup: EmailOnSignup,
/// The minimum password length.
pub min_password_length: usize,
/// The maximum password length.
pub max_password_length: usize,
/// The secret key used to sign JWT tokens.
pub secret_key: String,
}

impl Default for Auth {
fn default() -> Self {
Self {
email_on_signup: EmailOnSignup::default(),
min_password_length: 6,
max_password_length: 64,
secret_key: "MaxVerstappenWC2021".to_string(),
}
}
}

impl Auth {
fn override_secret_key(&mut self, secret_key: &str) {
self.secret_key = secret_key.to_string();
}
}

/// Database configuration.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Database {
/// The connection string for the database. For example: `sqlite://data.db?mode=rwc`.
pub connect_url: String,
}

impl Default for Database {
fn default() -> Self {
Self {
connect_url: "sqlite://data.db?mode=rwc".to_string(),
}
}
}

/// SMTP configuration.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Mail {
/// Whether or not to enable email verification on signup.
pub email_verification_enabled: bool,
/// The email address to send emails from.
pub from: String,
/// The email address to reply to.
pub reply_to: String,
/// The username to use for SMTP authentication.
pub username: String,
/// The password to use for SMTP authentication.
pub password: String,
/// The SMTP server to use.
pub server: String,
/// The SMTP port to use.
pub port: u16,
}

impl Default for Mail {
fn default() -> Self {
Self {
email_verification_enabled: false,
from: "example@email.com".to_string(),
reply_to: "noreply@email.com".to_string(),
username: String::default(),
password: String::default(),
server: String::default(),
port: 25,
}
}
}

/// Configuration for the image proxy cache.
///
/// Users have a cache quota per period. For example: 100MB per day.
/// When users are navigating the site, they will be downloading images that are
/// embedded in the torrent description. These images will be cached in the
/// proxy. The proxy will not download new images if the user has reached the
/// quota.
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ImageCache {
/// Maximum time in seconds to wait for downloading the image form the original source.
pub max_request_timeout_ms: u64,
/// Cache size in bytes.
pub capacity: usize,
/// Maximum size in bytes for a single image.
pub entry_size_limit: usize,
/// Users have a cache quota per period. For example: 100MB per day.
/// This is the period in seconds (1 day in seconds).
pub user_quota_period_seconds: u64,
/// Users have a cache quota per period. For example: 100MB per day.
/// This is the maximum size in bytes (100MB in bytes).
pub user_quota_bytes: usize,
}

/// Core configuration for the API
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Api {
/// The default page size for torrent lists.
pub default_torrent_page_size: u8,
/// The maximum page size for torrent lists.
pub max_torrent_page_size: u8,
}

impl Default for Api {
fn default() -> Self {
Self {
default_torrent_page_size: 10,
max_torrent_page_size: 30,
}
}
}

/// Configuration for the tracker statistics importer.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TrackerStatisticsImporter {
/// The interval in seconds to get statistics from the tracker.
pub torrent_info_update_interval: u64,
/// The port the Importer API is listening on. Default to `3002`.
pub port: u16,
}

impl Default for TrackerStatisticsImporter {
fn default() -> Self {
Self {
torrent_info_update_interval: 3600,
port: 3002,
}
}
}

impl Default for ImageCache {
fn default() -> Self {
Self {
max_request_timeout_ms: 1000,
capacity: 128_000_000,
entry_size_limit: 4_000_000,
user_quota_period_seconds: 3600,
user_quota_bytes: 64_000_000,
}
}
}

#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)]
pub struct Tsl {
Expand All @@ -422,49 +197,6 @@ impl Tsl {
}
}

/// The whole configuration for the index.
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
pub struct TorrustIndex {
/// Logging level. Possible values are: `Off`, `Error`, `Warn`, `Info`,
/// `Debug` and `Trace`. Default is `Info`.
pub log_level: Option<String>,
/// The website customizable values.
pub website: Website,
/// The tracker configuration.
pub tracker: Tracker,
/// The network configuration.
pub net: Network,
/// The authentication configuration.
pub auth: Auth,
/// The database configuration.
pub database: Database,
/// The SMTP configuration.
pub mail: Mail,
/// The image proxy cache configuration.
pub image_cache: ImageCache,
/// The API configuration.
pub api: Api,
/// The tracker statistics importer job configuration.
pub tracker_statistics_importer: TrackerStatisticsImporter,
}

impl TorrustIndex {
fn override_tracker_api_token(&mut self, tracker_api_token: &str) {
self.tracker.override_tracker_api_token(tracker_api_token);
}

fn override_auth_secret_key(&mut self, auth_secret_key: &str) {
self.auth.override_secret_key(auth_secret_key);
}

pub fn remove_secrets(&mut self) {
"***".clone_into(&mut self.tracker.token);
"***".clone_into(&mut self.database.connect_url);
"***".clone_into(&mut self.mail.password);
"***".clone_into(&mut self.auth.secret_key);
}
}

/// The configuration service.
#[derive(Debug)]
pub struct Configuration {
Expand Down
19 changes: 19 additions & 0 deletions src/config/v1/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};

/// Core configuration for the API
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Api {
/// The default page size for torrent lists.
pub default_torrent_page_size: u8,
/// The maximum page size for torrent lists.
pub max_torrent_page_size: u8,
}

impl Default for Api {
fn default() -> Self {
Self {
default_torrent_page_size: 10,
max_torrent_page_size: 30,
}
}
}
Loading

0 comments on commit 6c98e2b

Please sign in to comment.