From 8780b0684d916cb9b113a4afe09f24d3f85bc6fa Mon Sep 17 00:00:00 2001 From: hinto-janaiyo Date: Thu, 27 Oct 2022 11:52:18 -0400 Subject: [PATCH] update/gupax: retry on failed bytes, add progress bar/spinner --- src/constants.rs | 2 +- src/gupax.rs | 24 +++++++++++++++---- src/main.rs | 1 + src/update.rs | 61 +++++++++++++++++++++++++++++------------------- 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 0629206..756cb42 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -56,7 +56,7 @@ pub const HUGEPAGES_1GB: bool = true; // Gupax pub const GUPAX_UPDATE: &'static str = "Check for update on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically"; pub const GUPAX_AUTO_UPDATE: &'static str = "Automatically check for updates at startup"; -pub const GUPAX_UPDATE_VIA_TOR: &'static str = "Update through the Tor network. Gupax has Tor embedded, a Tor system proxy is not required."; +pub const GUPAX_UPDATE_VIA_TOR: &'static str = "Update through the Tor network. Tor is embedded within Gupax; a Tor system proxy is not required"; pub const GUPAX_AUTO_NODE: &'static str = "Automatically ping the community Monero nodes and select the fastest at startup for P2Pool"; pub const GUPAX_ASK_BEFORE_QUIT: &'static str = "Ask before quitting if processes are still alive or if an update is in progress"; pub const GUPAX_SAVE_BEFORE_QUIT: &'static str = "Automatically save any changed settings before quitting"; diff --git a/src/gupax.rs b/src/gupax.rs index d7f117c..ec732c7 100644 --- a/src/gupax.rs +++ b/src/gupax.rs @@ -35,27 +35,41 @@ impl Gupax { // I have to pick one. This one seperates them though. let height = height/6.0; let width = width - SPACE; + let updating = *update.updating.lock().unwrap(); ui.vertical(|ui| { - ui.set_enabled(!*update.updating.lock().unwrap()); + ui.set_enabled(!updating); if ui.add_sized([width, height], egui::Button::new("Check for updates")).on_hover_text(GUPAX_UPDATE).clicked() { update.path_p2pool = state.absolute_p2pool_path.display().to_string(); update.path_xmrig = state.absolute_xmrig_path.display().to_string(); update.tor = state.update_via_tor; let u = Arc::new(Mutex::new(update.clone())); let u = Arc::clone(&u); + let u2 = Arc::new(Mutex::new(update.clone())); + let u2 = Arc::clone(&u); thread::spawn(move|| { info!("Spawning update thread..."); - let handle = Update::start(u, version); - info!("...........>"); + match Update::start(u, version) { + Err(e) => { + info!("Update | {} ... FAIL", e); + *u2.lock().unwrap().msg.lock().unwrap() = MSG_FAILED.to_string(); + *u2.lock().unwrap().updating.lock().unwrap() = false; + }, + _ => { + info!("Update ... OK"); + *u2.lock().unwrap().msg.lock().unwrap() = MSG_SUCCESS.to_string(); + *u2.lock().unwrap().prog.lock().unwrap() = 100; + *u2.lock().unwrap().updating.lock().unwrap() = false; + }, + } }); } }); ui.vertical(|ui| { - ui.set_enabled(*update.updating.lock().unwrap()); + ui.set_enabled(updating); let height = height/2.0; let msg = format!("{}{}{}{}", *update.msg.lock().unwrap(), " ... ", *update.prog.lock().unwrap(), "%"); ui.add_sized([width, height], egui::Label::new(msg)); -// let range = *update.prog.lock().unwrap() as f32 / 100.0; + if updating { ui.add_sized([width, height], egui::Spinner::new().size(height)); } ui.add_sized([width, height], egui::ProgressBar::new(*update.prog.lock().unwrap() as f32 / 100.0)); }); }); diff --git a/src/main.rs b/src/main.rs index 52d9e04..14d9e1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -582,6 +582,7 @@ impl eframe::App for App { ui.style_mut().override_text_style = Some(egui::TextStyle::Body); match self.tab { Tab::About => { + info!(""); ui.add_space(10.0); ui.vertical_centered(|ui| { // Display [Gupax] banner at max, 1/4 the available length diff --git a/src/update.rs b/src/update.rs index ff6c3f2..1259540 100644 --- a/src/update.rs +++ b/src/update.rs @@ -163,7 +163,10 @@ const MSG_TMP: &'static str = "Creating temporary directory"; const MSG_TOR: &'static str = "Creating Tor+HTTPS client"; const MSG_HTTPS: &'static str = "Creating HTTPS client"; const MSG_METADATA: &'static str = "Fetching package metadata"; -const MSG_ARCHIVE: &'static str = "Downloading packages"; +const MSG_COMPARE: &'static str = "Compare package versions"; +const MSG_DOWNLOAD: &'static str = "Downloading packages"; +pub const MSG_SUCCESS: &'static str = "Update successful"; +pub const MSG_FAILED: &'static str = "Update failed"; // These two are sequential and not async so no need for a constant message. // The package in question will be known at runtime, so that will be printed. @@ -173,9 +176,10 @@ const MSG_ARCHIVE: &'static str = "Downloading packages"; //---------------------------------------------------------------------------------------------------- Update struct/impl // Contains values needed during update // Progress bar structure: -// 10% | Create tmp directory and pkg list -// 15% | Create Tor/HTTPS client +// 0% | Create tmp directory and pkg list +// 10% | Create Tor/HTTPS client // 15% | Download Metadata (x3) +// 15% | Compare Versions (x3) // 30% | Download Archive (x3) // 15% | Extract (x3) // 15% | Upgrade (x3) @@ -273,7 +277,6 @@ impl Update { // so there will be some intermediate variables. info!("Update | Init | {} ... {}%", MSG_TMP.to_string(), *update.lock().unwrap().prog.lock().unwrap()); let tmp_dir = Self::get_tmp_dir(); - *update.lock().unwrap().prog.lock().unwrap() += 10; // Make Pkg vector let prog = update.lock().unwrap().prog.clone(); @@ -294,7 +297,8 @@ impl Update { let prog = *update.lock().unwrap().prog.lock().unwrap(); info!("Update | Init | {} ... {}%", *update.lock().unwrap().msg.lock().unwrap(), prog); let client = Self::get_client(update.lock().unwrap().tor).await?; - *update.lock().unwrap().prog.lock().unwrap() += 15; + *update.lock().unwrap().prog.lock().unwrap() += 10; + info!("Update | Init ... OK"); // Loop for metadata *update.lock().unwrap().msg.lock().unwrap() = MSG_METADATA.to_string(); @@ -322,6 +326,7 @@ impl Update { info!("Update | Metadata ... OK"); // Loop for version comparison + *update.lock().unwrap().msg.lock().unwrap() = MSG_COMPARE.to_string(); info!("Update | Compare | Starting version comparison..."); let prog = update.lock().unwrap().prog.clone(); let msg = update.lock().unwrap().msg.clone(); @@ -354,10 +359,13 @@ impl Update { } } } + *update.lock().unwrap().prog.lock().unwrap() += 5; } + info!("Update | Compare ... OK"); // Loop for download let mut handles: Vec> = vec![]; + *update.lock().unwrap().msg.lock().unwrap() = MSG_DOWNLOAD.to_string(); info!("Update | Download | Starting download..."); for pkg in vec2.iter() { // Clone data before async @@ -380,11 +388,10 @@ impl Update { link = pkg.link_prefix.to_string() + &version + &pkg.link_suffix + &version + &pkg.link_extension; } info!("Update | Download | {} ... {}", pkg.name, link); - let request = Pkg::get_request(link)?; let handle: JoinHandle<()> = tokio::spawn(async move { match client { - ClientEnum::Tor(t) => Pkg::get_bytes(name, bytes, prog, t, request).await, - ClientEnum::Https(h) => Pkg::get_bytes(name, bytes, prog, h, request).await, + ClientEnum::Tor(t) => Pkg::get_bytes(name, bytes, prog, t, link).await, + ClientEnum::Https(h) => Pkg::get_bytes(name, bytes, prog, h, link).await, }; }); handles.push(handle); @@ -411,7 +418,6 @@ impl Update { } info!("Update | Extract ... OK"); *update.lock().unwrap().updating.lock().unwrap() = false; - std::process::exit(0); Ok(()) } } @@ -491,8 +497,7 @@ impl Pkg { pub async fn get_metadata(name: Name, new_ver: Arc>, prog: Arc>, client: Client, link: String) -> Result<(), Error> where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { // Retry [3] times if version is not [v*] - let mut n = 0; - while n < 3 { + for i in 0..3 { let request = Pkg::get_request(link.clone())?; let mut response = client.request(request).await?; let body = hyper::body::to_bytes(response.body_mut()).await?; @@ -503,28 +508,36 @@ impl Pkg { info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap()); return Ok(()) } - warn!("Update | Metadata | {} metadata fetch failed, retry [{}/3]...", name, n); - n += 1; + warn!("Update | Metadata | {} failed, retry [{}/3]...", name, i); } - error!("Update | Metadata | {} metadata fetch failed", name); - Err(anyhow!("Metadata fetch failed")) + error!("Update | Metadata | {} failed", name); + Err(anyhow!("{} | Metadata fetch failed", name)) } // Takes a [Request], fills the appropriate [Pkg] // [bytes] field with the [Archive/Standalone] - pub async fn get_bytes(name: Name, bytes: Arc>, prog: Arc>, client: Client, request: Request) -> Result<(), anyhow::Error> + pub async fn get_bytes(name: Name, bytes: Arc>, prog: Arc>, client: Client, link: String) -> Result<(), anyhow::Error> where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { // GitHub sends a 302 redirect, so we must follow // the [Location] header... only if Reqwest had custom // connectors so I didn't have to manually do this... - let response = client.request(request).await?; - let request = Self::get_request(response.headers().get(hyper::header::LOCATION).unwrap().to_str()?.to_string())?; - let response = client.request(request).await?; - let body = hyper::body::to_bytes(response.into_body()).await?; - *bytes.lock().unwrap() = body; - *prog.lock().unwrap() += 10; - info!("Update | Download | {} ... {}%", name, *prog.lock().unwrap()); - Ok(()) + // Also, retry [3] times if [Bytes] == empty + for i in 0..3 { + let request = Pkg::get_request(link.clone())?; + let response = client.request(request).await?; + let request = Self::get_request(response.headers().get(hyper::header::LOCATION).unwrap().to_str()?.to_string())?; + let response = client.request(request).await?; + let body = hyper::body::to_bytes(response.into_body()).await?; + if ! body.is_empty() { + *bytes.lock().unwrap() = body; + *prog.lock().unwrap() += 10; + info!("Update | Download | {} ... {}%", name, *prog.lock().unwrap()); + return Ok(()) + } + warn!("Update | Metadata | {} download bytes are empty, retry [{}/3]...", name, i); + } + error!("Update | Download | {} failed", name); + Err(anyhow!("{} | Download failed", name)) } }