Skip to content

Commit

Permalink
dev: cleanup bootstrap of services
Browse files Browse the repository at this point in the history
  • Loading branch information
da2ce7 committed Dec 30, 2023
1 parent 38d81ee commit 00c329c
Show file tree
Hide file tree
Showing 17 changed files with 233 additions and 115 deletions.
4 changes: 2 additions & 2 deletions packages/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ use config::{Config, ConfigError, File, FileFormat};
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, NoneAsEmptyString};
use thiserror::Error;
use torrust_tracker_located_error::{Located, LocatedError};
use torrust_tracker_located_error::{DynError, Located, LocatedError};
use torrust_tracker_primitives::{DatabaseDriver, TrackerMode};

/// Information required for loading config
Expand Down Expand Up @@ -289,7 +289,7 @@ impl Info {

fs::read_to_string(config_path)
.map_err(|e| Error::UnableToLoadFromConfigFile {
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
source: (Arc::new(e) as DynError).into(),

Check warning on line 292 in packages/configuration/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

packages/configuration/src/lib.rs#L292

Added line #L292 was not covered by tests
})?
.parse()
.map_err(|_e: std::convert::Infallible| Error::Infallible)?
Expand Down
4 changes: 3 additions & 1 deletion packages/located-error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ use std::error::Error;
use std::panic::Location;
use std::sync::Arc;

pub type DynError = Arc<dyn std::error::Error + Send + Sync>;

/// A generic wrapper around an error.
///
/// Where `E` is the inner error (source error).
Expand Down Expand Up @@ -96,7 +98,7 @@ where
}

#[allow(clippy::from_over_into)]
impl<'a> Into<LocatedError<'a, dyn std::error::Error + Send + Sync>> for Arc<dyn std::error::Error + Send + Sync> {
impl<'a> Into<LocatedError<'a, dyn std::error::Error + Send + Sync>> for DynError {
#[track_caller]
fn into(self) -> LocatedError<'a, dyn std::error::Error + Send + Sync> {
LocatedError {
Expand Down
15 changes: 4 additions & 11 deletions src/bootstrap/jobs/http_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use log::info;
use tokio::task::JoinHandle;
use torrust_tracker_configuration::HttpTracker;

use super::make_rust_tls;
use crate::core;
use crate::servers::http::server::{HttpServer, HttpServerLauncher};
use crate::servers::http::v1::launcher::Launcher;
Expand All @@ -39,17 +40,9 @@ pub async fn start_job(config: &HttpTracker, tracker: Arc<core::Tracker>, versio
.parse::<std::net::SocketAddr>()
.expect("Tracker API bind_address invalid.");

Check warning on line 41 in src/bootstrap/jobs/http_tracker.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/http_tracker.rs#L41

Added line #L41 was not covered by tests

let tls = if let (true, Some(cert), Some(key)) = (&config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path) {
let tls = RustlsConfig::from_pem_file(cert, key)
.await
.expect("Could not read tls cert.");
info!("Using https: cert path: {cert}.");
info!("Using https: key path: {cert}.");
Some(tls)
} else {
info!("Loading HTTP tracker without TLS.");
None
};
let tls = make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)
.await
.map(|tls| tls.expect("tls config failed"));

Check warning on line 45 in src/bootstrap/jobs/http_tracker.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/http_tracker.rs#L43-L45

Added lines #L43 - L45 were not covered by tests

match version {
Version::V1 => Some(start_v1(socket, tls, tracker.clone()).await),

Check warning on line 48 in src/bootstrap/jobs/http_tracker.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/http_tracker.rs#L48

Added line #L48 was not covered by tests
Expand Down
46 changes: 46 additions & 0 deletions src/bootstrap/jobs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,49 @@ pub mod udp_tracker;
pub struct Started {
pub address: std::net::SocketAddr,

Check warning on line 20 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L20

Added line #L20 was not covered by tests
}

pub async fn make_rust_tls(enabled: bool, cert: &Option<String>, key: &Option<String>) -> Option<Result<RustlsConfig, Error>> {
if enabled {
if let (Some(cert), Some(key)) = (cert, key) {
info!("Using https: cert path: {cert}.");
info!("Using https: key path: {cert}.");

Check warning on line 27 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L25-L27

Added lines #L25 - L27 were not covered by tests

Some(
RustlsConfig::from_pem_file(cert, key)
.await
.map_err(|err| Error::BadTlsConfig {
source: (Arc::new(err) as DynError).into(),
}),
)
} else {
Some(Err(Error::MissingTlsConfig {
location: Location::caller(),
}))

Check warning on line 39 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L29-L39

Added lines #L29 - L39 were not covered by tests
}
} else {

Check warning on line 41 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L41

Added line #L41 was not covered by tests
info!("tls not enabled");
None
}
}

use std::panic::Location;
use std::sync::Arc;

use axum_server::tls_rustls::RustlsConfig;
use log::info;
use thiserror::Error;
use torrust_tracker_located_error::{DynError, LocatedError};

/// Error returned by the Bootstrap Process.
#[derive(Error, Debug)]

Check warning on line 56 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L56

Added line #L56 was not covered by tests
pub enum Error {
/// Enabled tls but missing config.
#[error("tls config missing")]
MissingTlsConfig { location: &'static Location<'static> },

Check warning on line 60 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L60

Added line #L60 was not covered by tests

/// Unable to parse tls Config.
#[error("bad tls config: {source}")]

Check warning on line 63 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L63

Added line #L63 was not covered by tests
BadTlsConfig {
source: LocatedError<'static, dyn std::error::Error + Send + Sync>,

Check warning on line 65 in src/bootstrap/jobs/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/mod.rs#L65

Added line #L65 was not covered by tests
},
}
19 changes: 6 additions & 13 deletions src/bootstrap/jobs/tracker_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use log::info;
use tokio::task::JoinHandle;
use torrust_tracker_configuration::HttpApi;

use super::make_rust_tls;
use crate::core;
use crate::servers::apis::server::{ApiServer, Launcher};
use crate::servers::apis::Version;
Expand All @@ -54,25 +55,17 @@ pub struct ApiServerJobStarted();
///
pub async fn start_job(config: &HttpApi, tracker: Arc<core::Tracker>, version: Version) -> Option<JoinHandle<()>> {
if config.enabled {
let socket = config
let bind_to = config

Check warning on line 58 in src/bootstrap/jobs/tracker_apis.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/tracker_apis.rs#L56-L58

Added lines #L56 - L58 were not covered by tests
.bind_address
.parse::<std::net::SocketAddr>()
.expect("Tracker API bind_address invalid.");

Check warning on line 61 in src/bootstrap/jobs/tracker_apis.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/tracker_apis.rs#L61

Added line #L61 was not covered by tests

let tls = if let (true, Some(cert), Some(key)) = (&config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path) {
let tls = RustlsConfig::from_pem_file(cert, key)
.await
.expect("Could not read tls cert.");
info!("Using https: cert path: {cert}.");
info!("Using https: key path: {cert}.");
Some(tls)
} else {
info!("Loading HTTP tracker without TLS.");
None
};
let tls = make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)
.await
.map(|tls| tls.expect("tls config failed"));

Check warning on line 65 in src/bootstrap/jobs/tracker_apis.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/tracker_apis.rs#L63-L65

Added lines #L63 - L65 were not covered by tests

match version {
Version::V1 => Some(start_v1(socket, tls, tracker.clone()).await),
Version::V1 => Some(start_v1(bind_to, tls, tracker.clone()).await),

Check warning on line 68 in src/bootstrap/jobs/tracker_apis.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/jobs/tracker_apis.rs#L68

Added line #L68 was not covered by tests
}
} else {
info!("Note: Not loading Http Tracker Service, Not Enabled in Configuration.");
Expand Down
4 changes: 2 additions & 2 deletions src/core/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use torrust_tracker_located_error::LocatedError;
use torrust_tracker_located_error::{DynError, LocatedError};

use crate::shared::bit_torrent::common::AUTH_KEY_LENGTH;
use crate::shared::clock::{convert_from_timestamp_to_datetime_utc, Current, DurationSinceUnixEpoch, Time, TimeNow};
Expand Down Expand Up @@ -185,7 +185,7 @@ pub enum Error {
impl From<r2d2_sqlite::rusqlite::Error> for Error {
fn from(e: r2d2_sqlite::rusqlite::Error) -> Self {
Error::KeyVerificationError {
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
source: (Arc::new(e) as DynError).into(),

Check warning on line 188 in src/core/auth.rs

View check run for this annotation

Codecov / codecov/patch

src/core/auth.rs#L188

Added line #L188 was not covered by tests
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/core/databases/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::panic::Location;
use std::sync::Arc;

use r2d2_mysql::mysql::UrlError;
use torrust_tracker_located_error::{Located, LocatedError};
use torrust_tracker_located_error::{DynError, Located, LocatedError};
use torrust_tracker_primitives::DatabaseDriver;

#[derive(thiserror::Error, Debug, Clone)]
Expand Down Expand Up @@ -59,11 +59,11 @@ impl From<r2d2_sqlite::rusqlite::Error> for Error {
fn from(err: r2d2_sqlite::rusqlite::Error) -> Self {
match err {
r2d2_sqlite::rusqlite::Error::QueryReturnedNoRows => Error::QueryReturnedNoRows {
source: (Arc::new(err) as Arc<dyn std::error::Error + Send + Sync>).into(),
source: (Arc::new(err) as DynError).into(),

Check warning on line 62 in src/core/databases/error.rs

View check run for this annotation

Codecov / codecov/patch

src/core/databases/error.rs#L62

Added line #L62 was not covered by tests
driver: DatabaseDriver::Sqlite3,
},
_ => Error::InvalidQuery {
source: (Arc::new(err) as Arc<dyn std::error::Error + Send + Sync>).into(),
source: (Arc::new(err) as DynError).into(),
driver: DatabaseDriver::Sqlite3,
},
}
Expand All @@ -73,7 +73,7 @@ impl From<r2d2_sqlite::rusqlite::Error> for Error {
impl From<r2d2_mysql::mysql::Error> for Error {
#[track_caller]
fn from(err: r2d2_mysql::mysql::Error) -> Self {
let e: Arc<dyn std::error::Error + Send + Sync> = Arc::new(err);
let e: DynError = Arc::new(err);

Check warning on line 76 in src/core/databases/error.rs

View check run for this annotation

Codecov / codecov/patch

src/core/databases/error.rs#L76

Added line #L76 was not covered by tests
Error::InvalidQuery {
source: e.into(),
driver: DatabaseDriver::MySQL,
Expand Down
3 changes: 2 additions & 1 deletion src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ use std::time::Duration;
use futures::future::join_all;
use tokio::sync::mpsc::error::SendError;
use torrust_tracker_configuration::Configuration;
use torrust_tracker_located_error::DynError;
use torrust_tracker_primitives::TrackerMode;

use self::auth::Key;
Expand Down Expand Up @@ -933,7 +934,7 @@ impl Tracker {
if let Err(e) = self.verify_auth_key(key).await {
return Err(Error::PeerKeyNotValid {
key: key.clone(),
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
source: (Arc::new(e) as DynError).into(),

Check warning on line 937 in src/core/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/core/mod.rs#L937

Added line #L937 was not covered by tests
});
}
}
Expand Down
59 changes: 25 additions & 34 deletions src/servers/apis/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use tokio::sync::oneshot::{Receiver, Sender};
use super::routes::router;
use crate::bootstrap::jobs::Started;
use crate::core::Tracker;
use crate::servers::signals::{shutdown_signal_with_message, Halted};
use crate::servers::signals::{graceful_shutdown, Halted};

/// Errors that can occur when starting or stopping the API server.
#[derive(Debug)]
Expand Down Expand Up @@ -97,10 +97,7 @@ impl ApiServer<Stopped> {
let launcher = self.state.launcher;

let task = tokio::spawn(async move {
let server = launcher.start(tracker, tx_start, rx_halt);

server.await;

launcher.start(tracker, tx_start, rx_halt).await;
launcher
});

Expand Down Expand Up @@ -153,30 +150,30 @@ impl Launcher {
/// Will panic if unable to bind to the socket, or unable to get the address of the bound socket.
/// Will also panic if unable to send message regarding the bound socket address.
pub fn start(&self, tracker: Arc<Tracker>, tx_start: Sender<Started>, rx_halt: Receiver<Halted>) -> BoxFuture<'static, ()> {
let app = router(tracker);
let router = router(tracker);
let socket = std::net::TcpListener::bind(self.bind_to).expect("Could not bind tcp_listener to address.");
let address = socket.local_addr().expect("Could not get local_addr from tcp_listener.");

let handle = Handle::new();
let handel_cloned = handle.clone();

tokio::task::spawn(async move {
shutdown_signal_with_message(rx_halt, format!("Halting API Service Bound to Socket: {address}")).await;
handel_cloned.graceful_shutdown(None);
});
tokio::task::spawn(graceful_shutdown(
handle.clone(),
rx_halt,
format!("shutting down http server on socket address: {address}"),
));

let tls = self.tls.clone();

let running = Box::pin(async {
match tls {
Some(tls) => axum_server::from_tcp_rustls(socket, tls)
.handle(handle)
.serve(app.into_make_service_with_connect_info::<std::net::SocketAddr>())
.serve(router.into_make_service_with_connect_info::<std::net::SocketAddr>())
.await
.expect("Axum server crashed."),

Check warning on line 173 in src/servers/apis/server.rs

View check run for this annotation

Codecov / codecov/patch

src/servers/apis/server.rs#L169-L173

Added lines #L169 - L173 were not covered by tests
None => axum_server::from_tcp(socket)
.handle(handle)
.serve(app.into_make_service_with_connect_info::<std::net::SocketAddr>())
.serve(router.into_make_service_with_connect_info::<std::net::SocketAddr>())
.await
.expect("Axum server crashed."),
}
Expand All @@ -194,37 +191,31 @@ impl Launcher {
mod tests {
use std::sync::Arc;

use torrust_tracker_configuration::Configuration;
use torrust_tracker_test_helpers::configuration;
use torrust_tracker_test_helpers::configuration::ephemeral_mode_public;

use crate::core;
use crate::core::statistics;
use crate::bootstrap::app::initialize_with_configuration;
use crate::bootstrap::jobs::make_rust_tls;
use crate::servers::apis::server::{ApiServer, Launcher};

fn tracker_configuration() -> Arc<Configuration> {
Arc::new(configuration::ephemeral())
}

#[tokio::test]
async fn it_should_be_able_to_start_from_stopped_state_and_then_stop_again() {
let cfg = tracker_configuration();

let tracker = Arc::new(core::Tracker::new(cfg.clone(), None, statistics::Repo::new()).unwrap());
async fn it_should_be_able_to_start_and_stop() {
let cfg = Arc::new(ephemeral_mode_public());
let tracker = initialize_with_configuration(&cfg);
let config = &cfg.http_trackers[0];

let bind_to = cfg
.http_api
let bind_to = config
.bind_address
.parse::<std::net::SocketAddr>()
.expect("Tracker API bind_address invalid.");

let stopped_api_server = ApiServer::new(Launcher::new(bind_to, None));

let running_api_server_result = stopped_api_server.start(tracker).await;

assert!(running_api_server_result.is_ok());
let tls = make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)
.await
.map(|tls| tls.expect("tls config failed"));

let running_api_server = running_api_server_result.unwrap();
let stopped = ApiServer::new(Launcher::new(bind_to, tls));
let started = stopped.start(tracker).await.expect("it should start the server");
let stopped = started.stop().await.expect("it should stop the server");

assert!(running_api_server.stop().await.is_ok());
assert_eq!(stopped.state.launcher.bind_to, bind_to);
}
}
34 changes: 34 additions & 0 deletions src/servers/http/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,37 @@ impl<I: HttpServerLauncher> HttpServer<Running<I>> {
})
}
}

#[cfg(test)]
mod tests {
use std::sync::Arc;

use torrust_tracker_test_helpers::configuration::ephemeral_mode_public;

use crate::bootstrap::app::initialize_with_configuration;
use crate::bootstrap::jobs::make_rust_tls;
use crate::servers::http::server::{HttpServer, HttpServerLauncher};
use crate::servers::http::v1::launcher::Launcher;

#[tokio::test]
async fn it_should_be_able_to_start_and_stop() {
let cfg = Arc::new(ephemeral_mode_public());
let tracker = initialize_with_configuration(&cfg);
let config = &cfg.http_trackers[0];

let bind_to = config
.bind_address
.parse::<std::net::SocketAddr>()
.expect("Tracker API bind_address invalid.");

let tls = make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)
.await
.map(|tls| tls.expect("tls config failed"));

let stopped = HttpServer::new(Launcher::new(bind_to, tls));
let started = stopped.start(tracker).await.expect("it should start the server");
let stopped = started.stop().await.expect("it should stop the server");

assert_eq!(stopped.state.launcher.bind_to, bind_to);
}
}
Loading

0 comments on commit 00c329c

Please sign in to comment.