diff --git a/Cargo.lock b/Cargo.lock index 9210fa7..b66d5cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,48 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Gupax" +version = "0.1.0" +dependencies = [ + "anyhow", + "arti-client", + "arti-hyper", + "bytes", + "chrono", + "dirs", + "eframe", + "egui", + "egui_extras", + "env_logger 0.9.1", + "figment", + "flate2", + "hex-literal", + "hyper", + "hyper-tls", + "image", + "log", + "monero", + "num-format", + "num_cpus", + "rand 0.8.5", + "regex", + "reqwest", + "rusqlite", + "serde", + "serde_json", + "sha2 0.10.6", + "tar", + "tls-api", + "tls-api-native-tls", + "tokio", + "toml", + "tor-rtcompat", + "walkdir", + "winres", + "zip", +] + [[package]] name = "ab_glyph" version = "0.2.18" @@ -1158,6 +1200,8 @@ dependencies = [ [[package]] name = "eframe" version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d49426c3e72a6728b0c790d22db8bf7bbcff10d83b8b6f3a01295be982302e" dependencies = [ "bytemuck", "egui", @@ -1178,6 +1222,8 @@ 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", @@ -1188,6 +1234,8 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ddc525334c416e11580123e147b970f738507f427c9fb1cd09ea2dd7416a3a" dependencies = [ "arboard", "egui", @@ -1201,6 +1249,8 @@ dependencies = [ [[package]] name = "egui_extras" version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f698f685bb0ad39e87109e2f695ded0bccde77d5d40bbf7590cb5561c1e3039d" dependencies = [ "egui", "image", @@ -1209,6 +1259,8 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad77d4a00402bae9658ee64be148f4b2a0b38e4fc7874970575ca01ed1c5b75d" dependencies = [ "bytemuck", "egui", @@ -1228,6 +1280,8 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "emath" version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9542a40106fdba943a055f418d1746a050e1a903a049b030c2b097d4686a33cf" dependencies = [ "bytemuck", ] @@ -1284,6 +1338,8 @@ 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", @@ -1766,48 +1822,6 @@ dependencies = [ "gl_generator", ] -[[package]] -name = "gupax" -version = "0.1.0" -dependencies = [ - "anyhow", - "arti-client", - "arti-hyper", - "bytes", - "chrono", - "dirs", - "eframe", - "egui", - "egui_extras", - "env_logger 0.9.1", - "figment", - "flate2", - "hex-literal", - "hyper", - "hyper-tls", - "image", - "log", - "monero", - "num-format", - "num_cpus", - "rand 0.8.5", - "regex", - "reqwest", - "rusqlite", - "serde", - "serde_json", - "sha2 0.10.6", - "tar", - "tls-api", - "tls-api-native-tls", - "tokio", - "toml", - "tor-rtcompat", - "walkdir", - "winres", - "zip", -] - [[package]] name = "h2" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index e5fa50a..088c556 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,9 @@ [package] -name = "gupax" +name = "Gupax" version = "0.1.0" +authors = ["hinto-janaiyo "] +description = "GUI for P2Pool+XMRig" +documentation = "https://github.com/hinto-janaiyo/gupax" edition = "2021" [dependencies] @@ -10,17 +13,18 @@ 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_glow = { path = "external/egui/crates/egui_glow"} +#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" @@ -61,6 +65,5 @@ winres = "0.1.12" # For macOS build (cargo-bundle) [package.metadata.bundle] -identifier = "io.github.hinto-janaiyo.gupax" -icon = ["images/png/icon@2x.png"] -short_description = "GUI for P2Pool+XMRig" +identifier = "com.github.hinto-janaiyo.gupax" +icon = ["images/icons/icon@2x.png"] diff --git a/README.md b/README.md index 92fa0cb..f3eec8d 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Windows/macOS/Linux: ``` cargo build --release ``` -On macOS, if you want the binary to have an icon in `Finder`, you must install [`cargo-bundle`](https://github.com/burtonageo/cargo-bundle) and compile with: +On macOS, if you want the binary to have an icon in `Finder`, you must install [`cargo-bundle`](https://github.com/burtonageo/cargo-bundle) and compile uwith: ``` cargo bundle --release ``` diff --git a/src/README.md b/src/README.md index 29925f6..67fcfee 100644 --- a/src/README.md +++ b/src/README.md @@ -57,6 +57,6 @@ Every frame, the max available `[width, height]` are calculated, and those are u Main [App] outer frame (default: [1280.0, 720.0]) ├─ Inner frame (1264.0, 704.0) ├─ TopPanel = [width: (max-90.0)/5.0, height: max/10.0] - ├─ BottomPanel = [width: max, height: max/15.0] + ├─ BottomPanel = [width: max, height: max/18.0] ├─ CentralPanel = [width: (max/8.0), height: the rest ``` diff --git a/src/constants.rs b/src/constants.rs index 0a7765f..bedc9ae 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -96,8 +96,6 @@ r#"USAGE: gupax [--flags] -r | --reset Reset all Gupax configuration/state -f | --ferris Print an extremely cute crab"#; pub const ARG_COPYRIGHT: &'static str = -r#"Gupax, P2Pool, and XMRig are licensed under GPLv3. -For more information, see here: - - https://github.com/hinto-janaiyo/gupax - - https://github.com/SChernykh/p2pool - - https://github.com/xmrig/xmrig"#; +r#"Gupax is licensed under GPLv3. +For more information, see link below: +"#; diff --git a/src/gupax.rs b/src/gupax.rs index 8c92d29..04efe93 100644 --- a/src/gupax.rs +++ b/src/gupax.rs @@ -51,7 +51,7 @@ impl Gupax { info!("Spawning update thread..."); 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); }, _ => { @@ -87,13 +87,13 @@ impl Gupax { ui.horizontal(|ui| { ui.group(|ui| { let width = (width - SPACE*9.8)/5.0; - let height = height/2.0; + let height = height/2.5; let mut style = (*ctx.style()).clone(); style.spacing.icon_width_inner = width / 6.0; style.spacing.icon_width = width / 4.0; style.spacing.icon_spacing = 20.0; ctx.set_style(style); - let height = height/2.0; + let height = height/2.5; 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); diff --git a/src/main.rs b/src/main.rs index 32832b7..8a4d7ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,7 +85,7 @@ pub struct App { // Static stuff now: Instant, // Internal timer exe: String, // Path for [Gupax] binary - tmp: String, // Tmp folder for updates, random every update + dir: String, // Directory [Gupax] binary is in resolution: Vec2, // Frame resolution os: &'static str, // OS version: String, // Gupax version @@ -115,7 +115,7 @@ impl App { node: Arc::new(Mutex::new(NodeStruct::default())), og: Arc::new(Mutex::new(State::default())), state: State::default(), - update: Arc::new(Mutex::new(Update::new(PathBuf::new(), PathBuf::new(), true))), + update: Arc::new(Mutex::new(Update::new(String::new(), PathBuf::new(), PathBuf::new(), true))), diff: false, p2pool: false, xmrig: false, @@ -123,7 +123,7 @@ impl App { reset: false, now: Instant::now(), exe: "".to_string(), - tmp: "".to_string(), + dir: "".to_string(), resolution: Vec2::new(1280.0, 720.0), os: OS, version: format!("{}", GUPAX_VERSION), @@ -132,12 +132,16 @@ impl App { }; // Apply arg state let mut app = parse_args(app); - // Get exe path + random tmp folder - app.exe = match get_exe_dir() { + // Get exe path + app.exe = match get_exe() { Ok(exe) => exe, Err(err) => { panic_main(err.to_string()); exit(1); }, }; - app.tmp = get_rand_tmp(&app.exe); + // Get exe directory path + app.dir = match get_exe_dir() { + Ok(dir) => dir, + Err(err) => { panic_main(err.to_string()); exit(1); }, + }; // Read disk state if no [--reset] arg if app.reset == false { app.og = match State::get() { @@ -157,7 +161,7 @@ impl App { 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.update = Arc::new(Mutex::new(Update::new(app.exe.clone(), p2pool_path, xmrig_path, tor))); app } } @@ -264,7 +268,7 @@ fn parse_args(mut app: App) -> App { match arg.as_str() { "-h"|"--help" => { println!("{}", ARG_HELP); exit(0); }, "-v"|"--version" => { - println!("Gupax | {}\nP2Pool | {}\nXMRig | {}\n\nOS: [{}], Commit: [{}]\n\n{}", GUPAX_VERSION, P2POOL_VERSION, XMRIG_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT); + println!("Gupax {} (OS: {}, Commit: {})\n\n{}", GUPAX_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT); exit(0); }, "-f"|"--ferris" => { println!("{}", FERRIS); exit(0); }, @@ -298,25 +302,12 @@ pub fn get_exe_dir() -> Result { } } -pub fn get_rand_tmp(path: &String) -> String { - use rand::{thread_rng, Rng}; - use rand::distributions::Alphanumeric; - let rand: String = thread_rng() - .sample_iter(&Alphanumeric) - .take(10) - .map(char::from) - .collect(); - let path = path.to_string() + "/gupax_tmp_" + &rand; - info!("Generated rand_tmp ... {}", path); - 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_") { + if ! entry.path().is_dir() { continue } + if entry.file_name().to_str().ok_or(anyhow::Error::msg("Basename failed"))?.starts_with("gupax_update_") { let path = entry.path(); match std::fs::remove_dir_all(&path) { Ok(_) => info!("Remove [{}] ... OK", path.display()), @@ -431,13 +422,13 @@ impl eframe::App for App { // Close confirmation. if self.quit { // If [ask_before_quit == true] - if self.state.gupax.ask_before_quit { + if self.og.lock().unwrap().gupax.ask_before_quit { egui::TopBottomPanel::bottom("quit").show(ctx, |ui| { let width = self.width; let height = self.height/8.0; ui.group(|ui| { if ui.add_sized([width, height], egui::Button::new("Yes")).clicked() { - if self.state.gupax.save_before_quit { + if self.og.lock().unwrap().gupax.save_before_quit { if self.diff { info!("Saving before quit..."); match self.state.save() { @@ -461,15 +452,14 @@ impl eframe::App for App { let ten = height/10.0; // Detect processes or update ui.add_space(ten); - // || self.update.updating - if self.p2pool || self.xmrig { + if *self.update.lock().unwrap().updating.lock().unwrap() || self.p2pool || self.xmrig { ui.add_sized([width, height/4.0], Label::new("Are you sure you want to quit?")); -// if self.update.updating { ui.add_sized([width, ten], Label::new("Update is in progress...!")); } + if *self.update.lock().unwrap().updating.lock().unwrap() { ui.add_sized([width, ten], Label::new("Update is in progress...!")); } if self.p2pool { ui.add_sized([width, ten], Label::new("P2Pool is online...!")); } if self.xmrig { ui.add_sized([width, ten], Label::new("XMRig is online...!")); } // Else, just quit } else { - if self.state.gupax.save_before_quit { + if self.og.lock().unwrap().gupax.save_before_quit { if self.diff { info!("Saving before quit..."); match self.state.save() { @@ -486,7 +476,7 @@ impl eframe::App for App { }); // Else, quit (save if [save_before_quit == true] } else { - if self.state.gupax.save_before_quit { + if self.og.lock().unwrap().gupax.save_before_quit { if self.diff { info!("Saving before quit..."); match self.state.save() { @@ -534,7 +524,7 @@ impl eframe::App for App { // Bottom: app info + state/process buttons egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| { let width = self.width/8.0; - let height = self.height/15.0; + let height = self.height/18.0; ui.style_mut().override_text_style = Some(Name("Bottom".into())); ui.horizontal(|ui| { ui.group(|ui| { diff --git a/src/state.rs b/src/state.rs index 9cae04d..d246f63 100644 --- a/src/state.rs +++ b/src/state.rs @@ -96,7 +96,7 @@ impl State { // Windows | {FOLDERID_RoamingAppData} | C:\Users\Alice\AppData\Roaming let mut path = match dirs::data_dir() { Some(mut path) => { - path.push(DIRECTORY); + path.push(STATE_DIRECTORY); info!("OS data path ... OK"); path }, @@ -104,7 +104,7 @@ impl State { }; // Create directory fs::create_dir_all(&path)?; - path.push(FILENAME); + path.push(STATE_FILE); info!("TOML path ... {}", path.display()); Ok(path) } @@ -255,27 +255,24 @@ impl From for TomlError { } //---------------------------------------------------------------------------------------------------- Const -const FILENAME: &'static str = "gupax.toml"; +// State file +const STATE_FILE: &'static str = "gupax.toml"; const ERROR: &'static str = "TOML Error"; const PATH_ERROR: &'static str = "PATH for state directory could not be not found"; #[cfg(target_os = "windows")] -const DIRECTORY: &'static str = "Gupax"; +const STATE_DIRECTORY: &'static str = "Gupax"; #[cfg(target_os = "macos")] -const DIRECTORY: &'static str = "Gupax"; +const STATE_DIRECTORY: &'static str = "com.github.hinto-janaiyo.gupax"; #[cfg(target_os = "linux")] -const DIRECTORY: &'static str = "gupax"; +const STATE_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"; -#[cfg(target_os = "linux")] +#[cfg(target_family = "unix")] 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"; -#[cfg(target_os = "linux")] +#[cfg(target_family = "unix")] pub const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig"; //---------------------------------------------------------------------------------------------------- Error Enum diff --git a/src/update.rs b/src/update.rs index 8a0f085..ba05425 100644 --- a/src/update.rs +++ b/src/update.rs @@ -35,6 +35,7 @@ use crate::update::Name::*; use hyper::{Client,Body,Request}; use hyper::header::HeaderValue; use hyper_tls::HttpsConnector; +use hyper::header::LOCATION; use log::*; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -55,18 +56,17 @@ use std::os::unix::fs::OpenOptionsExt; //---------------------------------------------------------------------------------------------------- Constants // Package naming schemes: -// gupax | gupax-vX.X.X-(windows|macos|linux)-x64.(zip|tar.gz) +// gupax | gupax-vX.X.X-(windows|macos|linux)-x64(standalone|bundle).(zip|tar.gz) // p2pool | p2pool-vX.X.X-(windows|macos|linux)-x64.(zip|tar.gz) // xmrig | xmrig-X.X.X-(msvc-win64|macos-x64|linux-static-x64).(zip|tar.gz) // // 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 +// Example: https://github.com/hinto-janaiyo/gupax/releases/download/v0.0.1/gupax-v0.0.1-linux-standalone-x64.tar.gz // // Exceptions (there are always exceptions...): // - XMRig doesn't have a [v], so it is [xmrig-6.18.0-...] // - XMRig separates the hash and signature // - P2Pool hashes are in UPPERCASE -// - Gupax will be downloaded as a standalone binary (no decompression/extraction needed) const GUPAX_METADATA: &'static str = "https://api.github.com/repos/hinto-janaiyo/gupax/releases/latest"; const P2POOL_METADATA: &'static str = "https://api.github.com/repos/SChernykh/p2pool/releases/latest"; @@ -85,21 +85,21 @@ const P2POOL_HASH: &'static str = "sha256sums.txt.asc"; const XMRIG_HASH: &'static str = "SHA256SUMS"; #[cfg(target_os = "windows")] -const GUPAX_EXTENSION: &'static str = "-windows-x64-standalone.exe"; +const GUPAX_EXTENSION: &'static str = "-windows-x64-standalone.zip"; #[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-x64-standalone"; +const GUPAX_EXTENSION: &'static str = "-macos-x64-standalone.tar.gz"; #[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-x64-standalone"; +const GUPAX_EXTENSION: &'static str = "-linux-x64-standalone.tar.gz"; #[cfg(target_os = "linux")] const P2POOL_EXTENSION: &'static str = "-linux-x64.tar.gz"; #[cfg(target_os = "linux")] @@ -107,23 +107,17 @@ 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")] +#[cfg(target_family = "unix")] 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")] +#[cfg(target_family = "unix")] 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")] +#[cfg(target_family = "unix")] const XMRIG_BINARY: &'static str = "xmrig"; // Some fake Curl/Wget user-agents because GitHub API requires one and a Tor browser @@ -235,9 +229,9 @@ pub struct Update { impl Update { // Takes in current paths from [State] - pub fn new(path_p2pool: PathBuf, path_xmrig: PathBuf, tor: bool) -> Self { + pub fn new(path_gupax: String, path_p2pool: PathBuf, path_xmrig: PathBuf, tor: bool) -> Self { Self { - path_gupax: crate::get_exe().unwrap(), + path_gupax, path_p2pool: path_p2pool.display().to_string(), path_xmrig: path_xmrig.display().to_string(), tmp_dir: "".to_string(), @@ -260,9 +254,9 @@ impl Update { .collect(); let base = crate::get_exe_dir()?; #[cfg(target_os = "windows")] - let tmp_dir = format!("{}{}{}{}", base, r"\gupax_tmp_", rand_string, r"\"); + let tmp_dir = format!("{}{}{}{}", base, r"\gupax_update_", rand_string, r"\"); #[cfg(target_family = "unix")] - let tmp_dir = format!("{}{}{}{}", base, "/gupax_tmp_", rand_string, "/"); + let tmp_dir = format!("{}{}{}{}", base, "/gupax_update_", rand_string, "/"); info!("Update | Temporary directory ... {}", tmp_dir); Ok(tmp_dir) } @@ -346,7 +340,8 @@ impl Update { } let prog = *update.lock().unwrap().prog.lock().unwrap(); info!("Update | {}", update.lock().unwrap().msg.lock().unwrap()); - let client = Self::get_client(update.lock().unwrap().tor).await?; + let tor = update.lock().unwrap().tor; + let client = Self::get_client(tor).await?; *update.lock().unwrap().prog.lock().unwrap() += 5.0; info!("Update | Init ... OK ... {}%", prog); @@ -490,14 +485,10 @@ impl Update { 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 + // Example: https://github.com/hinto-janaiyo/gupax/releases/download/v0.0.1/gupax-v0.0.1-linux-x64-standalone // XMRig doesn't have a [v], so slice it out if pkg.name == Name::Xmrig { link = pkg.link_prefix.to_string() + &version + &pkg.link_suffix + &version[1..] + &pkg.link_extension; - // TODO FIX ME - // This is temp link for v0.0.1 of [Gupax] - } else if pkg.name == Name::Gupax { - link = "https://github.com/hinto-janaiyo/gupax/releases/download/v0.0.1/gupax-v0.0.1-linux-x64".to_string() } else { link = pkg.link_prefix.to_string() + &version + &pkg.link_suffix + &version + &pkg.link_extension; } @@ -549,18 +540,15 @@ impl Update { *update.lock().unwrap().msg.lock().unwrap() = format!("{}{}", MSG_EXTRACT, new_pkgs); info!("Update | {}", EXTRACT); for pkg in vec4.iter() { - if pkg.name == Name::Gupax { - let tmp = tmp_dir.to_owned() + GUPAX_BINARY; - #[cfg(target_family = "unix")] - 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")] - tar::Archive::new(flate2::read::GzDecoder::new(pkg.bytes.lock().unwrap().as_ref())).unpack(tmp)?; + let tmp; + match pkg.name { + Name::Gupax => tmp = tmp_dir.to_owned() + GUPAX_BINARY, + _ => 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")] + tar::Archive::new(flate2::read::GzDecoder::new(pkg.bytes.lock().unwrap().as_ref())).unpack(tmp)?; *update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round(); info!("Update | {} ... OK", pkg.name); } @@ -577,18 +565,24 @@ impl Update { // Just in case, create all folders for entry in WalkDir::new(tmp_dir.clone()) { let entry = entry?.clone(); + // If not a file, continue + if ! entry.file_type().is_file() { continue } let basename = entry.file_name().to_str().ok_or(anyhow::Error::msg("WalkDir basename failed"))?; match basename { 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. + let path = update.lock().unwrap().path_gupax.clone(); #[cfg(target_os = "windows")] - std::fs::rename(&path, tmp_dir.clone() + "gupax_old.exe")?; + let tmp_windows = tmp_dir.clone() + "gupax_old.exe"; + #[cfg(target_os = "windows")] + info!("Update | WINDOWS ONLY ... Moving [{}] -> [{}]", &path, tmp_windows); + #[cfg(target_os = "windows")] + std::fs::rename(&path, tmp_windows)?; + info!("Update | Moving [{}] -> [{}]", entry.path().display(), path); std::fs::rename(entry.path(), path)?; *update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round(); }, @@ -693,7 +687,7 @@ impl Pkg { //---------------------------------------------------------------------------------------------------- Pkg functions // Generate fake [User-Agent] HTTP header - pub fn get_user_agent() -> &'static str { + fn get_user_agent() -> &'static str { let rand = thread_rng().gen_range(0..50); let user_agent = FAKE_USER_AGENT[rand]; info!("Update | Randomly selecting User-Agent ({}/50) ... {}", rand, user_agent); @@ -701,7 +695,7 @@ impl Pkg { } // Generate GET request based off input URI + fake user agent - pub fn get_request(link: String, user_agent: &'static str) -> Result, anyhow::Error> { + fn get_request(link: String, user_agent: &'static str) -> Result, anyhow::Error> { let request = Request::builder() .method("GET") .uri(link) @@ -712,8 +706,8 @@ impl Pkg { // Get metadata using [Generic hyper::client] & [Request] // and change [version, prog] under an Arc - pub async fn get_metadata(name: Name, new_ver: Arc>, client: Client, link: String, user_agent: &'static str) -> Result<(), Error> - where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { + async fn get_metadata(name: Name, new_ver: Arc>, client: Client, link: String, user_agent: &'static str) -> Result<(), Error> + where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { let request = Pkg::get_request(link.clone(), user_agent)?; let mut response = client.request(request).await?; let body = hyper::body::to_bytes(response.body_mut()).await?; @@ -724,15 +718,17 @@ impl Pkg { // Takes a [Request], fills the appropriate [Pkg] // [bytes] field with the [Archive/Standalone] - pub async fn get_bytes(name: Name, bytes: Arc>, client: Client, link: String, user_agent: &'static str) -> Result<(), anyhow::Error> - where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { + async fn get_bytes(name: Name, bytes: Arc>, client: Client, link: String, user_agent: &'static str) -> Result<(), anyhow::Error> + where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { + let request = Self::get_request(link.clone(), user_agent)?; + let mut response = client.request(request).await?; // 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 request = Self::get_request(link.clone(), user_agent)?; - let response = client.request(request).await?; - let request = Self::get_request(response.headers().get(hyper::header::LOCATION).unwrap().to_str()?.to_string(), user_agent)?; - let response = client.request(request).await?; + if response.headers().contains_key(LOCATION) { + let request = Self::get_request(response.headers().get(LOCATION).unwrap().to_str()?.to_string(), user_agent)?; + response = client.request(request).await?; + } let body = hyper::body::to_bytes(response.into_body()).await?; *bytes.lock().unwrap() = body; Ok(())