diff --git a/Cargo.lock b/Cargo.lock index 70ac685a1..44f9db17c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -836,16 +836,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "colored" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" -dependencies = [ - "lazy_static", - "windows-sys 0.48.0", -] - [[package]] name = "concurrent-queue" version = "2.4.0" @@ -3396,6 +3386,7 @@ version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -3925,7 +3916,6 @@ dependencies = [ "axum-server", "chrono", "clap", - "colored", "config", "crossbeam-skiplist", "dashmap", diff --git a/Cargo.toml b/Cargo.toml index 94889cbf0..0e37b7ad0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,6 @@ axum-extra = { version = "0", features = ["query"] } axum-server = { version = "0", features = ["tls-rustls"] } chrono = { version = "0", default-features = false, features = ["clock"] } clap = { version = "4", features = ["derive", "env"] } -colored = "2" config = "0" crossbeam-skiplist = "0.1" dashmap = "5.5.3" @@ -62,7 +61,7 @@ ringbuf = "0" serde = { version = "1", features = ["derive"] } serde_bencode = "0" serde_bytes = "0" -serde_json = "1" +serde_json = { version = "1", features = ["preserve_order"] } serde_repr = "0" thiserror = "1" tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "signal", "sync"] } diff --git a/src/console/clients/checker/checks/health.rs b/src/console/clients/checker/checks/health.rs index 9c28da514..47eec4cbd 100644 --- a/src/console/clients/checker/checks/health.rs +++ b/src/console/clients/checker/checks/health.rs @@ -1,51 +1,49 @@ use std::time::Duration; -use colored::Colorize; use reqwest::{Client as HttpClient, Url, Url as ServiceUrl}; -use crate::console::clients::checker::console::Console; -use crate::console::clients::checker::printer::Printer; +use super::structs::{CheckerOutput, Status}; use crate::console::clients::checker::service::{CheckError, CheckResult}; -pub async fn run(health_checks: &Vec, console: &Console, check_results: &mut Vec) { - console.println("Health checks ..."); +#[allow(clippy::missing_panics_doc)] +pub async fn run(health_checks: &Vec, check_results: &mut Vec) -> Vec { + let mut health_checkers: Vec = Vec::new(); for health_check_url in health_checks { - match run_health_check(health_check_url.clone(), console).await { - Ok(()) => check_results.push(Ok(())), - Err(err) => check_results.push(Err(err)), + let mut health_checker = CheckerOutput { + url: health_check_url.to_string(), + status: Status { + code: String::new(), + message: String::new(), + }, + }; + match run_health_check(health_check_url.clone()).await { + Ok(()) => { + check_results.push(Ok(())); + health_checker.status.code = "ok".to_string(); + } + Err(err) => { + check_results.push(Err(err)); + health_checker.status.code = "error".to_string(); + health_checker.status.message = "Health API is failing.".to_string(); + } } + health_checkers.push(health_checker); } + health_checkers } -async fn run_health_check(url: Url, console: &Console) -> Result<(), CheckError> { +async fn run_health_check(url: Url) -> Result<(), CheckError> { let client = HttpClient::builder().timeout(Duration::from_secs(5)).build().unwrap(); - let colored_url = url.to_string().yellow(); - match client.get(url.clone()).send().await { Ok(response) => { if response.status().is_success() { - console.println(&format!("{} - Health API at {} is OK", "✓".green(), colored_url)); Ok(()) } else { - console.eprintln(&format!( - "{} - Health API at {} is failing: {:?}", - "✗".red(), - colored_url, - response - )); Err(CheckError::HealthCheckError { url }) } } - Err(err) => { - console.eprintln(&format!( - "{} - Health API at {} is failing: {:?}", - "✗".red(), - colored_url, - err - )); - Err(CheckError::HealthCheckError { url }) - } + Err(_) => Err(CheckError::HealthCheckError { url }), } } diff --git a/src/console/clients/checker/checks/http.rs b/src/console/clients/checker/checks/http.rs index 501696df4..e0b14b480 100644 --- a/src/console/clients/checker/checks/http.rs +++ b/src/console/clients/checker/checks/http.rs @@ -1,47 +1,56 @@ use std::str::FromStr; -use colored::Colorize; use log::debug; use reqwest::Url as ServiceUrl; use torrust_tracker_primitives::info_hash::InfoHash; use url::Url; -use crate::console::clients::checker::console::Console; -use crate::console::clients::checker::printer::Printer; +use super::structs::{CheckerOutput, Status}; use crate::console::clients::checker::service::{CheckError, CheckResult}; use crate::shared::bit_torrent::tracker::http::client::requests::announce::QueryBuilder; use crate::shared::bit_torrent::tracker::http::client::responses::announce::Announce; use crate::shared::bit_torrent::tracker::http::client::responses::scrape; use crate::shared::bit_torrent::tracker::http::client::{requests, Client}; -pub async fn run(http_trackers: &Vec, console: &Console, check_results: &mut Vec) { - console.println("HTTP trackers ..."); +#[allow(clippy::missing_panics_doc)] +pub async fn run(http_trackers: &Vec, check_results: &mut Vec) -> Vec { + let mut http_checkers: Vec = Vec::new(); for http_tracker in http_trackers { - let colored_tracker_url = http_tracker.to_string().yellow(); + let mut http_checker = CheckerOutput { + url: http_tracker.to_string(), + status: Status { + code: String::new(), + message: String::new(), + }, + }; match check_http_announce(http_tracker).await { Ok(()) => { check_results.push(Ok(())); - console.println(&format!("{} - Announce at {} is OK", "✓".green(), colored_tracker_url)); + http_checker.status.code = "ok".to_string(); } Err(err) => { check_results.push(Err(err)); - console.println(&format!("{} - Announce at {} is failing", "✗".red(), colored_tracker_url)); + http_checker.status.code = "error".to_string(); + http_checker.status.message = "Announce is failing.".to_string(); } } match check_http_scrape(http_tracker).await { Ok(()) => { check_results.push(Ok(())); - console.println(&format!("{} - Scrape at {} is OK", "✓".green(), colored_tracker_url)); + http_checker.status.code = "ok".to_string(); } Err(err) => { check_results.push(Err(err)); - console.println(&format!("{} - Scrape at {} is failing", "✗".red(), colored_tracker_url)); + http_checker.status.code = "error".to_string(); + http_checker.status.message = "Scrape is failing.".to_string(); } } + http_checkers.push(http_checker); } + http_checkers } async fn check_http_announce(tracker_url: &Url) -> Result<(), CheckError> { diff --git a/src/console/clients/checker/checks/mod.rs b/src/console/clients/checker/checks/mod.rs index 16256595e..f8b03f749 100644 --- a/src/console/clients/checker/checks/mod.rs +++ b/src/console/clients/checker/checks/mod.rs @@ -1,3 +1,4 @@ pub mod health; pub mod http; +pub mod structs; pub mod udp; diff --git a/src/console/clients/checker/checks/structs.rs b/src/console/clients/checker/checks/structs.rs new file mode 100644 index 000000000..d28e20c04 --- /dev/null +++ b/src/console/clients/checker/checks/structs.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct Status { + pub code: String, + pub message: String, +} +#[derive(Serialize, Deserialize)] +pub struct CheckerOutput { + pub url: String, + pub status: Status, +} diff --git a/src/console/clients/checker/checks/udp.rs b/src/console/clients/checker/checks/udp.rs index 47a2a1a00..48f72edf9 100644 --- a/src/console/clients/checker/checks/udp.rs +++ b/src/console/clients/checker/checks/udp.rs @@ -1,26 +1,31 @@ use std::net::SocketAddr; use aquatic_udp_protocol::{Port, TransactionId}; -use colored::Colorize; use hex_literal::hex; use log::debug; use torrust_tracker_primitives::info_hash::InfoHash; -use crate::console::clients::checker::console::Console; -use crate::console::clients::checker::printer::Printer; +use crate::console::clients::checker::checks::structs::{CheckerOutput, Status}; use crate::console::clients::checker::service::{CheckError, CheckResult}; use crate::console::clients::udp::checker; const ASSIGNED_BY_OS: u16 = 0; const RANDOM_TRANSACTION_ID: i32 = -888_840_697; -pub async fn run(udp_trackers: &Vec, console: &Console, check_results: &mut Vec) { - console.println("UDP trackers ..."); +#[allow(clippy::missing_panics_doc)] +pub async fn run(udp_trackers: &Vec, check_results: &mut Vec) -> Vec { + let mut udp_checkers: Vec = Vec::new(); for udp_tracker in udp_trackers { - debug!("UDP tracker: {:?}", udp_tracker); + let mut checker_output = CheckerOutput { + url: udp_tracker.to_string(), + status: Status { + code: String::new(), + message: String::new(), + }, + }; - let colored_tracker_url = udp_tracker.to_string().yellow(); + debug!("UDP tracker: {:?}", udp_tracker); let transaction_id = TransactionId(RANDOM_TRANSACTION_ID); @@ -32,7 +37,8 @@ pub async fn run(udp_trackers: &Vec, console: &Console, check_result check_results.push(Err(CheckError::UdpError { socket_addr: *udp_tracker, })); - console.println(&format!("{} - Can't connect to socket {}", "✗".red(), colored_tracker_url)); + checker_output.status.code = "error".to_string(); + checker_output.status.message = "Can't connect to socket.".to_string(); break; }; @@ -42,11 +48,8 @@ pub async fn run(udp_trackers: &Vec, console: &Console, check_result check_results.push(Err(CheckError::UdpError { socket_addr: *udp_tracker, })); - console.println(&format!( - "{} - Can't make tracker connection request to {}", - "✗".red(), - colored_tracker_url - )); + checker_output.status.code = "error".to_string(); + checker_output.status.message = "Can't make tracker connection request.".to_string(); break; }; @@ -60,13 +63,14 @@ pub async fn run(udp_trackers: &Vec, console: &Console, check_result .is_ok() { check_results.push(Ok(())); - console.println(&format!("{} - Announce at {} is OK", "✓".green(), colored_tracker_url)); + checker_output.status.code = "ok".to_string(); } else { let err = CheckError::UdpError { socket_addr: *udp_tracker, }; check_results.push(Err(err)); - console.println(&format!("{} - Announce at {} is failing", "✗".red(), colored_tracker_url)); + checker_output.status.code = "error".to_string(); + checker_output.status.message = "Announce is failing.".to_string(); } debug!("Send scrape request"); @@ -75,13 +79,16 @@ pub async fn run(udp_trackers: &Vec, console: &Console, check_result if (client.send_scrape_request(connection_id, transaction_id, info_hashes).await).is_ok() { check_results.push(Ok(())); - console.println(&format!("{} - Announce at {} is OK", "✓".green(), colored_tracker_url)); + checker_output.status.code = "ok".to_string(); } else { let err = CheckError::UdpError { socket_addr: *udp_tracker, }; check_results.push(Err(err)); - console.println(&format!("{} - Announce at {} is failing", "✗".red(), colored_tracker_url)); + checker_output.status.code = "error".to_string(); + checker_output.status.message = "Scrape is failing.".to_string(); } + udp_checkers.push(checker_output); } + udp_checkers } diff --git a/src/console/clients/checker/service.rs b/src/console/clients/checker/service.rs index 94eff4a88..16483e92e 100644 --- a/src/console/clients/checker/service.rs +++ b/src/console/clients/checker/service.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use reqwest::Url; -use super::checks; +use super::checks::{self}; use super::config::Configuration; use super::console::Console; use crate::console::clients::checker::printer::Printer; @@ -26,16 +26,19 @@ impl Service { /// # Errors /// /// Will return OK is all checks pass or an array with the check errors. + #[allow(clippy::missing_panics_doc)] pub async fn run_checks(&self) -> Vec { - self.console.println("Running checks for trackers ..."); - let mut check_results = vec![]; - checks::udp::run(&self.config.udp_trackers, &self.console, &mut check_results).await; + let udp_checkers = checks::udp::run(&self.config.udp_trackers, &mut check_results).await; + + let http_checkers = checks::http::run(&self.config.http_trackers, &mut check_results).await; - checks::http::run(&self.config.http_trackers, &self.console, &mut check_results).await; + let health_checkers = checks::health::run(&self.config.health_checks, &mut check_results).await; - checks::health::run(&self.config.health_checks, &self.console, &mut check_results).await; + let json_output = + serde_json::json!({ "udp_trackers": udp_checkers, "http_trackers": http_checkers, "health_checks": health_checkers }); + self.console.println(&serde_json::to_string_pretty(&json_output).unwrap()); check_results }