diff --git a/Cargo.lock b/Cargo.lock index 14aae8f..9210fa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1158,8 +1158,6 @@ dependencies = [ [[package]] name = "eframe" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d49426c3e72a6728b0c790d22db8bf7bbcff10d83b8b6f3a01295be982302e" dependencies = [ "bytemuck", "egui", @@ -1180,8 +1178,6 @@ dependencies = [ [[package]] name = "egui" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc9fcd393c3daaaf5909008a1d948319d538b79c51871e4df0993260260a94e4" dependencies = [ "ahash 0.8.0", "epaint", @@ -1192,8 +1188,6 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ddc525334c416e11580123e147b970f738507f427c9fb1cd09ea2dd7416a3a" dependencies = [ "arboard", "egui", @@ -1207,8 +1201,6 @@ dependencies = [ [[package]] name = "egui_extras" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f698f685bb0ad39e87109e2f695ded0bccde77d5d40bbf7590cb5561c1e3039d" dependencies = [ "egui", "image", @@ -1217,8 +1209,6 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad77d4a00402bae9658ee64be148f4b2a0b38e4fc7874970575ca01ed1c5b75d" dependencies = [ "bytemuck", "egui", @@ -1238,8 +1228,6 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "emath" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9542a40106fdba943a055f418d1746a050e1a903a049b030c2b097d4686a33cf" dependencies = [ "bytemuck", ] @@ -1296,8 +1284,6 @@ dependencies = [ [[package]] name = "epaint" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba04741be7f6602b1a1b28f1082cce45948a7032961c52814f8946b28493300" dependencies = [ "ab_glyph", "ahash 0.8.0", @@ -1809,7 +1795,6 @@ dependencies = [ "reqwest", "rusqlite", "serde", - "serde_derive", "serde_json", "sha2 0.10.6", "tar", diff --git a/Cargo.toml b/Cargo.toml index a16b273..e5fa50a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,17 +10,17 @@ arti-hyper = "0.7.0" bytes = "1.2.1" chrono = "0.4.22" dirs = "4.0.0" -eframe = "0.19.0" -egui = "0.19.0" -egui_extras = { version = "0.19.0", features = ["image"] } +#eframe = "0.19.0" +#egui = "0.19.0" +#egui_extras = { version = "0.19.0", features = ["image"] } ## [external/egui/crates/eframe/src/native/run.rs] line 41: [.with_srgb(true)] ## This line causes a [panic!] inside a Windows VM, from a Linux host. ## There are many issue threads and PRs to fix it but for now, ## this is here for convenience sake when I'm testing. ## The only change is [.with_srgb()] is set to [false]. -#eframe = { path = "external/egui/crates/eframe" } -#egui = { path = "external/egui/crates/egui" } -#egui_extras = { path = "external/egui/crates/egui_extras", features = ["image"] } +eframe = { path = "external/egui/crates/eframe" } +egui = { path = "external/egui/crates/egui" } +egui_extras = { path = "external/egui/crates/egui_extras", features = ["image"] } env_logger = "0.9.1" figment = { version = "0.10.8", features = ["toml"] } flate2 = "1.0" @@ -37,24 +37,29 @@ rand = "0.8.5" regex = "1.6.0" reqwest = { version = "0.11.12", features = ["blocking", "json"] } rusqlite = { version = "0.28.0", features = ["bundled"] } -serde = "1.0.145" -serde_derive = "1.0.145" +serde = { version = "1.0.145", features = ["rc", "derive"] } serde_json = "1.0" sha2 = "0.10.6" -tar = "0.4.38" tls-api = "0.9.0" tls-api-native-tls = "0.9.0" tokio = { version = "1.21.2", features = ["full"] } toml = "0.5.9" tor-rtcompat = "0.7.0" walkdir = "2.3.2" + +# Unix dependencies +[target.'cfg(unix)'.dependencies] +tar = "0.4.38" + +# Windows dependencies +[target.'cfg(windows)'.dependencies] zip = "0.6.3" -# For Windows +# For Windows build (icon) [target.'cfg(windows)'.build-dependencies] winres = "0.1.12" -# For macOS (cargo-bundle) +# For macOS build (cargo-bundle) [package.metadata.bundle] identifier = "io.github.hinto-janaiyo.gupax" icon = ["images/png/icon@2x.png"] diff --git a/src/gupax.rs b/src/gupax.rs index a1cf49a..8c92d29 100644 --- a/src/gupax.rs +++ b/src/gupax.rs @@ -16,7 +16,7 @@ // along with this program. If not, see . use std::path::Path; -use crate::App; +use crate::{App,State}; use egui::WidgetType::Button; use crate::constants::*; use crate::state::{Gupax,Version}; @@ -26,7 +26,7 @@ use std::sync::{Arc,Mutex}; use log::*; impl Gupax { - pub fn show(state: &mut Gupax, og: &Gupax, width: f32, height: f32, update: &mut Update, version: Version, ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(state: &mut Gupax, og: &Arc>, state_ver: &Arc>, update: &Arc>, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) { // Update button + Progress bar ui.group(|ui| { // These are in unnecessary [ui.vertical()]'s @@ -35,30 +35,44 @@ 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(); + let updating = *update.lock().unwrap().updating.lock().unwrap(); ui.vertical(|ui| { 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 = og.absolute_p2pool_path.display().to_string(); - update.path_xmrig = og.absolute_xmrig_path.display().to_string(); - update.tor = og.update_via_tor; - let update = Arc::new(Mutex::new(update.clone())); + update.lock().unwrap().path_p2pool = og.lock().unwrap().gupax.absolute_p2pool_path.display().to_string(); + update.lock().unwrap().path_xmrig = og.lock().unwrap().gupax.absolute_xmrig_path.display().to_string(); + update.lock().unwrap().tor = og.lock().unwrap().gupax.update_via_tor; + let og = Arc::clone(&og); + let og_ver = Arc::clone(&og.lock().unwrap().version); + let state_ver = Arc::clone(&state_ver); + let update = Arc::clone(&update); + let update_thread = Arc::clone(&update); thread::spawn(move|| { info!("Spawning update thread..."); - match Update::start(update.clone(), version) { + match Update::start(update_thread, og_ver.clone(), state_ver.clone()) { Err(e) => { - info!("Update | {} ... FAIL", e); + info!("Update ... {} ... FAIL", e); *update.lock().unwrap().msg.lock().unwrap() = format!("{} | {}", MSG_FAILED, e); - *update.lock().unwrap().updating.lock().unwrap() = false; }, - _ => (), - } + _ => { + info!("Update | Saving state..."); + match State::save(&mut og.lock().unwrap()) { + Ok(_) => info!("Update ... OK"), + Err(e) => { + warn!("Update | Saving state ... FAIL ... {}", e); + *update.lock().unwrap().msg.lock().unwrap() = format!("Saving new versions into state failed"); + }, + }; + } + }; + *update.lock().unwrap().updating.lock().unwrap() = false; }); } }); ui.vertical(|ui| { ui.set_enabled(updating); - let msg = format!("{}\n{}{}", *update.msg.lock().unwrap(), *update.prog.lock().unwrap(), "%"); + let prog = *update.lock().unwrap().prog.lock().unwrap(); + let msg = format!("{}\n{}{}", *update.lock().unwrap().msg.lock().unwrap(), prog, "%"); ui.add_sized([width, height*1.4], egui::Label::new(msg)); let height = height/2.0; if updating { @@ -66,7 +80,7 @@ impl Gupax { } else { ui.add_sized([width, height], egui::Label::new("...")); } - ui.add_sized([width, height], egui::ProgressBar::new((update.prog.lock().unwrap().round() / 100.0))); + ui.add_sized([width, height], egui::ProgressBar::new((update.lock().unwrap().prog.lock().unwrap().round() / 100.0))); }); }); diff --git a/src/main.rs b/src/main.rs index da8b77e..32832b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ // along with this program. If not, see . // Hide console in Windows -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +//#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] //---------------------------------------------------------------------------------------------------- Imports // egui/eframe @@ -70,10 +70,10 @@ pub struct App { width: f32, // Top-level width height: f32, // Top-level height // State - og: State, // og = Old state to compare against + og: Arc>, // og = Old state to compare against state: State, // state = Working state (current settings) - update: Update, // State for update data [update.rs] - diff: bool, // Instead of comparing [og == state] every frame, this bool indicates changes + update: Arc>, // State for update data [update.rs] + diff: bool, // This bool indicates state changes // Process/update state: // Doesn't make sense to save this on disk // so it's represented as a bool here. @@ -113,9 +113,9 @@ impl App { width: 1280.0, height: 720.0, node: Arc::new(Mutex::new(NodeStruct::default())), - og: State::default(), + og: Arc::new(Mutex::new(State::default())), state: State::default(), - update: Update::new(PathBuf::new(), PathBuf::new(), true), + update: Arc::new(Mutex::new(Update::new(PathBuf::new(), PathBuf::new(), true))), diff: false, p2pool: false, xmrig: false, @@ -141,16 +141,23 @@ impl App { // Read disk state if no [--reset] arg if app.reset == false { app.og = match State::get() { - Ok(toml) => toml, + Ok(toml) => Arc::new(Mutex::new(toml)), Err(err) => { panic_main(err.to_string()); exit(1); }, }; } - app.state = app.og.clone(); + app.state = app.og.lock().unwrap().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.og.lock().unwrap().xmrig.max_threads = num_cpus::get(); + let current = app.og.lock().unwrap().xmrig.current_threads; + let max = app.og.lock().unwrap().xmrig.max_threads; + if current > max { + app.og.lock().unwrap().xmrig.current_threads = max; + } // 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); + let p2pool_path = app.og.lock().unwrap().gupax.absolute_p2pool_path.clone(); + let xmrig_path = app.og.lock().unwrap().gupax.absolute_xmrig_path.clone(); + let tor = app.og.lock().unwrap().gupax.update_via_tor; + app.update = Arc::new(Mutex::new(Update::new(p2pool_path, xmrig_path, tor))); app } } @@ -304,6 +311,22 @@ pub fn get_rand_tmp(path: &String) -> String { path } +// Clean any [gupax_tmp.*] directories +pub fn clean_dir() -> Result<(), anyhow::Error> { + for entry in std::fs::read_dir(get_exe_dir()?)? { + let entry = entry?; + entry.path().is_dir() && continue; + if entry.file_name().to_str().ok_or(anyhow::Error::msg("Basename failed"))?.starts_with("gupax_tmp_") { + let path = entry.path(); + match std::fs::remove_dir_all(&path) { + Ok(_) => info!("Remove [{}] ... OK", path.display()), + Err(e) => warn!("Remove [{}] ... FAIL ... {}", path.display(), e), + } + } + } + Ok(()) +} + //---------------------------------------------------------------------------------------------------- [App] frame for [Panic] situations fn panic_main(error: String) { error!("{}", error); @@ -358,6 +381,10 @@ impl eframe::App for Panic { fn main() { init_logger(); let options = init_options(); + match clean_dir() { + Ok(_) => info!("Temporary folder cleanup ... OK"), + Err(e) => warn!("Could not cleanup [gupax_tmp] folders: {}", e), + } let app = App::new(); let name = app.name_version.clone(); eframe::run_native(&name, options, Box::new(|cc| Box::new(App::cc(cc, app))),); @@ -366,7 +393,7 @@ fn main() { impl eframe::App for App { fn on_close_event(&mut self) -> bool { self.quit = true; - if self.og.gupax.ask_before_quit { + if self.og.lock().unwrap().gupax.ask_before_quit { self.quit_confirm } else { true @@ -390,6 +417,17 @@ impl eframe::App for App { frame.set_fullscreen(!info.window_info.fullscreen); } + // If no state diff (og == state), compare and enable if found. + // The struct fields are compared directly because [Version] + // contains Arc's that cannot be compared easily. + // They don't need to be compared anyway. + let og = self.og.lock().unwrap().clone(); + if og.gupax != self.state.gupax || og.p2pool != self.state.p2pool || og.xmrig != self.state.xmrig { + self.diff = true; + } else { + self.diff = false; + } + // Close confirmation. if self.quit { // If [ask_before_quit == true] @@ -521,12 +559,21 @@ impl eframe::App for App { ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| { ui.group(|ui| { - if self.state == self.og { + if self.diff == false { ui.set_enabled(false) } let width = width / 2.0; - if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { self.og = self.state.clone(); self.state.save(); } - if ui.add_sized([width, height], egui::Button::new("Reset")).on_hover_text("Reset changes").clicked() { self.state = self.og.clone(); } + if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { + self.og.lock().unwrap().gupax = self.state.gupax.clone(); + self.og.lock().unwrap().p2pool = self.state.p2pool.clone(); + self.og.lock().unwrap().xmrig = self.state.xmrig.clone(); + self.og.lock().unwrap().save(); + } + if ui.add_sized([width, height], egui::Button::new("Reset")).on_hover_text("Reset changes").clicked() { + self.state.gupax = self.og.lock().unwrap().gupax.clone(); + self.state.p2pool = self.og.lock().unwrap().p2pool.clone(); + self.state.xmrig = self.og.lock().unwrap().xmrig.clone(); + } }); let width = (ui.available_width() / 3.0) - 6.2; @@ -615,7 +662,7 @@ impl eframe::App for App { Status::show(self, self.width, self.height, ctx, ui); } Tab::Gupax => { - Gupax::show(&mut self.state.gupax, &self.og.gupax, self.width, self.height, &mut self.update, self.og.version.clone(), ctx, ui); + Gupax::show(&mut self.state.gupax, &self.og, &self.state.version, &self.update, self.width, self.height, ctx, ui); } Tab::P2pool => { P2pool::show(&mut self.state.p2pool, self.width, self.height, ctx, ui); diff --git a/src/node.rs b/src/node.rs index 007cbe9..bbfdbd5 100644 --- a/src/node.rs +++ b/src/node.rs @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use serde_derive::{Serialize,Deserialize}; +use serde::{Serialize,Deserialize}; use std::time::{Instant,Duration}; use std::collections::HashMap; use std::error::Error; diff --git a/src/state.rs b/src/state.rs index 8e71d9a..9cae04d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -32,7 +32,8 @@ use std::{fs,env}; use std::fmt::Display; use std::path::{Path,PathBuf}; use std::result::Result; -use serde_derive::{Serialize,Deserialize}; +use std::sync::{Arc,Mutex}; +use serde::{Serialize,Deserialize}; use figment::Figment; use figment::providers::{Format,Toml}; use crate::constants::HORIZONTAL; @@ -81,10 +82,10 @@ impl State { pool: "localhost:3333".to_string(), address: "".to_string(), }, - version: Version { - p2pool: P2POOL_VERSION.to_string(), - xmrig: XMRIG_VERSION.to_string(), - }, + version: Arc::new(Mutex::new(Version { + p2pool: Arc::new(Mutex::new(P2POOL_VERSION.to_string())), + xmrig: Arc::new(Mutex::new(XMRIG_VERSION.to_string())), + })), } } @@ -267,13 +268,13 @@ const DIRECTORY: &'static str = "gupax"; #[cfg(target_os = "windows")] pub const DEFAULT_P2POOL_PATH: &'static str = r"P2Pool\p2pool.exe"; #[cfg(target_os = "macos")] -pub const DEFAULT_P2POOL_PATH: &'static str = "P2Pool/p2pool"; +pub const DEFAULT_P2POOL_PATH: &'static str = "P2Pool/P2Pool"; #[cfg(target_os = "linux")] pub const DEFAULT_P2POOL_PATH: &'static str = "p2pool/p2pool"; #[cfg(target_os = "windows")] pub const DEFAULT_XMRIG_PATH: &'static str = r"XMRig\xmrig.exe"; #[cfg(target_os = "macos")] -pub const DEFAULT_XMRIG_PATH: &'static str = "XMRig/xmrig"; +pub const DEFAULT_XMRIG_PATH: &'static str = "XMRig/XMRig"; #[cfg(target_os = "linux")] pub const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig"; @@ -288,12 +289,12 @@ pub enum TomlError { } //---------------------------------------------------------------------------------------------------- Structs -#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)] +#[derive(Clone,Debug,Deserialize,Serialize)] pub struct State { pub gupax: Gupax, pub p2pool: P2pool, pub xmrig: Xmrig, - pub version: Version, + pub version: Arc>, } #[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)] @@ -341,8 +342,8 @@ pub struct Xmrig { // pub args: String, } -#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)] +#[derive(Clone,Debug,Deserialize,Serialize)] pub struct Version { - pub p2pool: String, - pub xmrig: String, + pub p2pool: Arc>, + pub xmrig: Arc>, } diff --git a/src/update.rs b/src/update.rs index e16c144..8a0f085 100644 --- a/src/update.rs +++ b/src/update.rs @@ -38,7 +38,7 @@ use hyper_tls::HttpsConnector; use log::*; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; -use serde_derive::{Serialize,Deserialize}; +use serde::{Serialize,Deserialize}; use std::io::{Read,Write}; use std::path::PathBuf; use std::sync::{Arc,Mutex}; @@ -47,7 +47,11 @@ use tls_api::{TlsConnector, TlsConnectorBuilder}; use tokio::io::{AsyncReadExt,AsyncWriteExt}; use tokio::task::JoinHandle; use walkdir::WalkDir; + +#[cfg(target_os = "windows")] use zip::ZipArchive; +#[cfg(target_family = "unix")] +use std::os::unix::fs::OpenOptionsExt; //---------------------------------------------------------------------------------------------------- Constants // Package naming schemes: @@ -81,26 +85,47 @@ const P2POOL_HASH: &'static str = "sha256sums.txt.asc"; const XMRIG_HASH: &'static str = "SHA256SUMS"; #[cfg(target_os = "windows")] -const GUPAX_EXTENSION: &'static str = "-windows-standalone-x64.exe"; +const GUPAX_EXTENSION: &'static str = "-windows-x64-standalone.exe"; #[cfg(target_os = "windows")] const P2POOL_EXTENSION: &'static str = "-windows-x64.zip"; #[cfg(target_os = "windows")] const XMRIG_EXTENSION: &'static str = "-msvc-win64.zip"; #[cfg(target_os = "macos")] -const GUPAX_EXTENSION: &'static str = "-macos-standalone-x64"; +const GUPAX_EXTENSION: &'static str = "-macos-x64-standalone"; #[cfg(target_os = "macos")] const P2POOL_EXTENSION: &'static str = "-macos-x64.tar.gz"; #[cfg(target_os = "macos")] const XMRIG_EXTENSION: &'static str = "-macos-x64.tar.gz"; #[cfg(target_os = "linux")] -const GUPAX_EXTENSION: &'static str = "-linux-standalone-x64"; +const GUPAX_EXTENSION: &'static str = "-linux-x64-standalone"; #[cfg(target_os = "linux")] const P2POOL_EXTENSION: &'static str = "-linux-x64.tar.gz"; #[cfg(target_os = "linux")] const XMRIG_EXTENSION: &'static str = "-linux-static-x64.tar.gz"; +#[cfg(target_os = "windows")] +const GUPAX_BINARY: &'static str = "gupax.exe"; +#[cfg(target_os = "macos")] +const GUPAX_BINARY: &'static str = "Gupax"; +#[cfg(target_os = "linux")] +const GUPAX_BINARY: &'static str = "gupax"; + +#[cfg(target_os = "windows")] +const P2POOL_BINARY: &'static str = "p2pool.exe"; +#[cfg(target_os = "macos")] +const P2POOL_BINARY: &'static str = "P2Pool"; +#[cfg(target_os = "linux")] +const P2POOL_BINARY: &'static str = "p2pool"; + +#[cfg(target_os = "windows")] +const XMRIG_BINARY: &'static str = "xmrig.exe"; +#[cfg(target_os = "macos")] +const XMRIG_BINARY: &'static str = "XMRig"; +#[cfg(target_os = "linux")] +const XMRIG_BINARY: &'static str = "xmrig"; + // Some fake Curl/Wget user-agents because GitHub API requires one and a Tor browser // user-agent might be fingerprintable without all the associated headers. const FAKE_USER_AGENT: [&'static str; 50] = [ @@ -226,7 +251,7 @@ impl Update { // Get a temporary random folder for package download contents // This used to use [std::env::temp_dir()] but there were issues // using [std::fs::rename()] on tmpfs -> disk (Invalid cross-device link (os error 18)). - // So, uses the [Gupax] binary directory as a base, something like [/home/hinto/gupax/gupax_SG4xsDdVmr] + // So, uses the [Gupax] binary directory as a base, something like [/home/hinto/gupax/gupax_tmp_SG4xsDdVmr] pub fn get_tmp_dir() -> Result { let rand_string: String = thread_rng() .sample_iter(&Alphanumeric) @@ -235,9 +260,9 @@ impl Update { .collect(); let base = crate::get_exe_dir()?; #[cfg(target_os = "windows")] - let tmp_dir = format!("{}{}{}{}", base, r"\gupax_", rand_string, r"\"); + let tmp_dir = format!("{}{}{}{}", base, r"\gupax_tmp_", rand_string, r"\"); #[cfg(target_family = "unix")] - let tmp_dir = format!("{}{}{}{}", base, "/gupax_", rand_string, "/"); + let tmp_dir = format!("{}{}{}{}", base, "/gupax_tmp_", rand_string, "/"); info!("Update | Temporary directory ... {}", tmp_dir); Ok(tmp_dir) } @@ -281,7 +306,7 @@ impl Update { // 5. extract, upgrade #[tokio::main] - pub async fn start(update: Arc>, mut version: Version) -> Result<(), anyhow::Error> { + pub async fn start(update: Arc>, og_ver: Arc>, state_ver: Arc>) -> Result<(), anyhow::Error> { //---------------------------------------------------------------------------------------------------- Init *update.lock().unwrap().updating.lock().unwrap() = true; // Set timer @@ -408,28 +433,30 @@ impl Update { match pkg.name { Gupax => { if new_ver == GUPAX_VERSION { - info!("Update | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), GUPAX_VERSION); + info!("Update | {} {} == {} ... SKIPPING", pkg.name, GUPAX_VERSION, new_ver); } else { - info!("Update | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), GUPAX_VERSION); - new_pkgs.push(format!("\nGupax {} ➡ {}", GUPAX_VERSION, pkg.new_ver.lock().unwrap())); + info!("Update | {} {} != {} ... ADDING", pkg.name, GUPAX_VERSION, new_ver); + new_pkgs.push(format!("\nGupax {} ➡ {}", GUPAX_VERSION, new_ver)); vec3.push(pkg); } } P2pool => { - if new_ver == version.p2pool { - info!("Update | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), version.p2pool); + let old_ver = og_ver.lock().unwrap().p2pool.lock().unwrap().to_owned(); + if old_ver == new_ver { + info!("Update | {} {} == {} ... SKIPPING", pkg.name, old_ver, new_ver); } else { - info!("Update | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), version.p2pool); - new_pkgs.push(format!("\nP2Pool {} ➡ {}", version.p2pool, pkg.new_ver.lock().unwrap())); + info!("Update | {} {} != {} ... ADDING", pkg.name, old_ver, new_ver); + new_pkgs.push(format!("\nP2Pool {} ➡ {}", old_ver, new_ver)); vec3.push(pkg); } } Xmrig => { - if new_ver == GUPAX_VERSION { - info!("Update | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), version.xmrig); + let old_ver = og_ver.lock().unwrap().xmrig.lock().unwrap().to_owned(); + if old_ver == new_ver { + info!("Update | {} {} == {} ... SKIPPING", pkg.name, old_ver, new_ver); } else { - info!("Update | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), version.xmrig); - new_pkgs.push(format!("\nXMRig {} ➡ {}", version.xmrig, pkg.new_ver.lock().unwrap())); + info!("Update | {} {} != {} ... ADDING", pkg.name, old_ver, new_ver); + new_pkgs.push(format!("\nXMRig {} ➡ {}", old_ver, new_ver)); vec3.push(pkg); } } @@ -522,14 +549,13 @@ impl Update { *update.lock().unwrap().msg.lock().unwrap() = format!("{}{}", MSG_EXTRACT, new_pkgs); info!("Update | {}", EXTRACT); for pkg in vec4.iter() { - let tmp = tmp_dir.to_owned() + &pkg.name.to_string(); if pkg.name == Name::Gupax { + let tmp = tmp_dir.to_owned() + GUPAX_BINARY; #[cfg(target_family = "unix")] - use std::os::unix::fs::OpenOptionsExt; - #[cfg(target_family = "unix")] - std::fs::OpenOptions::new().create(true).write(true).mode(0o770).open(&tmp)?; + std::fs::OpenOptions::new().create(true).write(true).mode(0o750).open(&tmp)?; std::fs::write(tmp, pkg.bytes.lock().unwrap().as_ref())?; } else { + let tmp = tmp_dir.to_owned() + &pkg.name.to_string(); #[cfg(target_os = "windows")] ZipArchive::extract(&mut ZipArchive::new(std::io::Cursor::new(pkg.bytes.lock().unwrap().as_ref()))?, tmp)?; #[cfg(target_family = "unix")] @@ -553,46 +579,55 @@ impl Update { let entry = entry?.clone(); let basename = entry.file_name().to_str().ok_or(anyhow::Error::msg("WalkDir basename failed"))?; match basename { - "Gupax" => { + GUPAX_BINARY => { let path = update.lock().unwrap().path_gupax.clone(); info!("Update | Moving [{}] -> [{}]", entry.path().display(), path); + // Unix can replace running binaries no problem (they're loading into memory) + // Windows locks binaries in place, so we must move (rename) current binary + // into the temp folder, then move the new binary into the old ones spot. + // Clearing the temp folder is now moved at startup instead at the end + // of this function due to this behavior, thanks Windows. + #[cfg(target_os = "windows")] + std::fs::rename(&path, tmp_dir.clone() + "gupax_old.exe")?; std::fs::rename(entry.path(), path)?; *update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round(); }, - "p2pool" => { + P2POOL_BINARY => { let path = update.lock().unwrap().path_p2pool.clone(); let path = std::path::Path::new(&path); info!("Update | Moving [{}] -> [{}]", entry.path().display(), path.display()); std::fs::create_dir_all(path.parent().ok_or(anyhow::Error::msg("P2Pool path failed"))?)?; std::fs::rename(entry.path(), path)?; - version.p2pool = Pkg::get_new_pkg_version(P2pool, &vec4)?; + *og_ver.lock().unwrap().p2pool.lock().unwrap() = Pkg::get_new_pkg_version(P2pool, &vec4)?; *update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round(); }, - "xmrig" => { + XMRIG_BINARY => { let path = update.lock().unwrap().path_xmrig.clone(); let path = std::path::Path::new(&path); info!("Update | Moving [{}] -> [{}]", entry.path().display(), path.display()); std::fs::create_dir_all(path.parent().ok_or(anyhow::Error::msg("XMRig path failed"))?)?; std::fs::rename(entry.path(), path)?; - version.xmrig = Pkg::get_new_pkg_version(Xmrig, &vec4)?; + *og_ver.lock().unwrap().xmrig.lock().unwrap() = Pkg::get_new_pkg_version(Xmrig, &vec4)?; *update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round(); }, _ => (), } } + // Remove tmp dir (on Unix) + #[cfg(target_family = "unix")] info!("Update | Removing temporary directory ... {}", tmp_dir); + #[cfg(target_family = "unix")] std::fs::remove_dir_all(&tmp_dir)?; + let seconds = now.elapsed().as_secs(); - info!("Update ... Seconds elapsed: [{}s]", seconds); - info!("Update ... OK ... 100%"); + info!("Update | Seconds elapsed ... [{}s]", seconds); match seconds { 0 => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took 0 seconds... Do you have 10Gbit internet or something...?!{}", MSG_SUCCESS, new_pkgs), 1 => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took 1 second... Wow!{}", MSG_SUCCESS, new_pkgs), _ => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took {} seconds.{}", MSG_SUCCESS, seconds, new_pkgs), } *update.lock().unwrap().prog.lock().unwrap() = 100.0; - *update.lock().unwrap().updating.lock().unwrap() = false; Ok(()) } }