diff --git a/clients/cli/src/analytics.rs b/clients/cli/src/analytics.rs index 4e6031e..9365956 100644 --- a/clients/cli/src/analytics.rs +++ b/clients/cli/src/analytics.rs @@ -13,8 +13,11 @@ pub fn track( description: String, ws_addr_string: &str, event_properties: Value, + print_description: bool, ) { - println!("{}", description); + if print_description { + println!("{}", description); + } let firebase_app_id = analytics_id(ws_addr_string); let firebase_api_key = analytics_api_key(ws_addr_string); diff --git a/clients/cli/src/connection.rs b/clients/cli/src/connection.rs index c5e6e84..1d15375 100644 --- a/clients/cli/src/connection.rs +++ b/clients/cli/src/connection.rs @@ -1,4 +1,5 @@ use crate::analytics::track; +use colored::Colorize; use serde_json::json; use tokio::net::TcpStream; use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; @@ -25,11 +26,14 @@ pub async fn connect_to_orchestrator_with_infinite_retry( loop { match connect_to_orchestrator(ws_addr).await { Ok(client) => { + println!("\t✓ Connected to Nexus Network."); + track( "connected".into(), "Connected.".into(), ws_addr, json!({"prover_id": prover_id}), + false, ); return client; } @@ -68,7 +72,9 @@ pub async fn connect_to_orchestrator_with_limited_retry( "Connected.".into(), ws_addr, json!({"prover_id": prover_id}), + false, ); + println!("{}", "✓ Success! Connected to Nexus Network.\n".green()); return Ok(client); } Err(e) => { diff --git a/clients/cli/src/prover.rs b/clients/cli/src/prover.rs index 1c508c7..fb9b181 100644 --- a/clients/cli/src/prover.rs +++ b/clients/cli/src/prover.rs @@ -18,6 +18,7 @@ use crate::connection::{ }; use clap::Parser; +use colored::Colorize; use futures::{SinkExt, StreamExt}; use generated::pb::ClientProgramProofRequest; @@ -85,9 +86,12 @@ fn get_file_as_byte_vec(filename: &str) -> Vec { #[tokio::main] async fn main() -> Result<(), Box> { // Print the banner at startup - utils::ascii_art::print_banner(); + utils::cli_branding::print_banner(); - // Check for CLI updates periodically + println!( + "\n===== {}...\n", + "Setting up CLI configuration".bold().underline() + ); // Configure the tracing subscriber tracing_subscriber::fmt() @@ -119,27 +123,49 @@ async fn main() -> Result<(), Box> { // get or generate the prover id let prover_id = prover_id_manager::get_or_generate_prover_id(); + println!( + "\n===== {}...\n", + "Connecting to Nexus Network".bold().underline() + ); + track( "connect".into(), format!("Connecting to {}...", &ws_addr_string), &ws_addr_string, json!({"prover_id": prover_id}), + false, ); // Connect to the Orchestrator with exponential backoff let mut client = connect_to_orchestrator_with_infinite_retry(&ws_addr_string, &prover_id).await; + println!( + "\t✔ Your current prover identifier is {}", + prover_id.bright_cyan() + ); + + println!( + "\n{}", + "Success! Connection complete!\n".green().bold().underline() + ); + track( "register".into(), format!("Your current prover identifier is {}.", prover_id), &ws_addr_string, json!({"ws_addr_string": ws_addr_string, "prover_id": prover_id}), + false, ); let mut queued_proof_duration_millis = 0; let mut queued_steps_proven: i32 = 0; let mut timer_since_last_orchestrator_update = Instant::now(); + println!( + "\n===== {}...\n", + "Starting proof generation for programs".bold().underline() + ); + loop { // Create the inputs for the program use rand::Rng; // Required for .gen() methods @@ -169,6 +195,11 @@ async fn main() -> Result<(), Box> { let mut completed_fraction = 0.0; let mut steps_proven = 0; + println!( + "Program trace is {} steps. Proving {} steps starting at {}...", + total_steps, steps_to_prove, start + ); + track( "progress".into(), format!( @@ -185,6 +216,7 @@ async fn main() -> Result<(), Box> { "k": k, "prover_id": prover_id, }), + false, ); let start_time = Instant::now(); let mut progress_time = start_time; @@ -211,6 +243,12 @@ async fn main() -> Result<(), Box> { cli_prover_id: Some(prover_id.clone()), }; + // Print the proof progress in green or blue depending on the step number + println!( + "\t✓ Proved step {} at {:.2} proof cycles/sec.", + step, proof_cycles_hertz + ); + track( "progress".into(), format!( @@ -229,6 +267,7 @@ async fn main() -> Result<(), Box> { "proof_cycles_hertz": proof_cycles_hertz, "prover_id": prover_id, }), + false, ); progress_time = Instant::now(); @@ -340,7 +379,7 @@ async fn main() -> Result<(), Box> { if args.just_once { break; } else { - println!("\n\nWaiting for a new program to prove..."); + println!("\n\nWaiting for a new program to prove...\n"); } } @@ -359,6 +398,7 @@ async fn main() -> Result<(), Box> { "prover_id": &prover_id, "error": e.to_string(), }), + true, ); format!("Failed to close WebSocket connection: {}", e) })?; @@ -367,6 +407,7 @@ async fn main() -> Result<(), Box> { "Sent proof and closed connection...".into(), &ws_addr_string, json!({ "prover_id": prover_id }), + true, ); Ok(()) } diff --git a/clients/cli/src/prover_id_manager.rs b/clients/cli/src/prover_id_manager.rs index d087fb9..32a71da 100644 --- a/clients/cli/src/prover_id_manager.rs +++ b/clients/cli/src/prover_id_manager.rs @@ -1,3 +1,4 @@ +use colored::Colorize; use rand::RngCore; use random_word::Lang; use std::{fs, path::Path}; @@ -30,7 +31,13 @@ pub fn get_or_generate_prover_id() -> String { }, // 2. If file doesn't exist or can't be read: Err(e) => { - eprintln!("Could not read prover-id file: {}", e); + eprintln!( + "{}: {}", + "Warning: Could not read prover-id file" + .to_string() + .yellow(), + e + ); // if the error is because the file doesn't exist // Try to save the generated prover-id to the file @@ -46,7 +53,13 @@ pub fn get_or_generate_prover_id() -> String { } } Err(e) => { - eprintln!("Failed to create .nexus directory: {}", e); + eprintln!( + "{}: {}", + "Warning: Failed to create .nexus directory" + .to_string() + .yellow(), + e + ); } } } diff --git a/clients/cli/src/updater.rs b/clients/cli/src/updater.rs index eaa535d..3c977e2 100644 --- a/clients/cli/src/updater.rs +++ b/clients/cli/src/updater.rs @@ -23,7 +23,7 @@ pub fn spawn_auto_update_thread( updater_config: &UpdaterConfig, ) -> Result<(), Box> { println!( - "{}[auto-updater thread]{} Starting periodic CLI updates...", + "{}[auto-updater]{} Starting periodic CLI updates...", BLUE, RESET ); @@ -40,7 +40,7 @@ pub fn spawn_auto_update_thread( // Spawn the update checker thread thread::spawn(move || { println!( - "{}[auto-updater thread]{} Update checker thread started!", + "{}[auto-updater]{} Update checker thread started!", BLUE, RESET ); @@ -53,19 +53,19 @@ pub fn spawn_auto_update_thread( VersionStatus::UpdateAvailable(new_version) => { if let Err(e) = version_manager_thread.apply_update(&new_version) { eprintln!( - "{}[auto-updater thread]{} Failed to update CLI: {}", + "{}[auto-updater]{} Failed to update CLI: {}", BLUE, RESET, e ); } } // ... No update needed VersionStatus::UpToDate => { - println!("{}[auto-updater thread]{} CLI is up to date", BLUE, RESET); + println!("{}[auto-updater]{} CLI is up to date", BLUE, RESET); } }, Err(e) => { eprintln!( - "{}[auto-updater thread]{} Failed to check version: {}", + "{}[auto-updater]{} Failed to check version: {}", BLUE, RESET, e ); } @@ -73,7 +73,7 @@ pub fn spawn_auto_update_thread( // Wait for the next update check println!( - "{}[auto-updater thread]{} Next update check in {} seconds...", + "{}[auto-updater]{} Next update check in {} seconds...\n", BLUE, RESET, update_interval ); thread::sleep(Duration::from_secs(update_interval)); diff --git a/clients/cli/src/utils/ascii_art.rs b/clients/cli/src/utils/ascii_art.rs deleted file mode 100644 index 929de35..0000000 --- a/clients/cli/src/utils/ascii_art.rs +++ /dev/null @@ -1,29 +0,0 @@ -use colored::Colorize; - -pub const BANNER: &str = r#" -=========================================================================== -███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗ -████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝ -██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗ -██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║ -██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║ -╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ -=========================================================================== -"#; - -pub fn print_banner() { - println!("{}", BANNER.bright_cyan()); - println!( - "{} {}\n", - "Welcome to the".bright_white(), - "Nexus Network CLI".bright_cyan().bold() - ); -} - -pub fn print_success(message: &str) { - println!("✨ {}", message.green()); -} - -pub fn print_error(message: &str) { - println!("❌ {}", message.red()); -} diff --git a/clients/cli/src/utils/cli_branding.rs b/clients/cli/src/utils/cli_branding.rs new file mode 100644 index 0000000..4288e45 --- /dev/null +++ b/clients/cli/src/utils/cli_branding.rs @@ -0,0 +1,70 @@ +use colored::Colorize; + +pub const LOGO: &str = r#" +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%/*/(#&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%******/((((((&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@&#**********/////////((%@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@&/***************/////////////(#@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@%**********,,,,,,,,,*****////////////((#&@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@%***********,,,,,,,,,,,,***********////////(((((&@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* .********,,,,,,,,,,,,,,,,,,***********///////(((#%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* ,*,,,,,,,,,,,......,,,,,,,,,*******///(#%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* ,,,,,,............,,,,,,,,****/#####%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* ..................,,,,/#########%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* .. . ...../(((###########%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* ./((((((((##########%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* /(((((((((((##########%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* /#####(((((###########%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* /####################%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* /###########%%######%%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* ..... /########%%%%%%%%%%%%%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@* ............ (####%%%%%%%%%%%%%%%%%%%%%&@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@&,................ (%%%%%%%%%%%%%%%%%%%%%%%&@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@&/...................(%%%%%%%%%%%%%%%%%%%&@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@&#...............(%%%%%%%%%%%%%%%&@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@%,..........(%%%%%%%%%%&@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&*......(%%%%%%&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&/..(%%&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +"#; + +pub const BANNER: &str = r#" +=========================================================================== +███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗ +████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝ +██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗ +██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║ +██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║ +╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ +=========================================================================== +"#; + +pub fn print_banner() { + println!("{}", BANNER.bright_cyan()); + println!("{}", LOGO.bright_cyan()); + println!( + "{} {}\n", + "Welcome to the".bright_white(), + "Nexus Network CLI".bright_cyan().bold() + ); + println!( + "{}", + "The Nexus network is a massively-parallelized proof network for executing and proving the \x1b]8;;https://docs.nexus.org\x1b\\Nexus zkVM\x1b]8;;\x1b\\.\n\n" + .bright_white() + ); +} + +pub fn print_success(message: &str) { + println!("✨ {}", message.green()); +} + +pub fn print_error(message: &str) { + println!("❌ {}", message.red()); +} diff --git a/clients/cli/src/utils/mod.rs b/clients/cli/src/utils/mod.rs index 7720194..93de7e3 100644 --- a/clients/cli/src/utils/mod.rs +++ b/clients/cli/src/utils/mod.rs @@ -1,2 +1,2 @@ -pub mod ascii_art; +pub mod cli_branding; pub mod updater; diff --git a/clients/cli/src/utils/updater.rs b/clients/cli/src/utils/updater.rs index 5914f5a..7a92950 100644 --- a/clients/cli/src/utils/updater.rs +++ b/clients/cli/src/utils/updater.rs @@ -102,7 +102,7 @@ impl VersionManager { write_version_to_file(¤t_git_version)?; println!( - "{}[auto-updater thread]{} Wrote version to file: {}", + "{}[auto-updater]{} Wrote version to file: {}", BLUE, RESET, current_git_version ); @@ -154,7 +154,7 @@ impl VersionManager { if should_write { write_version_to_file(&version)?; println!( - "{}[auto-updater thread]{} Wrote version to file: {}", + "{}[auto-updater]{} Wrote version to file: {}", BLUE, RESET, version ); } @@ -165,7 +165,7 @@ impl VersionManager { /// Apply an update to the CLI given a new version pub fn apply_update(&self, new_version: &Version) -> Result<(), Box> { println!( - "{}[auto-updater thread]{} Using repo path: {}", + "{}[auto-updater]{} Using repo path: {}", BLUE, RESET, self.config.repo_path ); @@ -177,7 +177,7 @@ impl VersionManager { match self.config.mode { AutoUpdaterMode::Test => { println!( - "{}[auto-updater thread]{} Building version {} from local repository...", + "{}[auto-updater]{} Building version {} from local repository...", BLUE, RESET, new_version ); let build_output = Command::new("cargo") @@ -196,7 +196,7 @@ impl VersionManager { AutoUpdaterMode::Production => { if repo_path.read_dir()?.next().is_none() { println!( - "{}[auto-updater thread]{} Cloning remote repository...", + "{}[auto-updater]{} Cloning remote repository...", BLUE, RESET ); Command::new("git") @@ -204,14 +204,14 @@ impl VersionManager { .output()?; } - println!("{}[auto-updater thread]{} Fetching updates...", BLUE, RESET); + println!("{}[auto-updater]{} Fetching updates...", BLUE, RESET); Command::new("git") .args(["fetch", "--all", "--tags", "--prune"]) .current_dir(repo_path) .output()?; println!( - "{}[auto-updater thread]{} Checking out version {}...", + "{}[auto-updater]{} Checking out version {}...", BLUE, RESET, new_version ); let checkout_output = Command::new("git") @@ -228,7 +228,7 @@ impl VersionManager { } println!( - "{}[auto-updater thread]{} Building version {} from remote repository...", + "{}[auto-updater]{} Building version {} from remote repository...", BLUE, RESET, new_version ); let build_output = Command::new("cargo") @@ -255,7 +255,7 @@ impl VersionManager { let latest_version = self.get_cli_release_version(false)?; println!( - "{}[auto-updater thread]{} Current version of CLI: {} | Latest version of CLI: {}", + "{}[auto-updater]{} Current version of CLI: {} | Latest version of CLI: {}", BLUE, RESET, this_repo_version, latest_version ); @@ -314,13 +314,13 @@ pub fn restart_cli_process_with_new_version( std::fs::write(".prover.pid", child.id().to_string())?; println!( - "{}[auto-updater thread]{} Started new process with PID: {}", + "{}[auto-updater]{} Started new process with PID: {}", BLUE, RESET, child.id() ); println!( - "{}[auto-updater thread]{} Restarting with new version...", + "{}[auto-updater]{} Restarting with new version...", BLUE, RESET );