Skip to content

Commit

Permalink
Doctor command for Health check
Browse files Browse the repository at this point in the history
  • Loading branch information
Harshil-Jani committed Oct 11, 2024
1 parent 2a618b9 commit 78dfa25
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 1 deletion.
2 changes: 2 additions & 0 deletions crates/web5_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
25 changes: 25 additions & 0 deletions crates/web5_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
3 changes: 3 additions & 0 deletions crates/web5_cli/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ sudo mv /tmp/$FILENAME /usr/local/bin/web5

# Cleanup
rm /tmp/$FILENAME

# Running health check
/usr/local/bin/web5 doctor
218 changes: 218 additions & 0 deletions crates/web5_cli/src/doctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
use std::collections::HashMap;

use crate::CheckType;

pub struct HealthCheckState {
cli_version: Option<Option<String>>,
dependencies: Option<HashMap<String, bool>>,
env_vars: Option<HashMap<String, bool>>,
connectivity: Option<bool>,
basic_functionality: Option<bool>,
}

impl HealthCheckState {
fn new() -> Self {
Self {
cli_version: None,
dependencies: None,
env_vars: None,
connectivity: None,
basic_functionality: None,
}
}
}

fn check_cli_version() -> Option<Option<String>> {
Some(Some(env!("CARGO_PKG_VERSION").to_string())) // This will return the binary version.
}

fn check_dependencies() -> Option<HashMap<String, bool>> {
// 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<HashMap<String, bool>> {
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<bool> {
let client = reqwest::Client::new();
Some(client.get("https://developer.tbd.website/projects/web5/").send().await.is_ok())
}

fn test_basic_functionality() -> Option<bool> {
// 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<CheckType>) -> 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()
);
}
}
}
21 changes: 20 additions & 1 deletion crates/web5_cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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 {
Expand All @@ -25,6 +36,10 @@ enum Commands {
#[command(subcommand)]
vc_command: vcs::Commands,
},
Doctor {
#[arg(long, value_enum)]
check: Option<CheckType>, // Optional argument for individual checks
},
}

#[tokio::main]
Expand All @@ -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);
}
}
}

0 comments on commit 78dfa25

Please sign in to comment.