feat(cli): Added a spinner to the CLI for long running commands like fetching releases

This commit is contained in:
2024-11-20 19:33:40 -07:00
parent f5631376af
commit 34157ef32f
19 changed files with 717 additions and 271 deletions
+20 -79
View File
@@ -1,20 +1,13 @@
#![warn(rust_2018_idioms)]
use std::fs::{self, File};
use std::io::BufReader;
use anyhow::Result;
use std::panic::PanicHookInfo;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::{io, panic, process};
use anyhow::anyhow;
use anyhow::Result;
use app::{log_and_print_error, AppConfig};
use clap::{
command, crate_authors, crate_description, crate_name, crate_version, CommandFactory, Parser,
};
use clap::{crate_authors, crate_description, crate_name, crate_version, CommandFactory, Parser};
use clap_complete::generate;
use colored::Colorize;
use crossterm::execute;
@@ -25,14 +18,17 @@ use log::{error, warn};
use network::NetworkTrait;
use ratatui::backend::CrosstermBackend;
use ratatui::Terminal;
use reqwest::{Certificate, Client};
use reqwest::Client;
use tokio::select;
use tokio::sync::mpsc::Receiver;
use tokio::sync::{mpsc, Mutex};
use tokio_util::sync::CancellationToken;
use utils::tail_logs;
use utils::{
build_network_client, load_config, render_spinner, start_cli_no_spinner, start_cli_with_spinner,
tail_logs,
};
use crate::app::App;
use crate::app::{App, AppConfig};
use crate::cli::Command;
use crate::event::input_event::{Events, InputEvent};
use crate::event::Key;
@@ -67,6 +63,13 @@ mod utils;
struct Cli {
#[command(subcommand)]
command: Option<Command>,
#[arg(
long,
global = true,
env = "MANAGARR_DISABLE_SPINNER",
help = "Disable the spinner (can sometimes make parsing output challenging)"
)]
disable_spinner: bool,
#[arg(
long,
global = true,
@@ -91,6 +94,7 @@ async fn main() -> Result<()> {
} else {
confy::load("managarr", "config")?
};
let spinner_disabled = args.disable_spinner;
config.validate();
let reqwest_client = build_network_client(&config);
let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
@@ -113,14 +117,10 @@ async fn main() -> Result<()> {
match args.command {
Some(command) => match command {
Command::Radarr(_) | Command::Sonarr(_) => {
config.verify_config_present_for_cli(&command);
app.lock().await.cli_mode = true;
let app_nw = Arc::clone(&app);
let mut network = Network::new(&app_nw, cancellation_token, reqwest_client);
if let Err(e) = cli::handle_command(&app, command, &mut network).await {
eprintln!("error: {}", e.to_string().red());
process::exit(1);
if spinner_disabled {
start_cli_no_spinner(config, reqwest_client, cancellation_token, app, command).await;
} else {
start_cli_with_spinner(config, reqwest_client, cancellation_token, app, command).await;
}
}
Command::Completions { shell } => {
@@ -237,65 +237,6 @@ fn panic_hook(info: &PanicHookInfo<'_>) {
.unwrap();
}
fn load_config(path: &str) -> Result<AppConfig> {
let file = File::open(path).map_err(|e| anyhow!(e))?;
let reader = BufReader::new(file);
let config = serde_yaml::from_reader(reader)?;
Ok(config)
}
fn build_network_client(config: &AppConfig) -> Client {
let mut client_builder = Client::builder()
.pool_max_idle_per_host(10)
.http2_keep_alive_interval(Duration::from_secs(5))
.tcp_keepalive(Duration::from_secs(5));
if let Some(radarr_config) = &config.radarr {
if let Some(ref cert_path) = &radarr_config.ssl_cert_path {
let cert = create_cert(cert_path, "Radarr");
client_builder = client_builder.add_root_certificate(cert);
}
}
if let Some(sonarr_config) = &config.sonarr {
if let Some(ref cert_path) = &sonarr_config.ssl_cert_path {
let cert = create_cert(cert_path, "Sonarr");
client_builder = client_builder.add_root_certificate(cert);
}
}
match client_builder.build() {
Ok(client) => client,
Err(e) => {
error!("Unable to create reqwest client: {}", e);
eprintln!("error: {}", e.to_string().red());
process::exit(1);
}
}
}
fn create_cert(cert_path: &String, servarr_name: &str) -> Certificate {
match fs::read(cert_path) {
Ok(cert) => match Certificate::from_pem(&cert) {
Ok(certificate) => certificate,
Err(_) => {
log_and_print_error(format!(
"Unable to read the specified {} SSL certificate",
servarr_name
));
process::exit(1);
}
},
Err(_) => {
log_and_print_error(format!(
"Unable to open specified {} SSL certificate",
servarr_name
));
process::exit(1);
}
}
}
#[cfg(not(debug_assertions))]
fn panic_hook(info: &PanicHookInfo<'_>) {
use human_panic::{handle_dump, metadata, print_msg};