From e8060c45210c5a95846ca626ac474e45f76117bf Mon Sep 17 00:00:00 2001
From: hinto-janaiyo <hinto.janaiyo@protonmail.com>
Date: Wed, 26 Oct 2022 23:15:56 -0400
Subject: [PATCH] update: implement retry on [v*] failure, version diff to new
 vec

---
 src/about.rs     |   2 +-
 src/constants.rs |  13 +++-
 src/gupax.rs     |  80 ++++++++++++++++--------
 src/main.rs      |  75 +++++++++++-----------
 src/p2pool.rs    |   2 +-
 src/status.rs    |   2 +-
 src/update.rs    | 159 ++++++++++++++++++++++++++++++++---------------
 src/xmrig.rs     |   2 +-
 8 files changed, 212 insertions(+), 123 deletions(-)

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<Mutex<bool>>, // Is an update in progress?
-	prog: Arc<Mutex<u8>>, // Holds the 0-100% progress bar number
-	msg: Arc<Mutex<String>>, // 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<Mutex<bool>>, // Is an update in progress?
+	pub prog: Arc<Mutex<u8>>, // Holds the 0-100% progress bar number
+	pub msg: Arc<Mutex<String>>, // 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<Mutex<Self>>, 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<Mutex> 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<JoinHandle<()>> = 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<JoinHandle<()>> = 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<Mutex<u8>>,
 	msg: Arc<Mutex<String>>,
 	bytes: Arc<Mutex<hyper::body::Bytes>>,
-	version: Arc<Mutex<String>>,
+	old_ver: String,
+	new_ver: Arc<Mutex<String>>,
 }
 
 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<C>] & [Request]
 	// and change [version, prog] under an Arc<Mutex>
-	pub async fn get_metadata<C>(name: Name, version: Arc<Mutex<String>>, prog: Arc<Mutex<u8>>, client: Client<C>, request: Request<Body>) -> Result<(), Error>
+	pub async fn get_metadata<C>(name: Name, new_ver: Arc<Mutex<String>>, prog: Arc<Mutex<u8>>, client: Client<C>, 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| {