p2pool/xmrig: handle custom arg [--no-color], API ip/port/path

This commit is contained in:
hinto-janaiyo 2022-12-13 12:44:57 -05:00
parent 79b0361152
commit 9eb49b6dbd
No known key found for this signature in database
GPG key ID: B1C5A64B80691E45
7 changed files with 67 additions and 38 deletions

View file

@ -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 <PATH>] & [--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 <IP>] & [--http-port <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";

View file

@ -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<PathBuf, TomlError> {
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)) },
}
}
}

View file

@ -322,10 +322,10 @@ impl Helper {
pub fn start_p2pool(helper: &Arc<Mutex<Self>>, 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<Mutex<Self>>, state: &crate::disk::P2pool, path: &std::path::PathBuf) -> Vec<String> {
pub fn build_p2pool_args_and_mutate_img(helper: &Arc<Mutex<Self>>, state: &crate::disk::P2pool, path: &std::path::PathBuf) -> (Vec<String>, 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<Mutex<Process>>, gui_api: Arc<Mutex<PubP2poolApi>>, pub_api: Arc<Mutex<PubP2poolApi>>, priv_api: Arc<Mutex<PrivP2poolApi>>, args: Vec<String>, mut path: std::path::PathBuf) {
fn spawn_p2pool_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubP2poolApi>>, pub_api: Arc<Mutex<PubP2poolApi>>, priv_api: Arc<Mutex<PrivP2poolApi>>, args: Vec<String>, 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<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) -> (Vec<String>, 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.

View file

@ -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<Mutex>'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),
};

View file

@ -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

View file

@ -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;
});
}
}

View file

@ -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