From 9eb49b6dbd08c9f2fc3e5060f16094ecc1c6cdb1 Mon Sep 17 00:00:00 2001 From: hinto-janaiyo Date: Tue, 13 Dec 2022 12:44:57 -0500 Subject: [PATCH] p2pool/xmrig: handle custom arg [--no-color], API ip/port/path --- src/constants.rs | 12 ++++++++++-- src/disk.rs | 19 +++++++++++++------ src/helper.rs | 42 ++++++++++++++++++++++-------------------- src/main.rs | 25 ++++++++++++++++++------- src/p2pool.rs | 2 +- src/sudo.rs | 3 ++- src/xmrig.rs | 2 +- 7 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index bca5a3a..d61170b 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -198,7 +198,11 @@ pub const P2POOL_AUTO_SELECT: &str = "Automatically select the fastest community pub const P2POOL_SELECT_FASTEST: &str = "Select the fastest community Monero node"; pub const P2POOL_PING: &str = "Ping the built-in community Monero nodes"; pub const P2POOL_ADDRESS: &str = "You must use a primary Monero address to mine on P2Pool (starts with a 4). It is highly recommended to create a new wallet since addresses are public on P2Pool!"; -pub const P2POOL_ARGUMENTS: &str = "Start P2Pool with these arguments and override all below settings; If the [--data-api] & [--local-api] flag is not given, Gupax will append it to the arguments automatically so that the [Status] tab can work"; +pub const P2POOL_INPUT: &str = "Send a command to P2Pool"; +pub const P2POOL_ARGUMENTS: &str = +r#"WARNING: Use [--no-color] and make sure to set [--data-api ] & [--local-api] so that the [Status] can work! + +Start P2Pool with these arguments and override all below settings"#; pub const P2POOL_SIMPLE: &str = r#"Use simple P2Pool settings: - Remote community Monero node @@ -239,7 +243,11 @@ r#"Use advanced XMRig settings: - TLS setting - Keepalive setting - Custom HTTP API IP/Port"#; -pub const XMRIG_ARGUMENTS: &str = "Start XMRig with these arguments and override all below settings; If the [http-api] options are not set, Gupax will append it to the arguments automatically so that the [Status] tab can work"; +pub const XMRIG_INPUT: &str = "Send a command to XMRig"; +pub const XMRIG_ARGUMENTS: &str = +r#"WARNING: Use [--no-color] and make sure to set [--http-host ] & [--http-port ] so that the [Status] can work! + +Start XMRig with these arguments and override all below settings"#; pub const XMRIG_ADDRESS: &str = "Specify which Monero address to payout to. This does nothing if mining to P2Pool since the address being payed out to will be the one P2Pool started with. This doubles as a rig identifier for P2Pool and some pools."; pub const XMRIG_NAME: &str = "Add a unique name to identify this pool; Only [A-Za-z0-9-_] and spaces allowed; Max length = 30 characters"; pub const XMRIG_IP: &str = "Specify the pool IP to connect to with XMRig; It must be a valid IPv4 address or a valid domain name; Max length = 255 characters"; diff --git a/src/disk.rs b/src/disk.rs index 2e420d4..7f3c3ec 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -119,6 +119,13 @@ pub fn print_dash(toml: &str) { info!("{}", HORIZONTAL); } +// Write str to console with [debug!] surrounded by "---" +pub fn print_dash_debug(toml: &str) { + info!("{}", HORIZONTAL); + for i in toml.lines() { debug!("{}", i); } + info!("{}", HORIZONTAL); +} + // Turn relative paths into absolute paths pub fn into_absolute_path(path: String) -> Result { let path = PathBuf::from(path); @@ -395,11 +402,11 @@ impl Node { // Save [Node] onto disk file [node.toml] pub fn save(vec: &[(String, Self)], path: &PathBuf) -> Result<(), TomlError> { - info!("Node | Saving to disk..."); + info!("Node | Saving to disk ... [{}]", path.display()); let string = Self::to_string(vec)?; match fs::write(path, string) { - Ok(_) => { info!("TOML save ... OK"); Ok(()) }, - Err(err) => { error!("Couldn't overwrite TOML file"); Err(TomlError::Io(err)) }, + Ok(_) => { info!("Node | Save ... OK"); Ok(()) }, + Err(err) => { error!("Node | Couldn't overwrite file"); Err(TomlError::Io(err)) }, } } @@ -497,11 +504,11 @@ impl Pool { } pub fn save(vec: &[(String, Self)], path: &PathBuf) -> Result<(), TomlError> { - info!("Pool | Saving to disk..."); + info!("Pool | Saving to disk ... [{}]", path.display()); let string = Self::to_string(vec)?; match fs::write(path, string) { - Ok(_) => { info!("TOML save ... OK"); Ok(()) }, - Err(err) => { error!("Couldn't overwrite TOML file"); Err(TomlError::Io(err)) }, + Ok(_) => { info!("Pool | Save ... OK"); Ok(()) }, + Err(err) => { error!("Pool | Couldn't overwrite file"); Err(TomlError::Io(err)) }, } } } diff --git a/src/helper.rs b/src/helper.rs index 45692b9..2e5dbf4 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -322,10 +322,10 @@ impl Helper { pub fn start_p2pool(helper: &Arc>, state: &crate::disk::P2pool, path: &std::path::PathBuf) { helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle; - let args = Self::build_p2pool_args_and_mutate_img(helper, state, path); + let (args, api_path) = Self::build_p2pool_args_and_mutate_img(helper, state, path); // Print arguments & user settings to console - crate::disk::print_dash(&format!("P2Pool | Launch arguments: {:#?}", args)); + crate::disk::print_dash(&format!("P2Pool | Launch arguments: {:#?} | API Path: {:#?}", args, api_path)); // Spawn watchdog thread let process = Arc::clone(&helper.lock().unwrap().p2pool); @@ -334,14 +334,14 @@ impl Helper { let priv_api = Arc::clone(&helper.lock().unwrap().priv_api_p2pool); let path = path.clone(); thread::spawn(move || { - Self::spawn_p2pool_watchdog(process, gui_api, pub_api, priv_api, args, path); + Self::spawn_p2pool_watchdog(process, gui_api, pub_api, priv_api, args, path, api_path); }); } // Takes in some [State/P2pool] and parses it to build the actual command arguments. // Returns the [Vec] of actual arguments, and mutates the [ImgP2pool] for the main GUI thread // It returns a value... and mutates a deeply nested passed argument... this is some pretty bad code... - pub fn build_p2pool_args_and_mutate_img(helper: &Arc>, state: &crate::disk::P2pool, path: &std::path::PathBuf) -> Vec { + pub fn build_p2pool_args_and_mutate_img(helper: &Arc>, state: &crate::disk::P2pool, path: &std::path::PathBuf) -> (Vec, PathBuf) { let mut args = Vec::with_capacity(500); let path = path.clone(); let mut api_path = path.clone(); @@ -389,6 +389,7 @@ impl Helper { "--loglevel" => p2pool_image.log_level = arg.to_string(), "--out-peers" => p2pool_image.out_peers = arg.to_string(), "--in-peers" => p2pool_image.in_peers = arg.to_string(), + "--data-api" => api_path = PathBuf::from(arg), _ => (), } args.push(arg.to_string()); @@ -419,11 +420,11 @@ impl Helper { } } } - args + (args, api_path) } // The P2Pool watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works. - fn spawn_p2pool_watchdog(process: Arc>, gui_api: Arc>, pub_api: Arc>, priv_api: Arc>, args: Vec, mut path: std::path::PathBuf) { + fn spawn_p2pool_watchdog(process: Arc>, gui_api: Arc>, pub_api: Arc>, priv_api: Arc>, args: Vec, path: std::path::PathBuf, api_path: std::path::PathBuf) { // 1a. Create PTY debug!("P2Pool | Creating PTY..."); let pty = portable_pty::native_pty_system(); @@ -463,18 +464,15 @@ impl Helper { let output_full = Arc::clone(&process.lock().unwrap().output_full); let output_buf = Arc::clone(&process.lock().unwrap().output_buf); - path.pop(); - path.push(P2POOL_API_PATH); - debug!("P2Pool | Cleaning old API files..."); // Attempt to remove stale API file - match std::fs::remove_file(&path) { + match std::fs::remove_file(&api_path) { Ok(_) => info!("P2Pool | Attempting to remove stale API file ... OK"), Err(e) => warn!("P2Pool | Attempting to remove stale API file ... FAIL ... {}", e), } // Attempt to create a default empty one. use std::io::Write; - if let Ok(_) = std::fs::File::create(&path) { + if let Ok(_) = std::fs::File::create(&api_path) { let text = r#"{"hashrate_15m":0,"hashrate_1h":0,"hashrate_24h":0,"shares_found":0,"average_effort":0.0,"current_effort":0.0,"connections":0}"#; match std::fs::write(&path, text) { Ok(_) => info!("P2Pool | Creating default empty API file ... OK"), @@ -570,7 +568,7 @@ impl Helper { // Read API file into string debug!("P2Pool Watchdog | Attempting API file read"); - if let Ok(string) = PrivP2poolApi::read_p2pool_api(&path) { + if let Ok(string) = PrivP2poolApi::read_p2pool_api(&api_path) { // Deserialize if let Ok(s) = PrivP2poolApi::str_to_priv_p2pool_api(&string) { // Update the structs. @@ -685,7 +683,8 @@ impl Helper { // It returns a value... and mutates a deeply nested passed argument... this is some pretty bad code... pub fn build_xmrig_args_and_mutate_img(helper: &Arc>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) -> (Vec, String) { let mut args = Vec::with_capacity(500); - let mut api_ip_port = String::with_capacity(15); + let mut api_ip = String::with_capacity(15); + let mut api_port = String::with_capacity(5); let path = path.clone(); // The actual binary we're executing is [sudo], technically // the XMRig path is just an argument to sudo, so add it. @@ -712,7 +711,8 @@ impl Helper { threads: state.current_threads.to_string(), url: "127.0.0.1:3333 (Local P2Pool)".to_string(), }; - api_ip_port = "127.0.0.1:18088".to_string(); + api_ip = "127.0.0.1".to_string(); + api_port = "18088".to_string(); // [Advanced] } else { @@ -725,8 +725,10 @@ impl Helper { let mut xmrig_image = lock.img_xmrig.lock().unwrap(); for arg in state.arguments.split_whitespace() { match last { - "--threads" => xmrig_image.threads = arg.to_string(), - "--url" => xmrig_image.url = arg.to_string(), + "--threads" => xmrig_image.threads = arg.to_string(), + "--url" => xmrig_image.url = arg.to_string(), + "--http-host" => api_ip = arg.to_string(), + "--http-port" => api_port = arg.to_string(), _ => (), } args.push(arg.to_string()); @@ -734,8 +736,9 @@ impl Helper { } // Else, build the argument } else { - let api_ip = if state.api_ip == "localhost" || state.api_ip.is_empty() { "127.0.0.1" } else { &state.api_ip }; // XMRig doesn't understand [localhost] - let api_port = if state.api_port.is_empty() { "18088" } else { &state.api_port }; + // XMRig doesn't understand [localhost] + api_ip = if state.api_ip == "localhost" || state.api_ip.is_empty() { "127.0.0.1".to_string() } else { state.api_ip.to_string() }; + api_port = if state.api_port.is_empty() { "18088".to_string() } else { state.api_port.to_string() }; let url = format!("{}:{}", state.selected_ip, state.selected_port); // Combine IP:Port into one string args.push("--user".to_string()); args.push(state.address.clone()); // Wallet args.push("--threads".to_string()); args.push(state.current_threads.to_string()); // Threads @@ -751,10 +754,9 @@ impl Helper { url, threads: state.current_threads.to_string(), }; - api_ip_port = format!("{}:{}", api_ip, api_port); } } - (args, api_ip_port) + (args, format!("{}:{}", api_ip, api_port)) } // We actually spawn [sudo] on Unix, with XMRig being the argument. diff --git a/src/main.rs b/src/main.rs index 9b83b0e..16c5a90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -289,7 +289,7 @@ impl App { app.og = Arc::new(Mutex::new(app.state.clone())); // Read node list debug!("App Init | Reading node list..."); - app.og_node_vec = match Node::get(&app.node_path) { + app.node_vec = match Node::get(&app.node_path) { Ok(toml) => toml, Err(err) => { error!("Node ... {}", err); @@ -304,9 +304,12 @@ impl App { Node::new_vec() }, }; + app.og_node_vec = app.node_vec.clone(); + debug!("Node Vec:"); + debug!("{:#?}", app.node_vec); // Read pool list debug!("App Init | Reading pool list..."); - app.og_pool_vec = match Pool::get(&app.pool_path) { + app.pool_vec = match Pool::get(&app.pool_path) { Ok(toml) => toml, Err(err) => { error!("Pool ... {}", err); @@ -321,7 +324,10 @@ impl App { Pool::new_vec() }, }; - app.pool_vec = app.og_pool_vec.clone(); + app.og_pool_vec = app.pool_vec.clone(); + debug!("Pool Vec:"); + debug!("{:#?}", app.pool_vec); + //---------------------------------------------------------------------------------------------------- let mut og = app.og.lock().unwrap(); // Lock [og] @@ -1167,6 +1173,7 @@ impl eframe::App for App { let box_width = (ui.available_width()/2.0)-5.0; if (response.lost_focus() && ui.input().key_pressed(Key::Enter)) || ui.add_sized([box_width, height], Button::new("Enter")).on_hover_text(PASSWORD_ENTER).clicked() { + response.request_focus(); if !sudo.testing { SudoState::test_sudo(self.sudo.clone(), &self.helper.clone(), &self.state.xmrig, &self.state.gupax.absolute_xmrig_path); } @@ -1187,13 +1194,17 @@ impl eframe::App for App { return } - // Compare [og == state] and the [node_vec] and enable diff if found. + // Compare [og == state] & [node_vec/pool_vec] and enable diff 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. debug!("App | Checking diff between [og] & [state]"); let og = self.og.lock().unwrap(); - if og.gupax != self.state.gupax || og.p2pool != self.state.p2pool || og.xmrig != self.state.xmrig || self.og_node_vec != self.node_vec { + if og.gupax != self.state.gupax || + og.p2pool != self.state.p2pool || + og.xmrig != self.state.xmrig || + self.og_node_vec != self.node_vec || + self.og_pool_vec != self.pool_vec { self.diff = true; } else { self.diff = false; @@ -1299,11 +1310,11 @@ impl eframe::App for App { self.error_state.set(format!("State file: {}", e), ErrorFerris::Error, ErrorButtons::Okay); }, }; - match Node::save(&self.og_node_vec, &self.node_path) { + match Node::save(&self.node_vec, &self.node_path) { Ok(_) => self.og_node_vec = self.node_vec.clone(), Err(e) => self.error_state.set(format!("Node list: {}", e), ErrorFerris::Error, ErrorButtons::Okay), }; - match Pool::save(&self.og_pool_vec, &self.pool_path) { + match Pool::save(&self.pool_vec, &self.pool_path) { Ok(_) => self.og_pool_vec = self.pool_vec.clone(), Err(e) => self.error_state.set(format!("Pool list: {}", e), ErrorFerris::Error, ErrorButtons::Okay), }; diff --git a/src/p2pool.rs b/src/p2pool.rs index 7448aed..aed5a28 100644 --- a/src/p2pool.rs +++ b/src/p2pool.rs @@ -59,7 +59,7 @@ impl P2pool { }); }); ui.separator(); - let response = ui.add_sized([width, text_edit], TextEdit::hint_text(TextEdit::singleline(buffer), r#"Type a command (e.g "help" or "status") and press Enter"#)); + let response = ui.add_sized([width, text_edit], TextEdit::hint_text(TextEdit::singleline(buffer), r#"Type a command (e.g "help" or "status") and press Enter"#)).on_hover_text(P2POOL_INPUT); // If the user pressed enter, dump buffer contents into the process STDIN if response.lost_focus() && ui.input().key_pressed(egui::Key::Enter) { response.request_focus(); // Get focus back diff --git a/src/sudo.rs b/src/sudo.rs index 1228c0f..db536fe 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -167,10 +167,11 @@ impl SudoState { _ => crate::helper::Helper::start_xmrig(&helper, &xmrig, &path, Arc::clone(&state)), } } else { - state.lock().unwrap().msg = "Incorrect password!".to_string(); + state.lock().unwrap().msg = "Incorrect password! (or sudo timeout)".to_string(); Self::wipe(&state); } state.lock().unwrap().signal = ProcessSignal::None; + state.lock().unwrap().testing = false; }); } } diff --git a/src/xmrig.rs b/src/xmrig.rs index d133547..273e390 100644 --- a/src/xmrig.rs +++ b/src/xmrig.rs @@ -60,7 +60,7 @@ impl Xmrig { }); }); ui.separator(); - let response = ui.add_sized([width, text_edit], TextEdit::hint_text(TextEdit::singleline(buffer), r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#)); + let response = ui.add_sized([width, text_edit], TextEdit::hint_text(TextEdit::singleline(buffer), r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#)).on_hover_text(XMRIG_INPUT); // If the user pressed enter, dump buffer contents into the process STDIN if response.lost_focus() && ui.input().key_pressed(egui::Key::Enter) { response.request_focus(); // Get focus back