mod appstate; mod cli; mod sharry; use std::{ process::exit, sync::{ Arc, atomic::{AtomicBool, Ordering}, }, }; use clap::Parser; use console::style; use dialoguer::{Confirm, theme::ColorfulTheme}; use log::{error, info}; use ureq::Agent; use appstate::AppState; use cli::Cli; fn main() { 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"); env_logger::init(); let args = Cli::parse(); info!("args: {args:?}"); info!("timeout: {:?}", args.get_timeout()); let agent: Agent = Agent::config_builder() .timeout_global(args.get_timeout()) .build() .into(); let mut state = AppState::try_resume(&args) .and_then(|state| { Confirm::with_theme(&ColorfulTheme::default()) .with_prompt("Previous operation found. Continue?") .default(true) .interact() .map_or(None, |b| b.then_some(state)) }) .unwrap_or_else(|| { stop.load(Ordering::SeqCst).then(|| exit(0)); match AppState::from_args(&args, &agent) { Ok(state) => { state.save().unwrap(); state } Err(e) => { if let Some(cause) = match e { ureq::Error::StatusCode(403) => Some("Alias ID"), ureq::Error::Io(_) => Some("URL"), _ => None, } { println!( "{} probably wrong: {} – {:?}", style("Error!").red(), style(cause).cyan(), style(e.to_string()).yellow() ); } else { error!("unknown error: {e}"); println!("{}", style("Unknown Error!").red()); } exit(1); } } }); info!("continuing with state: {state:?}"); loop { match state.upload_chunk(&agent, args.chunk_size * 1024 * 1024) { Err(e) => error!("error: {e:?}"), Ok(None) => { info!("all uploads done"); state.clear().unwrap(); break; } _ => (), } state.save().unwrap(); stop.load(Ordering::SeqCst).then(|| exit(0)); } }