mirror of
https://github.com/hinto-janai/gupax.git
synced 2024-11-17 01:37:52 +00:00
p2pool/xmrig: handle custom arg [--no-color], API ip/port/path
This commit is contained in:
parent
79b0361152
commit
9eb49b6dbd
7 changed files with 67 additions and 38 deletions
|
@ -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";
|
||||
|
|
19
src/disk.rs
19
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<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)) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
25
src/main.rs
25
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<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),
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue