diff --git a/CHANGELOG.md b/CHANGELOG.md index fc1d916..d6cc1dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,19 @@ # v1.0.0 -## Updates -* +[Download here](https://github.com/hinto-janaiyo/gupax/releases/latest) or at https://gupax.io. -## Fixes -* +[Watch a 3-minute setup guide here.](https://github.com/hinto-janaiyo/gupax#How-To) + +## Changes +* Optimized PTY output handling (less memory usage) +* Added `Select random node`, `<- Last`, `Next ->` buttons in `P2Pool Simple` +* Added `Debug Info` screen (`D` key on `About` tab) +* Added Linux distro build profile +* Added `21` unit tests +* Misc fixes/optimizations + +## Bundled Versions +* [`P2Pool v2.6`](https://github.com/SChernykh/p2pool/releases/tag/v2.6) +* [`XMRig v6.18.1`](https://github.com/xmrig/xmrig/releases/tag/v6.18.1) --- diff --git a/README.md b/README.md index 790e5a6..f3f2080 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -# WORK IN PROGRESS - ETA: December 25th, 2022 ![banner.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/banner.png) Gupax is a (Windows|macOS|Linux) GUI for mining [**Monero**](https://github.com/monero-project/monero) on [**P2Pool**](https://github.com/SChernykh/p2pool), using [**XMRig**](https://github.com/xmrig/xmrig). @@ -481,6 +480,8 @@ After that, run: cargo build --release ``` +The Linux release tars come with another file next to the Gupax binary: `Gupax.AppImage`. ***This is not an actual [AppImage](https://en.wikipedia.org/wiki/AppImage)***, it is just a text file that contains: `./gupax`. This allows users to double-click and execute Gupax in file explorers like `Nautilus` in Ubuntu/Debian. + ### Building for a distribution Gupax has a build flag for use as a package in a Linux distribution: ``` diff --git a/src/constants.rs b/src/constants.rs index e69e509..a1b0f6f 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -16,8 +16,8 @@ // along with this program. If not, see . pub const GUPAX_VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); // e.g: Gupax v1.0.0 -pub const P2POOL_VERSION: &str = "v2.5"; -pub const XMRIG_VERSION: &str = "v6.18.0"; +pub const P2POOL_VERSION: &str = "v2.6"; +pub const XMRIG_VERSION: &str = "v6.18.1"; pub const COMMIT: &str = include_str!("../.git/refs/heads/main"); // e.g: Gupax_v1_0_0 // Would have been [Gupax_v1.0.0] but P2Pool truncates everything after [.] @@ -73,7 +73,7 @@ r#"*---------------------------------------* pub const P2POOL_API_PATH: &str = r"local\stats"; // The default relative FS path of P2Pool's local API #[cfg(target_family = "unix")] pub const P2POOL_API_PATH: &str = "local/stats"; -pub const XMRIG_API_URI: &str = "/1/summary"; // The default relative URI of XMRig's API +pub const XMRIG_API_URI: &str = "1/summary"; // The default relative URI of XMRig's API // Process state tooltips (online, offline, etc) pub const P2POOL_ALIVE: &str = "P2Pool is online"; diff --git a/src/helper.rs b/src/helper.rs index 42c1906..859684e 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -360,7 +360,6 @@ impl Helper { out_peers: "10".to_string(), in_peers: "10".to_string(), }; - api_path.push(P2POOL_API_PATH); // [Advanced] } else { @@ -410,9 +409,9 @@ impl Helper { out_peers: state.out_peers.to_string(), in_peers: state.in_peers.to_string(), }; - api_path.push(P2POOL_API_PATH); } } + api_path.push(P2POOL_API_PATH); (args, api_path) } @@ -738,11 +737,11 @@ impl Helper { match last { "--threads" => xmrig_image.threads = arg.to_string(), "--url" => xmrig_image.url = arg.to_string(), - "--http-host" => api_ip = arg.to_string(), + "--http-host" => api_ip = if arg == "localhost" { "127.0.0.1".to_string() } else { arg.to_string() }, "--http-port" => api_port = arg.to_string(), _ => (), } - args.push(arg.to_string()); + args.push(if arg == "localhost" { "127.0.0.1".to_string() } else { arg.to_string() }); last = arg; } // Else, build the argument @@ -791,7 +790,7 @@ impl Helper { // The XMRig watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works. // This isn't actually async, a tokio runtime is unfortunately needed because [Hyper] is an async library (HTTP API calls) #[tokio::main] - async fn spawn_xmrig_watchdog(process: Arc>, gui_api: Arc>, pub_api: Arc>, _priv_api: Arc>, args: Vec, path: std::path::PathBuf, sudo: Arc>, api_ip_port: String) { + async fn spawn_xmrig_watchdog(process: Arc>, gui_api: Arc>, pub_api: Arc>, _priv_api: Arc>, args: Vec, path: std::path::PathBuf, sudo: Arc>, mut api_ip_port: String) { // 1a. Create PTY debug!("XMRig | Creating PTY..."); let pty = portable_pty::native_pty_system(); @@ -845,6 +844,11 @@ impl Helper { let client: hyper::Client = hyper::Client::builder().build(hyper::client::HttpConnector::new()); let start = process.lock().unwrap().start; + let api_uri = { + if !api_ip_port.ends_with('/') { api_ip_port.push('/'); } + "http://".to_owned() + &api_ip_port + XMRIG_API_URI + }; + info!("XMRig | Final API URI: {}", api_uri); // Reset stats before loop *pub_api.lock().unwrap() = PubXmrigApi::new(); @@ -959,11 +963,11 @@ impl Helper { // Send an HTTP API request debug!("XMRig Watchdog | Attempting HTTP API request..."); - if let Ok(priv_api) = PrivXmrigApi::request_xmrig_api(client.clone(), &api_ip_port).await { + if let Ok(priv_api) = PrivXmrigApi::request_xmrig_api(client.clone(), &api_uri).await { debug!("XMRig Watchdog | HTTP API request OK, attempting [update_from_priv()]"); PubXmrigApi::update_from_priv(&pub_api, priv_api); } else { - warn!("XMRig Watchdog | Could not send HTTP API request to: {}", api_ip_port); + warn!("XMRig Watchdog | Could not send HTTP API request to: {}", api_uri); } // Sleep (only if 900ms hasn't passed) @@ -1300,11 +1304,11 @@ impl HumanNumber { // The following STDLIB implementation takes [0.003~] seconds to find all matches given a [String] with 30k lines: // let mut n = 0; // for line in P2POOL_OUTPUT.lines() { -// if line.contains("You received a payout of [0-9].[0-9]+ XMR") { n += 1; } +// if line.contains("payout of [0-9].[0-9]+ XMR") { n += 1; } // } // // This regex function takes [0.0003~] seconds (10x faster): -// let regex = Regex::new("You received a payout of [0-9].[0-9]+ XMR").unwrap(); +// let regex = Regex::new("payout of [0-9].[0-9]+ XMR").unwrap(); // let n = regex.find_iter(P2POOL_OUTPUT).count(); // // Both are nominally fast enough where it doesn't matter too much but meh, why not use regex. @@ -1316,7 +1320,7 @@ struct P2poolRegex { impl P2poolRegex { fn new() -> Self { Self { - payout: regex::Regex::new("You received a payout of [0-9].[0-9]+ XMR").unwrap(), + payout: regex::Regex::new("payout of [0-9].[0-9]+ XMR").unwrap(), float: regex::Regex::new("[0-9].[0-9]+").unwrap(), } } @@ -1685,10 +1689,10 @@ impl PrivXmrigApi { } } // Send an HTTP request to XMRig's API, serialize it into [Self] and return it - async fn request_xmrig_api(client: hyper::Client, api_ip_port: &str) -> Result { + async fn request_xmrig_api(client: hyper::Client, api_uri: &str) -> Result { let request = hyper::Request::builder() .method("GET") - .uri("http://".to_string() + api_ip_port + XMRIG_API_URI) + .uri(api_uri) .body(hyper::Body::empty())?; let response = tokio::time::timeout(std::time::Duration::from_millis(500), client.request(request)).await?; let body = hyper::body::to_bytes(response?.body_mut()).await?; @@ -1868,9 +1872,9 @@ mod test { use std::sync::{Arc,Mutex}; let public = Arc::new(Mutex::new(PubP2poolApi::new())); let output_parse = Arc::new(Mutex::new(String::from( - r#"You received a payout of 5.000000000001 XMR in block 1111 - You received a payout of 5.000000000001 XMR in block 1112 - You received a payout of 5.000000000001 XMR in block 1113"# + r#"payout of 5.000000000001 XMR in block 1111 + payout of 5.000000000001 XMR in block 1112 + payout of 5.000000000001 XMR in block 1113"# ))); let output_pub = Arc::new(Mutex::new(String::new())); let elapsed = std::time::Duration::from_secs(60); diff --git a/utils/create_tmp_env.sh b/utils/create_tmp_env.sh new file mode 100755 index 0000000..a9e3c3a --- /dev/null +++ b/utils/create_tmp_env.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Sets up a packaging environment in [/tmp] + +# Make sure we're in the [gupax/utils] directory +set -ex +[[ $PWD = */gupax ]] + +# Make sure the folder doesn't already exist +GIT_COMMIT=$(cat .git/refs/heads/main) +FOLDER="gupax_${GIT_COMMIT}" +[[ ! -e /tmp/${FOLDER} ]] + +mkdir /tmp/${FOLDER} +cp -r utils/* /tmp/${FOLDER}/ +cp CHANGELOG.md /tmp/${FOLDER}/skel/ + +set +ex + +echo +ls --color=always /tmp/${FOLDER} +echo "/tmp/${FOLDER} ... OK" diff --git a/utils/skel/macos/Gupax.app/Gupax b/utils/skel/linux/Gupax.AppImage old mode 100644 new mode 100755 similarity index 100% rename from utils/skel/macos/Gupax.app/Gupax rename to utils/skel/linux/Gupax.AppImage diff --git a/utils/skel/linux/gupax b/utils/skel/linux/gupax old mode 100644 new mode 100755 diff --git a/utils/skel/macos/Gupax.app/Contents/Info.plist b/utils/skel/macos/Gupax.app/Contents/Info.plist new file mode 100755 index 0000000..e69de29 diff --git a/utils/skel/macos/Gupax.app/Contents/MacOS/Gupax b/utils/skel/macos/Gupax.app/Contents/MacOS/Gupax new file mode 100644 index 0000000..e69de29 diff --git a/utils/skel/macos/Gupax.app/Contents/Resources/Gupax.icns b/utils/skel/macos/Gupax.app/Contents/Resources/Gupax.icns new file mode 100755 index 0000000..e69de29