diff --git a/src/about.rs b/src/about.rs index d5416b0..445d917 100644 --- a/src/about.rs +++ b/src/about.rs @@ -24,7 +24,7 @@ pub struct About { } impl About { - pub fn show(app: &mut App, ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(app: &mut App, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) { ui.add_space(10.0); ui.vertical_centered(|ui| { let space = ui.available_height()/2.2; diff --git a/src/constants.rs b/src/constants.rs index 2efa9d4..0629206 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -26,6 +26,12 @@ pub const P2POOL_BASE_ARGS: &'static str = ""; pub const XMRIG_BASE_ARGS: &'static str = "--http-host=127.0.0.1 --http-port=18088 --algo=rx/0 --coin=Monero --randomx-cache-qos"; pub const HORIZONTAL: &'static str = "--------------------------------------------"; +// This is the typical space added when using +// [ui.separator()] or [ui.group()] +// Used for subtracting the width/height so +// things actually line up. +pub const SPACE: f32 = 10.0; + // OS specific #[cfg(target_os = "windows")] pub const OS: &'static str = " Windows"; @@ -48,10 +54,11 @@ pub const HUGEPAGES_1GB: bool = true; // Tooltips // Gupax -pub const GUPAX_UPDATE: &'static str = "Update Gupax, P2Pool, and XMRig via GitHub's API"; +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_AUTO_NODE: &'static str = "Automatically ping the community Monero nodes and select the fastest at startup"; -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_UPDATE_VIA_TOR: &'static str = "Update through the Tor network. Gupax has Tor embedded, 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"; pub const GUPAX_PATH_P2POOL: &'static str = "The location of the P2Pool binary, both absolute and relative paths are accepted"; pub const GUPAX_PATH_XMRIG: &'static str = "The location of the XMRig binary, both absolute and relative paths are accepted"; diff --git a/src/gupax.rs b/src/gupax.rs index 6ed374f..d7f117c 100644 --- a/src/gupax.rs +++ b/src/gupax.rs @@ -19,43 +19,69 @@ use std::path::Path; use crate::App; use egui::WidgetType::Button; use crate::constants::*; -use crate::state::Gupax; +use crate::state::{Gupax,Version}; use crate::update::*; +use std::thread; +use std::sync::{Arc,Mutex}; +use log::*; impl Gupax { - pub fn show(state: &mut Gupax, ctx: &egui::Context, ui: &mut egui::Ui) { - let height = ui.available_height(); - let width = ui.available_width(); - let half_height = height / 6.0; - let half_width = width / 2.0; + pub fn show(state: &mut Gupax, width: f32, height: f32, update: &mut Update, version: Version, ctx: &egui::Context, ui: &mut egui::Ui) { + // Update button + Progress bar + ui.group(|ui| { + // These are in unnecessary [ui.vertical()]'s + // because I need to use [ui.set_enabled]s, but I can't + // find a way to use a [ui.xxx()] with [ui.add_sized()]. + // I have to pick one. This one seperates them though. + let height = height/6.0; + let width = width - SPACE; + ui.vertical(|ui| { + ui.set_enabled(!*update.updating.lock().unwrap()); + 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); + thread::spawn(move|| { + info!("Spawning update thread..."); + let handle = Update::start(u, version); + info!("...........>"); + }); + } + }); + ui.vertical(|ui| { + ui.set_enabled(*update.updating.lock().unwrap()); + 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; + ui.add_sized([width, height], egui::ProgressBar::new(*update.prog.lock().unwrap() as f32 / 100.0)); + }); + }); ui.horizontal(|ui| { ui.group(|ui| { - ui.vertical(|ui| { - ui.add_sized([half_width - 8.0, half_height], egui::Button::new("Check for updates")).on_hover_text(GUPAX_UPDATE); - ui.set_enabled(false); - ui.add_sized([half_width - 8.0, half_height], egui::Button::new("Upgrade")).on_hover_text("asdf"); - }); - }); - - ui.group(|ui| { + let width = (width - SPACE*10.0)/5.0; + let height = height/2.0; let mut style = (*ctx.style()).clone(); - style.spacing.icon_width_inner = ui.available_height() / 6.0; - style.spacing.icon_width = ui.available_height() / 4.0; - style.spacing.icon_spacing = ui.available_width() / 20.0; + style.spacing.icon_width_inner = height / 6.0; + style.spacing.icon_width = height / 4.0; + style.spacing.icon_spacing = width / 20.0; ctx.set_style(style); - let half_width = (half_width/2.0)-15.0; - ui.vertical(|ui| { - ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.auto_update, "Auto-update")).on_hover_text(GUPAX_AUTO_UPDATE); - ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.ask_before_quit, "Ask before quitting")).on_hover_text(GUPAX_ASK_BEFORE_QUIT); - }); - ui.vertical(|ui| { - ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.auto_node, "Auto-node")).on_hover_text(GUPAX_AUTO_NODE); - ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.save_before_quit, "Save before quitting")).on_hover_text(GUPAX_SAVE_BEFORE_QUIT); - }); + let height = height/2.0; + ui.add_sized([width, height], egui::Checkbox::new(&mut state.auto_update, "Auto-update")).on_hover_text(GUPAX_AUTO_UPDATE); + ui.separator(); + ui.add_sized([width, height], egui::Checkbox::new(&mut state.auto_node, "Auto-node")).on_hover_text(GUPAX_AUTO_NODE); + ui.separator(); + ui.add_sized([width, height], egui::Checkbox::new(&mut state.update_via_tor, "Update via Tor")).on_hover_text(GUPAX_UPDATE_VIA_TOR); + ui.separator(); + ui.add_sized([width, height], egui::Checkbox::new(&mut state.ask_before_quit, "Ask before quit")).on_hover_text(GUPAX_ASK_BEFORE_QUIT); + ui.separator(); + ui.add_sized([width, height], egui::Checkbox::new(&mut state.save_before_quit, "Save before quit")).on_hover_text(GUPAX_SAVE_BEFORE_QUIT); }); }); - ui.add_space(10.0); + ui.add_space(SPACE); ui.horizontal(|ui| { ui.label("P2Pool binary path:"); diff --git a/src/main.rs b/src/main.rs index 0c6acf8..52d9e04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,7 +70,7 @@ pub struct App { // State og: State, // og = Old state to compare against state: State, // state = Working state (current settings) -// update: Update, // State for update data [update.rs] + update: Update, // State for update data [update.rs] diff: bool, // Instead of comparing [og == state] every frame, this bool indicates changes // Process/update state: // Doesn't make sense to save this on disk @@ -102,7 +102,6 @@ impl App { } fn new() -> Self { - let throwaway = State::default(); let app = Self { tab: Tab::default(), quit: false, @@ -114,7 +113,7 @@ impl App { node: Arc::new(Mutex::new(NodeStruct::default())), og: State::default(), state: State::default(), -// update: Update::new(&throwaway.gupax.absolute_p2pool_path, &throwaway.gupax.absolute_xmrig_path, true), + update: Update::new(PathBuf::new(), PathBuf::new(), true), diff: false, p2pool: false, xmrig: false, @@ -144,10 +143,12 @@ impl App { Err(err) => { panic_app(err.to_string()); exit(1); }, }; } + app.state = app.og.clone(); + // Handle max threads app.og.xmrig.max_threads = num_cpus::get(); if app.og.xmrig.current_threads > app.og.xmrig.max_threads { app.og.xmrig.current_threads = app.og.xmrig.max_threads; } - app.state = app.og.clone(); -// app.update = Update::new(&app.og.gupax.absolute_p2pool_path, &app.og.gupax.absolute_xmrig_path, app.og.gupax.update_via_tor); + // Apply TOML values to [Update] + app.update = Update::new(app.og.gupax.absolute_p2pool_path.clone(), app.og.gupax.absolute_xmrig_path.clone(), app.og.gupax.update_via_tor); app } } @@ -198,10 +199,10 @@ fn init_text_styles(ctx: &egui::Context, width: f32) { } fn init_logger() { - #[cfg(debug_assertions)] +// #[cfg(debug_assertions)] let filter = LevelFilter::Info; - #[cfg(not(debug_assertions))] - let filter = LevelFilter::Warn; +// #[cfg(not(debug_assertions))] +// let filter = LevelFilter::Warn; use env_logger::fmt::Color; Builder::new().format(|buf, record| { let level; @@ -228,7 +229,7 @@ fn init_logger() { fn init_options() -> NativeOptions { let mut options = eframe::NativeOptions::default(); - options.min_window_size = Option::from(Vec2::new(1280.0, 720.0)); + options.min_window_size = Option::from(Vec2::new(854.0, 480.0)); options.max_window_size = Option::from(Vec2::new(3180.0, 2160.0)); options.initial_window_size = Option::from(Vec2::new(1280.0, 720.0)); options.follow_system_theme = false; @@ -353,8 +354,8 @@ impl eframe::App for Panic { //---------------------------------------------------------------------------------------------------- Main [App] frame fn main() { init_logger(); - let app = App::new(); let options = init_options(); + let app = App::new(); eframe::run_native("Gupax", options, Box::new(|cc| Box::new(App::cc(cc, app))),); } @@ -372,14 +373,7 @@ impl eframe::App for App { // *-------* // | DEBUG | // *-------* - let p2pool = self.og.gupax.absolute_p2pool_path.clone(); - let xmrig = self.og.gupax.absolute_xmrig_path.clone(); - let tor = self.og.gupax.update_via_tor.clone(); - thread::spawn(move|| { - info!("Spawning update thread..."); - let update = Update::start(&mut Update::new(p2pool, xmrig, tor)); - }); - thread::park(); + // This sets the top level Ui dimensions. // Used as a reference for other uis. egui::CentralPanel::default().show(ctx, |ui| { self.width = ui.available_width(); self.height = ui.available_height(); }); @@ -580,15 +574,19 @@ impl eframe::App for App { }); } + // Middle panel, contents of the [Tab] egui::CentralPanel::default().show(ctx, |ui| { + // This sets the Ui dimensions after Top/Bottom are filled + self.width = ui.available_width(); + self.height = ui.available_height(); ui.style_mut().override_text_style = Some(egui::TextStyle::Body); - match self.tab { - Tab::About => { + match self.tab { + Tab::About => { ui.add_space(10.0); ui.vertical_centered(|ui| { - let space = ui.available_height()/2.2; - self.banner.show(ui); - ui.label("Gupax (guh-picks) is a cross-platform GUI for mining"); + // Display [Gupax] banner at max, 1/4 the available length + self.banner.show_max_size(ui, Vec2::new(self.width, self.height/4.0)); + ui.label("Gupax is a cross-platform GUI for mining"); ui.hyperlink_to("[Monero]", "https://www.github.com/monero-project/monero"); ui.label("on the decentralized"); ui.hyperlink_to("[P2Pool]", "https://www.github.com/SChernykh/p2pool"); @@ -596,27 +594,26 @@ impl eframe::App for App { ui.hyperlink_to("[XMRig]", "https://www.github.com/xmrig/xmrig"); ui.label("miner for max hashrate"); - ui.add_space(ui.available_height()/2.4); - + ui.add_space(ui.available_height()/2.0); ui.hyperlink_to("Powered by egui", "https://github.com/emilk/egui"); ui.hyperlink_to(format!("{} {}", GITHUB, "Gupax made by hinto-janaiyo"), "https://www.github.com/hinto-janaiyo/gupax"); ui.label("egui is licensed under MIT & Apache-2.0"); ui.label("Gupax, P2Pool, and XMRig are licensed under GPLv3"); }); - } - Tab::Status => { - Status::show(self, ctx, ui); - } - Tab::Gupax => { - Gupax::show(&mut self.state.gupax, ctx, ui); - } - Tab::P2pool => { - P2pool::show(&mut self.state.p2pool, ctx, ui); - } - Tab::Xmrig => { - Xmrig::show(&mut self.state.xmrig, ctx, ui); - } - } + } + Tab::Status => { + Status::show(self, self.width, self.height, ctx, ui); + } + Tab::Gupax => { + Gupax::show(&mut self.state.gupax, self.width, self.height, &mut self.update, self.og.version.clone(), ctx, ui); + } + Tab::P2pool => { + P2pool::show(&mut self.state.p2pool, self.width, self.height, ctx, ui); + } + Tab::Xmrig => { + Xmrig::show(&mut self.state.xmrig, self.width, self.height, ctx, ui); + } + } }); } } diff --git a/src/p2pool.rs b/src/p2pool.rs index 31b13ad..a07883b 100644 --- a/src/p2pool.rs +++ b/src/p2pool.rs @@ -34,7 +34,7 @@ use crate::node::{RINO,SETH,SELSTA}; impl P2pool { - pub fn show(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(&mut self, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) { // TODO: // ping code // If ping-ING, display stats diff --git a/src/status.rs b/src/status.rs index c818364..4825dd3 100644 --- a/src/status.rs +++ b/src/status.rs @@ -25,7 +25,7 @@ pub struct Status { } impl Status { - pub fn show(app: &mut App, ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(app: &mut App, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) { let color = if ui.visuals().dark_mode { Color32::from_additive_luminance(196) } else { diff --git a/src/update.rs b/src/update.rs index adb1669..ff6c3f2 100644 --- a/src/update.rs +++ b/src/update.rs @@ -33,7 +33,7 @@ use std::io::{Read,Write}; //use crate::{Name::*,State}; use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; -use anyhow::Error; +use anyhow::{anyhow,Error}; use arti_hyper::*; use arti_client::{TorClient,TorClientConfig}; use tokio::io::{AsyncReadExt,AsyncWriteExt}; @@ -45,6 +45,8 @@ use arti_hyper::*; use log::*; use crate::update::Name::*; use std::path::PathBuf; +use crate::state::Version; +use crate::constants::GUPAX_VERSION; // use tls_api_native_tls::{TlsConnector,TlsConnectorBuilder}; @@ -155,6 +157,7 @@ const FAKE_USER_AGENT: [&'static str; 50] = [ "curl/7.85.0", ]; +const MSG_NONE: &'static str = "No update in progress"; const MSG_START: &'static str = "Starting update"; const MSG_TMP: &'static str = "Creating temporary directory"; const MSG_TOR: &'static str = "Creating Tor+HTTPS client"; @@ -177,15 +180,16 @@ const MSG_ARCHIVE: &'static str = "Downloading packages"; // 15% | Extract (x3) // 15% | Upgrade (x3) +#[derive(Clone)] pub struct Update { - path_gupax: String, // Full path to current gupax - path_p2pool: String, // Full path to current p2pool - path_xmrig: String, // Full path to current xmrig - tmp_dir: String, // Full path to temporary directory - updating: Arc>, // Is an update in progress? - prog: Arc>, // Holds the 0-100% progress bar number - msg: Arc>, // Message to display on [Gupax] tab while updating - tor: bool, // Is Tor enabled or not? + pub path_gupax: String, // Full path to current gupax + pub path_p2pool: String, // Full path to current p2pool + pub path_xmrig: String, // Full path to current xmrig + pub tmp_dir: String, // Full path to temporary directory + pub updating: Arc>, // Is an update in progress? + pub prog: Arc>, // Holds the 0-100% progress bar number + pub msg: Arc>, // Message to display on [Gupax] tab while updating + pub tor: bool, // Is Tor enabled or not? } impl Update { @@ -196,9 +200,9 @@ impl Update { path_p2pool: path_p2pool.display().to_string(), path_xmrig: path_xmrig.display().to_string(), tmp_dir: "".to_string(), - updating: Arc::new(Mutex::new(true)), + updating: Arc::new(Mutex::new(false)), prog: Arc::new(Mutex::new(0)), - msg: Arc::new(Mutex::new("".to_string())), + msg: Arc::new(Mutex::new(MSG_NONE.to_string())), tor, } } @@ -254,73 +258,114 @@ impl Update { // 5. extract, upgrade #[tokio::main] - pub async fn start(&mut self) -> Result<(), anyhow::Error> { + pub async fn start(update: Arc>, version: Version) -> Result<(), anyhow::Error> { + // Start + *update.lock().unwrap().updating.lock().unwrap() = true; + // Set progress bar - *self.msg.lock().unwrap() = MSG_START.to_string(); - *self.prog.lock().unwrap() = 0; - info!("Update | Init | {}...", *self.msg.lock().unwrap()); + *update.lock().unwrap().msg.lock().unwrap() = MSG_START.to_string(); + *update.lock().unwrap().prog.lock().unwrap() = 0; + info!("Update | Init | {}...", *update.lock().unwrap().msg.lock().unwrap()); // Get temporary directory - *self.msg.lock().unwrap() = MSG_TMP.to_string(); - info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap()); + *update.lock().unwrap().msg.lock().unwrap() = MSG_TMP.to_string(); + // Cannot lock Arc twice in same line + // 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(); - *self.prog.lock().unwrap() += 10; + *update.lock().unwrap().prog.lock().unwrap() += 10; // Make Pkg vector + let prog = update.lock().unwrap().prog.clone(); + let msg = update.lock().unwrap().msg.clone(); let vec = vec![ - Pkg::new(Gupax, &tmp_dir, self.prog.clone(), self.msg.clone()), - Pkg::new(P2pool, &tmp_dir, self.prog.clone(), self.msg.clone()), - Pkg::new(Xmrig, &tmp_dir, self.prog.clone(), self.msg.clone()), + Pkg::new(Gupax, &tmp_dir, prog.clone(), msg.clone()), + Pkg::new(P2pool, &tmp_dir, prog.clone(), msg.clone()), + Pkg::new(Xmrig, &tmp_dir, prog.clone(), msg.clone()), ]; let mut handles: Vec> = vec![]; // Create Tor/HTTPS client - if self.tor { *self.msg.lock().unwrap() = MSG_TOR.to_string() } else { *self.msg.lock().unwrap() = MSG_HTTPS.to_string() } - info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap()); - let client = Self::get_client(self.tor).await?; - *self.prog.lock().unwrap() += 15; + if update.lock().unwrap().tor { + *update.lock().unwrap().msg.lock().unwrap() = MSG_TOR.to_string() + } else { + *update.lock().unwrap().msg.lock().unwrap() = MSG_HTTPS.to_string() + } + 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; // Loop for metadata + *update.lock().unwrap().msg.lock().unwrap() = MSG_METADATA.to_string(); info!("Update | Metadata | Starting metadata fetch..."); for pkg in vec.iter() { // Clone data before sending to async let name = pkg.name.clone(); - let version = Arc::clone(&pkg.version); + let new_ver = Arc::clone(&pkg.new_ver); let prog = Arc::clone(&pkg.prog); let client = client.clone(); - let request = Pkg::get_request(pkg.link_metadata.to_string())?; + let link = pkg.link_metadata.to_string(); // Send to async let handle: JoinHandle<()> = tokio::spawn(async move { match client { - ClientEnum::Tor(t) => Pkg::get_metadata(name, version, prog, t, request).await, - ClientEnum::Https(h) => Pkg::get_metadata(name, version, prog, h, request).await, + ClientEnum::Tor(t) => Pkg::get_metadata(name, new_ver, prog, t, link).await, + ClientEnum::Https(h) => Pkg::get_metadata(name, new_ver, prog, h, link).await, }; }); handles.push(handle); } - - - // TODO: - // connection fails sometimes - // Regex for [v...] or restart Client process. - - // Unwrap async for handle in handles { handle.await?; } info!("Update | Metadata ... OK"); + // Loop for version comparison + info!("Update | Compare | Starting version comparison..."); + let prog = update.lock().unwrap().prog.clone(); + let msg = update.lock().unwrap().msg.clone(); + let mut vec2 = vec![]; + for pkg in vec.iter() { + let new_ver = pkg.new_ver.lock().unwrap().to_owned(); + match pkg.name { + Gupax => { + if new_ver == GUPAX_VERSION { + info!("Update | Compare | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), GUPAX_VERSION); + } else { + info!("Update | Compare | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), GUPAX_VERSION); + vec2.push(pkg); + } + } + P2pool => { + if new_ver == version.p2pool { + info!("Update | Compare | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), version.p2pool); + } else { + info!("Update | Compare | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), version.p2pool); + vec2.push(pkg); + } + } + Xmrig => { + if new_ver == GUPAX_VERSION { + info!("Update | Compare | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), version.xmrig); + } else { + info!("Update | Compare | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), version.xmrig); + vec2.push(pkg); + } + } + } + } + // Loop for download let mut handles: Vec> = vec![]; info!("Update | Download | Starting download..."); - for pkg in vec.iter() { + for pkg in vec2.iter() { // Clone data before async let name = pkg.name.clone(); let bytes = Arc::clone(&pkg.bytes); let prog = Arc::clone(&pkg.prog); let client = client.clone(); - let version = pkg.version.lock().unwrap().to_string(); + let version = pkg.new_ver.lock().unwrap(); let link; // Download link = PREFIX + Version (found at runtime) + SUFFIX + Version + EXT // Example: https://github.com/hinto-janaiyo/gupax/releases/download/v0.0.1/gupax-v0.0.1-linux-standalone-x64 @@ -354,7 +399,7 @@ impl Update { // std::fs::OpenOptions::new().mode(0o700).create(true).write(true).open(&tmp); std::fs::create_dir(&tmp)?; info!("Update | Extract | Starting extraction..."); - for pkg in vec.iter() { + for pkg in vec2.iter() { let tmp = tmp.to_string() + &pkg.name.to_string(); if pkg.name == Name::Gupax { std::fs::write(tmp, pkg.bytes.lock().unwrap().as_ref())?; @@ -365,6 +410,7 @@ impl Update { info!("Update | Extract | {} ... {}%", pkg.name, pkg.prog.lock().unwrap()); } info!("Update | Extract ... OK"); + *update.lock().unwrap().updating.lock().unwrap() = false; std::process::exit(0); Ok(()) } @@ -388,7 +434,8 @@ pub struct Pkg { prog: Arc>, msg: Arc>, bytes: Arc>, - version: Arc>, + old_ver: String, + new_ver: Arc>, } impl Pkg { @@ -423,7 +470,8 @@ impl Pkg { prog, msg, bytes: Arc::new(Mutex::new(bytes::Bytes::new())), - version: Arc::new(Mutex::new(String::new())), + old_ver: String::new(), + new_ver: Arc::new(Mutex::new(String::new())), } } @@ -440,15 +488,26 @@ impl Pkg { // Get metadata using [Generic hyper::client] & [Request] // and change [version, prog] under an Arc - pub async fn get_metadata(name: Name, version: Arc>, prog: Arc>, client: Client, request: Request) -> Result<(), Error> + 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, { - let mut response = client.request(request).await?; - let body = hyper::body::to_bytes(response.body_mut()).await?; - let body: Version = serde_json::from_slice(&body)?; - *version.lock().unwrap() = body.tag_name.clone(); - *prog.lock().unwrap() += 5; - info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap()); - Ok(()) + // Retry [3] times if version is not [v*] + let mut n = 0; + while n < 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?; + let body: TagName = serde_json::from_slice(&body)?; + if body.tag_name.starts_with('v') { + *new_ver.lock().unwrap() = body.tag_name.clone(); + *prog.lock().unwrap() += 5; + info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap()); + return Ok(()) + } + warn!("Update | Metadata | {} metadata fetch failed, retry [{}/3]...", name, n); + n += 1; + } + error!("Update | Metadata | {} metadata fetch failed", name); + Err(anyhow!("Metadata fetch failed")) } // Takes a [Request], fills the appropriate [Pkg] @@ -471,7 +530,7 @@ impl Pkg { // This inherits the value of [tag_name] from GitHub's JSON API #[derive(Debug, Serialize, Deserialize)] -struct Version { +struct TagName { tag_name: String, } diff --git a/src/xmrig.rs b/src/xmrig.rs index f84b072..ec12d74 100644 --- a/src/xmrig.rs +++ b/src/xmrig.rs @@ -24,7 +24,7 @@ use crate::constants::*; use crate::state::Xmrig; impl Xmrig { - pub fn show(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(&mut self, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) { let height = ui.available_height() / 10.0; let mut width = ui.available_width() - 10.0; ui.group(|ui| {