From 78dfa25143b3d4ce40e422f062afe30a573b968e Mon Sep 17 00:00:00 2001 From: Harshil-Jani Date: Sat, 12 Oct 2024 02:01:04 +0530 Subject: [PATCH] Doctor command for Health check --- crates/web5_cli/Cargo.toml | 2 + crates/web5_cli/README.md | 25 ++++ crates/web5_cli/install.sh | 3 + crates/web5_cli/src/doctor.rs | 218 ++++++++++++++++++++++++++++++++++ crates/web5_cli/src/main.rs | 21 +++- 5 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 crates/web5_cli/src/doctor.rs diff --git a/crates/web5_cli/Cargo.toml b/crates/web5_cli/Cargo.toml index bbc2514f..a8329a89 100644 --- a/crates/web5_cli/Cargo.toml +++ b/crates/web5_cli/Cargo.toml @@ -14,3 +14,5 @@ tokio = { version = "1.38.0", features = ["full"] } web5 = { path = "../web5" } url = "2.5.2" uuid = { workspace = true } +reqwest = "0.12.8" +colored = "2.1.0" diff --git a/crates/web5_cli/README.md b/crates/web5_cli/README.md index 06162c95..f69572e0 100644 --- a/crates/web5_cli/README.md +++ b/crates/web5_cli/README.md @@ -202,3 +202,28 @@ web5 vc create "alice" --portable-did $PORTABLE_DID web5 vc verify eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpkaHQ6OXFnOGgxc3Jvd2hzZHNla3hwODk4eTU0MXhndGZ4Ym1ybW5oaGdzanlobXRtOHRjb253byMwIn0.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpZCI6InVybjp2Yzp1dWlkOjlkMDhhNjAzLWMyNTMtNGQyNC05M2MzLWIzYzAwMzg2NjM5MCIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiZGlkOmRodDo5cWc4aDFzcm93aHNkc2VreHA4OTh5NTQxeGd0ZnhibXJtbmhoZ3NqeWhtdG04dGNvbndvIiwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNi0yOFQxMzoxOTo1OS45OTY2MzMrMDA6MDAiLCJleHBpcmF0aW9uRGF0ZSI6bnVsbCwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJhbGljZSJ9fSwiaXNzIjoiZGlkOmRodDo5cWc4aDFzcm93aHNkc2VreHA4OTh5NTQxeGd0ZnhibXJtbmhoZ3NqeWhtdG04dGNvbndvIiwianRpIjoidXJuOnZjOnV1aWQ6OWQwOGE2MDMtYzI1My00ZDI0LTkzYzMtYjNjMDAzODY2MzkwIiwic3ViIjoiYWxpY2UiLCJuYmYiOjE3MTk1ODA3OTksImlhdCI6MTcxOTU4MDgwMH0.PJbb9EidggoqHL3IkfcglcTNzp_obBqbZjE0M4mL2XlecdLKNusZ3i4Hm0BtnzJ0ME7zYAvdIwg4shW4U884Bg ``` + + +## Doctor Command + +The `doctor` command is a feature to check the health of the cli. This command performs a series of diagnostic checks and reports the status of various functionalities. It is useful for ensuring that the system is functioning correctly and for troubleshooting potential issues. + +### Usage + +To use the `doctor` command, simply run: + +```shell +#/bin/bash + +web5 doctor +``` + +To apply for a specific check you can run: + +```shell +#/bin/bash + +web5 doctor --check cli-version +web5 doctor --check connectivity +web5 doctor --check env-vars +``` diff --git a/crates/web5_cli/install.sh b/crates/web5_cli/install.sh index 457bd3b6..825e9f99 100755 --- a/crates/web5_cli/install.sh +++ b/crates/web5_cli/install.sh @@ -38,3 +38,6 @@ sudo mv /tmp/$FILENAME /usr/local/bin/web5 # Cleanup rm /tmp/$FILENAME + +# Running health check +/usr/local/bin/web5 doctor diff --git a/crates/web5_cli/src/doctor.rs b/crates/web5_cli/src/doctor.rs new file mode 100644 index 00000000..47afd6fc --- /dev/null +++ b/crates/web5_cli/src/doctor.rs @@ -0,0 +1,218 @@ +use std::collections::HashMap; + +use crate::CheckType; + +pub struct HealthCheckState { + cli_version: Option>, + dependencies: Option>, + env_vars: Option>, + connectivity: Option, + basic_functionality: Option, +} + +impl HealthCheckState { + fn new() -> Self { + Self { + cli_version: None, + dependencies: None, + env_vars: None, + connectivity: None, + basic_functionality: None, + } + } +} + +fn check_cli_version() -> Option> { + Some(Some(env!("CARGO_PKG_VERSION").to_string())) // This will return the binary version. +} + +fn check_dependencies() -> Option> { + // TODO : Implement this function + // DOUBT : Are we expecting to check system dependencies or dependencies in Cargo.toml ? + // If cargo dependencies then how exactly shall we check the versions ? + None +} + +fn check_environment_variables() -> Option> { + let mut env_vars = HashMap::new(); + let vars = vec!["PORTABLE_DID"]; // Add env_vars that you want to include in health checkup + + for var in vars { + let status = std::env::var(var).is_ok(); + env_vars.insert(var.to_string(), status); + } + + Some(env_vars) +} + +async fn check_connectivity() -> Option { + let client = reqwest::Client::new(); + Some(client.get("https://developer.tbd.website/projects/web5/").send().await.is_ok()) +} + +fn test_basic_functionality() -> Option { + // Supporting for actual binary + let web5_help = std::process::Command + ::new("web5") + .arg("did") + .arg("create") + .arg("dht") + .output() + .is_ok(); + + // Supporting for cargo environment just for testing purposes. + let cargo_check = std::process::Command + ::new("cargo") + .arg("run") + .arg("--") + .arg("did") + .arg("create") + .arg("dht") + .output() + .is_ok(); + + // If any one of the above commands is successful then return true. + Some(web5_help || cargo_check) +} + +pub async fn run_health_checks(check: Option) -> HealthCheckState { + let mut state = HealthCheckState::new(); + + match check { + // Run specific checks + Some(CheckType::CliVersion) => { + state.cli_version = check_cli_version(); + } + Some(CheckType::Dependencies) => { + state.dependencies = check_dependencies(); + } + Some(CheckType::EnvVars) => { + state.env_vars = check_environment_variables(); + } + Some(CheckType::Connectivity) => { + state.connectivity = check_connectivity().await; + } + Some(CheckType::BasicFunctionality) => { + state.basic_functionality = test_basic_functionality(); + } + None => { + // Run all checks + state.cli_version = check_cli_version(); + state.dependencies = check_dependencies(); + state.env_vars = check_environment_variables(); + state.connectivity = check_connectivity().await; + state.basic_functionality = test_basic_functionality(); + } + } + + state +} + +use colored::*; // Add this line at the top of your file + +pub fn print_health_check_results(state: &HealthCheckState) { + println!("{}", "Running Health Check for web5 CLI...".bold().blue()); + + // Handle CLI version + if let Some(cli_version) = &state.cli_version { + match cli_version { + Some(version) => println!("{} {}", "✔ CLI Version:".green(), version), + None => + println!( + "{} {}", + "✖ CLI Version check failed.".red(), + "Please ensure the CLI is installed correctly.".yellow() + ), + } + } + + // Handle dependencies + if let Some(dependencies) = &state.dependencies { + for (dep, status) in dependencies { + println!( + "{} {}: {}", + if *status { + "✔".green() + } else { + "✖".red() + }, + "Dependency".bold(), + dep + ); + if !status { + println!( + "{} {}", + "Remediation:".yellow(), + format!("Please install or update the dependency: {}", dep).yellow() + ); + } + } + } + + // Handle environment variables + if let Some(env_vars) = &state.env_vars { + for (var, status) in env_vars { + println!( + "{} : {}", + if *status { + "✔ Environment Variable :".green() + } else { + "✖ Missing Environment Variable :".red() + }, + if *status { + var.green() + } else { + var.red() + } + ); + if !status { + println!("{}", format!("Please set the environment variable: {}", var).yellow()); + // Example code to set the environment variable + println!("{}", format!("export {}=your_value", var).bright_yellow()); + } + } + } + + // Handle connectivity + if let Some(connectivity) = state.connectivity { + println!( + "{} {}", + if connectivity { + "✔ Connectivity:".green() + } else { + "✖ Connectivity:".red() + }, + if connectivity { + "OK".green() + } else { + "FAILED".red() + } + ); + if !connectivity { + println!("{}", "Please check your internet connection and try again.".yellow()); + } + } + + // Handle basic functionality + if let Some(basic_functionality) = state.basic_functionality { + println!( + "{} {}", + if basic_functionality { + "✔ Basic CLI Functionality:".green() + } else { + "✖ Basic CLI Functionality:".red() + }, + if basic_functionality { + "OK".green() + } else { + "FAILED".red() + } + ); + if !basic_functionality { + println!( + "{}", + "Might be a bug or your CLI have not been setup correctly. Please report on https://github.com/TBD54566975/web5-rs/issues ".yellow() + ); + } + } +} diff --git a/crates/web5_cli/src/main.rs b/crates/web5_cli/src/main.rs index a28a2215..dc4da96f 100644 --- a/crates/web5_cli/src/main.rs +++ b/crates/web5_cli/src/main.rs @@ -1,9 +1,11 @@ mod dids; +mod doctor; mod test; mod utils; mod vcs; -use clap::{Parser, Subcommand}; +use clap::{ Parser, Subcommand, ValueEnum }; +use doctor::{ print_health_check_results, run_health_checks }; #[derive(Parser, Debug)] #[command( @@ -15,6 +17,15 @@ struct Cli { command: Commands, } +#[derive(Debug, Clone, ValueEnum)] +enum CheckType { + CliVersion, + Dependencies, + EnvVars, + Connectivity, + BasicFunctionality, +} + #[derive(Subcommand, Debug)] enum Commands { Did { @@ -25,6 +36,10 @@ enum Commands { #[command(subcommand)] vc_command: vcs::Commands, }, + Doctor { + #[arg(long, value_enum)] + check: Option, // Optional argument for individual checks + }, } #[tokio::main] @@ -34,5 +49,9 @@ async fn main() { match cli.command { Commands::Did { did_command } => did_command.command().await, Commands::Vc { vc_command } => vc_command.command().await, + Commands::Doctor { check } => { + let state = run_health_checks(check).await; + print_health_check_results(&state); + } } }