From 9baedfbf467cc164a8749853ec1f3ebb50eda2bc Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 29 May 2023 12:51:59 +0100 Subject: [PATCH] docs: [#166] installation and configuration --- project-words.txt | 1 + src/bin/import_tracker_statistics.rs | 3 +- src/config.rs | 92 ++++++- .../commands/import_tracker_statistics.rs | 5 +- src/lib.rs | 238 +++++++++++++++++- src/services/about.rs | 1 - src/services/authentication.rs | 1 + src/services/mod.rs | 1 + src/services/settings.rs | 1 + src/services/torrent.rs | 1 + src/services/user.rs | 2 +- .../from_v1_0_0_to_v2_0_0/upgrader.rs | 1 - 12 files changed, 334 insertions(+), 13 deletions(-) diff --git a/project-words.txt b/project-words.txt index 5ca22cd6..b770bb51 100644 --- a/project-words.txt +++ b/project-words.txt @@ -30,6 +30,7 @@ leechers Leechers LEECHERS lettre +libsqlite luckythelab mailcatcher mandelbrotset diff --git a/src/bin/import_tracker_statistics.rs b/src/bin/import_tracker_statistics.rs index 3f8456c4..0b7f7288 100644 --- a/src/bin/import_tracker_statistics.rs +++ b/src/bin/import_tracker_statistics.rs @@ -1,7 +1,8 @@ //! Import Tracker Statistics command. +//! //! It imports the number of seeders and leechers for all torrent from the linked tracker. +//! //! You can execute it with: `cargo run --bin import_tracker_statistics` - use torrust_index_backend::console::commands::import_tracker_statistics::run_importer; #[actix_web::main] diff --git a/src/config.rs b/src/config.rs index becab7e1..8348edd3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +//! Configuration for the application. use std::path::Path; use std::{env, fs}; @@ -6,8 +7,10 @@ use log::warn; use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; +/// Information displayed to the user in the website. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Website { + /// The name of the website. pub name: String, } @@ -19,12 +22,18 @@ impl Default for Website { } } +/// See `TrackerMode` in [`torrust-tracker-primitives`](https://docs.rs/torrust-tracker-primitives) +/// crate for more information. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum TrackerMode { // todo: use https://crates.io/crates/torrust-tracker-primitives + /// Will track every new info hash and serve every peer. Public, + /// Will only serve authenticated peers. Private, + /// Will only track whitelisted info hashes. Whitelisted, + /// Will only track whitelisted info hashes and serve authenticated peers. PrivateWhitelisted, } @@ -34,12 +43,20 @@ impl Default for TrackerMode { } } +/// Configuration for the associated tracker. #[derive(Debug, Clone, Serialize, Deserialize)] 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, } @@ -55,12 +72,18 @@ impl Default for Tracker { } } -/// Port 0 means that the OS will choose a random free port. +/// 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)] pub struct Network { + /// The port to listen on. Default to `3000`. 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, } @@ -73,11 +96,15 @@ impl Default for Network { } } +/// Whether the email is required on signup or not. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum EmailOnSignup { + /// The email is required on signup. Required, + /// The email is optional on signup. Optional, - None, + /// The email is not allowed on signup. It will only be ignored if provided. + None, // code-review: rename to `Ignored`? } impl Default for EmailOnSignup { @@ -86,11 +113,16 @@ impl Default for EmailOnSignup { } } +/// Authentication options. #[derive(Debug, Clone, Serialize, Deserialize)] 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, } @@ -105,8 +137,10 @@ impl Default for Auth { } } +/// Database configuration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Database { + /// The connection string for the database. For example: `sqlite://data.db?mode=rwc`. pub connect_url: String, } @@ -118,14 +152,22 @@ impl Default for Database { } } +/// SMTP configuration. #[derive(Debug, Clone, Serialize, Deserialize)] 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, } @@ -143,19 +185,36 @@ impl Default for Mail { } } +/// 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)] 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)] 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, } @@ -168,8 +227,10 @@ impl Default for Api { } } +/// Configuration for the tracker statistics importer. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TrackerStatisticsImporter { + /// The interval in seconds to get statistics from the tracker. pub torrent_info_update_interval: u64, } @@ -193,22 +254,36 @@ impl Default for ImageCache { } } +/// The whole configuration for the backend. #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct TorrustBackend { + /// 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, } +/// The configuration service. #[derive(Debug)] pub struct Configuration { + /// The state of the configuration. pub settings: RwLock, + /// The path to the configuration file. This is `None` if the configuration + /// was loaded from the environment. pub config_path: Option, } @@ -237,13 +312,14 @@ impl Configuration { if Path::new(config_path).exists() { config = config_builder.add_source(File::with_name(config_path)).build()?; } else { - warn!("No config file found."); - warn!("Creating config file.."); + warn!("No config file found. Creating default config file ..."); + let config = Configuration::default(); let _ = config.save_to_file(config_path).await; - return Err(ConfigError::Message( - "Please edit the config.TOML in the root folder and restart the tracker.".to_string(), - )); + + return Err(ConfigError::Message(format!( + "No config file found. Created default config file in {config_path}. Edit the file and start the application." + ))); } let torrust_config: TorrustBackend = match config.try_deserialize() { @@ -345,6 +421,8 @@ impl Configuration { } } +/// The public backend configuration. +/// There is an endpoint to get this configuration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ConfigurationPublic { website_name: String, diff --git a/src/console/commands/import_tracker_statistics.rs b/src/console/commands/import_tracker_statistics.rs index a322eef2..39cc5a9f 100644 --- a/src/console/commands/import_tracker_statistics.rs +++ b/src/console/commands/import_tracker_statistics.rs @@ -1,5 +1,8 @@ //! It imports statistics for all torrents from the linked tracker. - +//! +//! It imports the number of seeders and leechers for all torrent from the linked tracker. +//! +//! You can execute it with: `cargo run --bin import_tracker_statistics` use std::env; use std::sync::Arc; diff --git a/src/lib.rs b/src/lib.rs index c66d8e73..2f5a347d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,11 +2,247 @@ //! //! This is the backend API for [Torrust Tracker Index](https://github.com/torrust/torrust-index). //! -//! It is written in Rust and uses the actix-web framework. It is designed to be +//! It is written in Rust and uses the [actix-web](https://actix.rs/) framework. It is designed to be //! used with by the [Torrust Tracker Index Frontend](https://github.com/torrust/torrust-index-frontend). //! //! If you are looking for information on how to use the API, please see the //! [API v1](crate::web::api::v1) section of the documentation. +//! +//! # Table of contents +//! +//! - [Features](#features) +//! - [Services](#services) +//! - [Installation](#installation) +//! - [Minimum requirements](#minimum-requirements) +//! - [Prerequisites](#prerequisites) +//! - [Install from sources](#install-from-sources) +//! - [Run with docker](#run-with-docker) +//! - [Development](#development) +//! - [Configuration](#configuration) +//! - [Usage](#usage) +//! - [Contributing](#contributing) +//! - [Documentation](#documentation) +//! +//! # Features +//! +//! - Torrent categories +//! - Image proxy cache for torrent descriptions +//! - User registration and authentication +//! - DB Support for `SQLite` and `MySQl` +//! +//! # Services +//! +//! From the end-user perspective the Torrust Tracker exposes three different services. +//! +//! - A REST [API](crate::web::api::v1) +//! +//! From the administrator perspective, the Torrust Index Backend exposes: +//! +//! - A console command to update torrents statistics from the associated tracker +//! - A console command to upgrade the database schema from version `1.0.0` to `2.0.0` +//! +//! # Installation +//! +//! ## Minimum requirements +//! +//! - Rust Stable `1.68` +//! +//! ## Prerequisites +//! +//! In order the run the backend you will need a running torrust tracker. In the +//! configuration you need to fill the `backend` section with the following: +//! +//! ```toml +//! [tracker] +//! url = "udp://localhost:6969" +//! mode = "Public" +//! api_url = "http://localhost:1212" +//! token = "MyAccessToken" +//! token_valid_seconds = 7257600 +//! ``` +//! +//! Refer to the [`config::tracker`](crate::config::Tracker) documentation for more information. +//! +//! You can follow the tracker installation instructions [here](https://docs.rs/torrust-tracker) +//! or you can use the docker to run both the tracker and the backend. Refer to the +//! [Run with docker](#run-with-docker) section for more information. +//! +//! If you are using `SQLite3` as database driver, you will need to install the +//! following dependency: +//! +//! ```text +//! sudo apt-get install libsqlite3-dev +//! ``` +//! +//! > **NOTICE**: those are the commands for `Ubuntu`. If you are using a +//! different OS, you will need to install the equivalent packages. Please +//! refer to the documentation of your OS. +//! +//! With the default configuration you will need to create the `storage` directory: +//! +//! ```text +//! storage/ +//! └── database +//!    └── data.db +//! ``` +//! +//! The default configuration expects a directory `./storage/database` to be writable by the app process. +//! +//! By default the backend uses `SQLite` and the database file name `data.db`. +//! +//! ## Install from sources +//! +//! ```text +//! git clone git@github.com:torrust/torrust-index-backend.git \ +//! && cd torrust-index-backend \ +//! && cargo build --release \ +//! && mkdir -p ./storage/database +//! ``` +//! +//! Then you can run it with: `./target/release/main` +//! +//! ## Run with docker +//! +//! You can run the backend with a pre-built docker image: +//! +//! ```text +//! mkdir -p ./storage/database \ +//! && export TORRUST_IDX_BACK_USER_UID=1000 \ +//! && docker run -it \ +//! --user="$TORRUST_IDX_BACK_USER_UID" \ +//! --publish 3000:3000/tcp \ +//! --volume "$(pwd)/storage":"/app/storage" \ +//! torrust/index-backend +//! ``` +//! +//! For more information about using docker visit the [tracker docker documentation](https://github.com/torrust/torrust-index-backend/tree/develop/docker). +//! +//! ## Development +//! +//! We are using the [The Rust SQL Toolkit](https://github.com/launchbadge/sqlx) +//! [(sqlx)](https://github.com/launchbadge/sqlx) for database migrations. +//! +//! You can install it with: +//! +//! ```text +//! cargo install sqlx-cli +//! ``` +//! +//! To initialize the database run: +//! +//! ```text +//! echo "DATABASE_URL=sqlite://data.db?mode=rwc" > .env +//! sqlx db setup +//! ``` +//! +//! The `sqlx db setup` command will create the database specified in your +//! `DATABASE_URL` and run any pending migrations. +//! +//! > **WARNING**: The `.env` file is also used by docker-compose. +//! +//! > **NOTICE**: Refer to the [sqlx-cli](https://github.com/launchbadge/sqlx/tree/main/sqlx-cli) +//! documentation for other commands to create new migrations or run them. +//! +//! > **NOTICE**: You can run the backend with [tmux](https://github.com/tmux/tmux/wiki) with `tmux new -s torrust-index-backend`. +//! +//! # Configuration +//! In order to run the backend you need to provide the configuration. If you run the backend without providing the configuration, +//! the tracker will generate the default configuration the first time you run it. It will generate a `config.toml` file with +//! in the root directory. +//! +//! The default configuration is: +//! +//! ```toml +//! [website] +//! name = "Torrust" +//! +//! [tracker] +//! url = "udp://localhost:6969" +//! mode = "Public" +//! api_url = "http://localhost:1212" +//! token = "MyAccessToken" +//! token_valid_seconds = 7257600 +//! +//! [net] +//! port = 3000 +//! +//! [auth] +//! email_on_signup = "Optional" +//! min_password_length = 6 +//! max_password_length = 64 +//! secret_key = "MaxVerstappenWC2021" +//! +//! [database] +//! connect_url = "sqlite://data.db?mode=rwc" +//! +//! [mail] +//! email_verification_enabled = false +//! from = "example@email.com" +//! reply_to = "noreply@email.com" +//! username = "" +//! password = "" +//! server = "" +//! port = 25 +//! +//! [image_cache] +//! max_request_timeout_ms = 1000 +//! capacity = 128000000 +//! entry_size_limit = 4000000 +//! user_quota_period_seconds = 3600 +//! user_quota_bytes = 64000000 +//! +//! [api] +//! default_torrent_page_size = 10 +//! max_torrent_page_size = 30 +//! +//! [tracker_statistics_importer] +//! torrent_info_update_interval = 3600 +//! ``` +//! +//! For more information about configuration you can visit the documentation for the [`config`](crate::config) module. +//! +//! Alternatively to the `config.toml` file you can use one environment variable `TORRUST_IDX_BACK_CONFIG` to pass the configuration to the tracker: +//! +//! ```text +//! TORRUST_IDX_BACK_CONFIG=$(cat config.toml) +//! cargo run +//! ``` +//! +//! In the previous example you are just setting the env var with the contents of the `config.toml` file. +//! +//! The env var contains the same data as the `config.toml`. It's particularly useful in you are [running the backend with docker](https://github.com/torrust/torrust-index-backend/tree/develop/docker). +//! +//! > **NOTICE**: The `TORRUST_IDX_BACK_CONFIG` env var has priority over the `config.toml` file. +//! +//! > **NOTICE**: You can also change the location for the configuration file with the `TORRUST_IDX_BACK_CONFIG_PATH` env var. +//! +//! # Usage +//! +//! Running the tracker with the default configuration will expose the REST API on port 3000: +//! +//! You can also run console commands: +//! +//! - [`Import tracker statistics`](crate::console::commands::import_tracker_statistics). +//! - [`Upgrade app from version 1.0.0 to 2.0.0`](crate::upgrades::from_v1_0_0_to_v2_0_0::upgrader). +//! +//! Refer to the documentation of each command for more information. +//! +//! # Contributing +//! +//! If you want to contribute to this documentation you can: +//! +//! - [Open a new discussion](https://github.com/torrust/torrust-index-backend/discussions) +//! - [Open a new issue](https://github.com/torrust/torrust-index-backend/issues). +//! - [Open a new pull request](https://github.com/torrust/torrust-index-backend/pulls). +//! +//! # Documentation +//! +//! You can find this documentation on [docs.rs](https://docs.rs/torrust-index-backend/). +//! +//! If you want to contribute to this documentation you can [open a new pull request](https://github.com/torrust/torrust-index-backend/pulls). +//! +//! In addition to the production code documentation you can find a lot of +//! examples in the [tests](https://github.com/torrust/torrust-index-backend/tree/develop/tests/e2e/contexts) directory. pub mod app; pub mod auth; pub mod bootstrap; diff --git a/src/services/about.rs b/src/services/about.rs index 53840421..b4e52a2a 100644 --- a/src/services/about.rs +++ b/src/services/about.rs @@ -1,5 +1,4 @@ //! Templates for "about" static pages. - use crate::routes::API_VERSION; #[must_use] diff --git a/src/services/authentication.rs b/src/services/authentication.rs index 5f792c87..c872e1e1 100644 --- a/src/services/authentication.rs +++ b/src/services/authentication.rs @@ -1,3 +1,4 @@ +//! Authentication services. use std::sync::Arc; use argon2::{Argon2, PasswordHash, PasswordVerifier}; diff --git a/src/services/mod.rs b/src/services/mod.rs index e298313e..79693c9c 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1,3 +1,4 @@ +//! App services. pub mod about; pub mod authentication; pub mod category; diff --git a/src/services/settings.rs b/src/services/settings.rs index f9aa0350..14ce5240 100644 --- a/src/services/settings.rs +++ b/src/services/settings.rs @@ -1,3 +1,4 @@ +//! Settings service. use std::sync::Arc; use super::user::DbUserRepository; diff --git a/src/services/torrent.rs b/src/services/torrent.rs index 7c18d6d2..c89df12f 100644 --- a/src/services/torrent.rs +++ b/src/services/torrent.rs @@ -1,3 +1,4 @@ +//! Torrent service. use std::sync::Arc; use serde_derive::Deserialize; diff --git a/src/services/user.rs b/src/services/user.rs index fb5c82f6..10a42b60 100644 --- a/src/services/user.rs +++ b/src/services/user.rs @@ -1,4 +1,4 @@ -//! User repository. +//! User services. use std::sync::Arc; use argon2::password_hash::SaltString; diff --git a/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs b/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs index d724ffb7..b866dfa6 100644 --- a/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs +++ b/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs @@ -10,7 +10,6 @@ //! //! - In v2, the table `torrust_user_profiles` contains two new fields: `bio` and `avatar`. //! Empty string is used as default value. - use std::env; use std::time::SystemTime;