mod appstate; mod cachefile; mod cli; mod file; mod sharry; use std::{ process, sync::{ Arc, atomic::{AtomicBool, Ordering}, }, }; use clap::Parser; use console::style; use dialoguer::{Confirm, theme::ColorfulTheme}; use log::{error, info}; use appstate::AppState; use cli::Cli; use sharry::ClientError; fn print_error(e: &ClientError) { if let Some(cause) = match e { // known errors ClientError::ResponseStatus { actual: 403, expected: _, } => Some("Alias ID"), ClientError::StdIo(_) => Some("URL"), // unknown error _ => None, } { // handle known error info!("known error: {e:?}"); println!( "{} probably wrong: {}", style("Error!").red().bold(), style(cause).cyan(), ); println!("{}", style(e.to_string()).yellow().italic()); } else { // handle unknown error error!("unknown error: {e} ({e:?})"); println!("{}", style("Unknown Error!").red().bold()); } } fn main() { env_logger::init(); println!( "{} to {}!", style("Welcome").magenta().bold(), style("ShrUpl").yellow().bold(), ); let check_ctrlc = { let stop = Arc::new(AtomicBool::new(false)); let stop_ctrlc = stop.clone(); ctrlc::set_handler(move || { stop_ctrlc.store(true, Ordering::SeqCst); info!("stopping as soon as possible ..."); }) .expect("Error setting Ctrl-C handler"); move || { if stop.load(Ordering::SeqCst) { process::exit(255); } } }; let args = Cli::parse(); info!("args: {args:?}"); let mut state = AppState::try_resume(&args) .and_then(|state| { Confirm::with_theme(&ColorfulTheme::default()) .with_prompt("Continue previously stopped operation?") .default(true) .interact() .map_or(None, |b| b.then_some(state)) }) .unwrap_or_else(|| { check_ctrlc(); match AppState::from_args(&args) { Ok(state) => { state.save().unwrap_or_else(|e| { eprintln!( "{} Failed to save {} state: {e}", style("Warning:").red().bold(), style("ShrUpl").yellow().bold(), ); }); state } Err(e) => { print_error(&e); process::exit(1); } } }); info!("continuing with state: {state:?}"); println!( "{} uploading: {}", style("ShrUpl").yellow().bold(), style(state.file_names().join(", ")).magenta(), ); loop { match state.upload_chunk() { Err(e) => error!("error: {e:?}"), // HACK handle errors better Ok(true) => { info!("all uploads done"); state.clear().unwrap_or_else(|e| { eprintln!( "{} Failed to remove {} state: {e}", style("Warning:").red().bold(), style("ShrUpl").yellow().bold(), ); }); break; } _ => (), } state.save().unwrap_or_else(|e| { eprintln!( "{} Failed to save {} state: {e}", style("Warning:").red().bold(), style("ShrUpl").yellow().bold(), ); }); check_ctrlc(); } }