Status Submenu: add macros!()

Writing [a.lock().unwrap().b.lock().unwrap()] sucks, so these are
some macros that are for common situations. This commit also has
a [sed] replace on all previous code that _could_ have been a macro,
which they all are now.

Hopefully nothing breaks :D
This commit is contained in:
hinto-janaiyo 2022-12-28 22:03:45 -05:00
parent 46b528ecbe
commit 19b5a2790b
No known key found for this signature in database
GPG key ID: B1C5A64B80691E45
13 changed files with 438 additions and 306 deletions

View file

@ -482,7 +482,7 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to
The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x.
There are `30` unit tests throughout the codebase files, you should probably run:
There are `34` unit tests throughout the codebase files, you should probably run:
```
cargo test
```

View file

@ -23,6 +23,7 @@
| ferris.rs | Cute crab bytes
| gupax.rs | `Gupax` tab
| helper.rs | The "helper" thread that runs for the entire duration Gupax is alive. All the processing that needs to be done without blocking the main GUI thread runs here, including everything related to handling P2Pool/XMRig
| macros.rs | General `macros!()` used in Gupax
| main.rs | The main `App` struct that holds all data + misc data/functions
| node.rs | Community node ping code for the `P2Pool` simple tab
| p2pool.rs | `P2Pool` tab

View file

@ -47,6 +47,7 @@ use crate::{
gupax::Ratio,
Tab,
xmr::*,
macros::*,
};
use log::*;
@ -213,7 +214,7 @@ impl State {
gupax: Gupax::default(),
p2pool: P2pool::default(),
xmrig: Xmrig::with_threads(max_threads, current_threads),
version: Arc::new(Mutex::new(Version::default())),
version: arc_mut!(Version::default()),
}
}

View file

@ -32,6 +32,7 @@ use crate::{
ErrorState,
Restart,
Tab,
macros::*,
};
use std::{
thread,
@ -55,13 +56,13 @@ pub struct FileWindow {
impl FileWindow {
pub fn new() -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(Self {
arc_mut!(Self {
thread: false,
picked_p2pool: false,
picked_xmrig: false,
p2pool_path: String::new(),
xmrig_path: String::new(),
}))
})
}
}
@ -89,7 +90,7 @@ impl crate::disk::Gupax {
let button = if self.simple { height/5.0 } else { height/15.0 };
let height = if self.simple { height/5.0 } else { height/10.0 };
let width = width - SPACE;
let updating = *update.lock().unwrap().updating.lock().unwrap();
let updating = *lock2!(update,updating);
ui.vertical(|ui| {
// If [Gupax] is being built for a Linux distro,
// disable built-in updating completely.
@ -106,8 +107,8 @@ impl crate::disk::Gupax {
});
ui.vertical(|ui| {
ui.set_enabled(updating);
let prog = *update.lock().unwrap().prog.lock().unwrap();
let msg = format!("{}\n{}{}", *update.lock().unwrap().msg.lock().unwrap(), prog, "%");
let prog = *lock2!(update,prog);
let msg = format!("{}\n{}{}", *lock2!(update,msg), prog, "%");
ui.add_sized([width, height*1.4], Label::new(RichText::text_style(RichText::new(msg), Monospace)));
let height = height/2.0;
if updating {
@ -115,7 +116,7 @@ impl crate::disk::Gupax {
} else {
ui.add_sized([width, height], Label::new("..."));
}
ui.add_sized([width, height], ProgressBar::new(update.lock().unwrap().prog.lock().unwrap().round() / 100.0));
ui.add_sized([width, height], ProgressBar::new(lock2!(update,prog).round() / 100.0));
});
});
@ -160,7 +161,7 @@ impl crate::disk::Gupax {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ✔").color(GREEN))).on_hover_text(P2POOL_PATH_OK);
}
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
ui.set_enabled(!file_window.lock().unwrap().thread);
ui.set_enabled(!lock!(file_window).thread);
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
Self::spawn_file_window_thread(file_window, FileType::P2pool);
}
@ -177,14 +178,14 @@ impl crate::disk::Gupax {
ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ✔").color(GREEN))).on_hover_text(XMRIG_PATH_OK);
}
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
ui.set_enabled(!file_window.lock().unwrap().thread);
ui.set_enabled(!lock!(file_window).thread);
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
Self::spawn_file_window_thread(file_window, FileType::Xmrig);
}
ui.add_sized([ui.available_width(), height], TextEdit::singleline(&mut self.xmrig_path)).on_hover_text(GUPAX_PATH_XMRIG);
});
});
let mut guard = file_window.lock().unwrap();
let mut guard = lock!(file_window);
if guard.picked_p2pool { self.p2pool_path = guard.p2pool_path.clone(); guard.picked_p2pool = false; }
if guard.picked_xmrig { self.xmrig_path = guard.xmrig_path.clone(); guard.picked_xmrig = false; }
drop(guard);
@ -276,19 +277,19 @@ impl crate::disk::Gupax {
Xmrig => "XMRig",
};
let file_window = file_window.clone();
file_window.lock().unwrap().thread = true;
lock!(file_window).thread = true;
thread::spawn(move|| {
match rfd::FileDialog::new().set_title(&format!("Select {} Binary for Gupax", name)).pick_file() {
Some(path) => {
info!("Gupax | Path selected for {} ... {}", name, path.display());
match file_type {
P2pool => { file_window.lock().unwrap().p2pool_path = path.display().to_string(); file_window.lock().unwrap().picked_p2pool = true; },
Xmrig => { file_window.lock().unwrap().xmrig_path = path.display().to_string(); file_window.lock().unwrap().picked_xmrig = true; },
P2pool => { lock!(file_window).p2pool_path = path.display().to_string(); lock!(file_window).picked_p2pool = true; },
Xmrig => { lock!(file_window).xmrig_path = path.display().to_string(); lock!(file_window).picked_xmrig = true; },
};
},
None => info!("Gupax | No path selected for {}", name),
};
file_window.lock().unwrap().thread = false;
lock!(file_window).thread = false;
});
}
}

View file

@ -26,7 +26,7 @@
// found here, e.g: User clicks [Stop P2Pool] -> Arc<Mutex<ProcessSignal> is set
// indicating to this thread during its loop: "I should stop P2Pool!", e.g:
//
// if p2pool.lock().unwrap().signal == ProcessSignal::Stop {
// if lock!(p2pool).signal == ProcessSignal::Stop {
// stop_p2pool(),
// }
//
@ -49,6 +49,7 @@ use crate::{
GupaxP2poolApi,
P2poolRegex,
xmr::*,
macros::*,
};
use sysinfo::SystemExt;
use serde::{Serialize,Deserialize};
@ -168,8 +169,8 @@ impl Process {
start: Instant::now(),
stdin: Option::None,
child: Option::None,
output_parse: Arc::new(Mutex::new(String::with_capacity(500))),
output_pub: Arc::new(Mutex::new(String::with_capacity(500))),
output_parse: arc_mut!(String::with_capacity(500)),
output_pub: arc_mut!(String::with_capacity(500)),
input: vec![String::new()],
}
}
@ -232,12 +233,12 @@ impl Helper {
instant,
pub_sys,
uptime: HumanTime::into_human(instant.elapsed()),
priv_api_p2pool_local: Arc::new(Mutex::new(PrivP2poolLocalApi::new())),
priv_api_p2pool_network: Arc::new(Mutex::new(PrivP2poolNetworkApi::new())),
priv_api_p2pool_pool: Arc::new(Mutex::new(PrivP2poolPoolApi::new())),
priv_api_xmrig: Arc::new(Mutex::new(PrivXmrigApi::new())),
pub_api_p2pool: Arc::new(Mutex::new(PubP2poolApi::new())),
pub_api_xmrig: Arc::new(Mutex::new(PubXmrigApi::new())),
priv_api_p2pool_local: arc_mut!(PrivP2poolLocalApi::new()),
priv_api_p2pool_network: arc_mut!(PrivP2poolNetworkApi::new()),
priv_api_p2pool_pool: arc_mut!(PrivP2poolPoolApi::new()),
priv_api_xmrig: arc_mut!(PrivXmrigApi::new()),
pub_api_p2pool: arc_mut!(PubP2poolApi::new()),
pub_api_xmrig: arc_mut!(PubXmrigApi::new()),
// These are created when initializing [App], since it needs a handle to it as well
p2pool,
xmrig,
@ -255,7 +256,7 @@ impl Helper {
// We don't need to write twice for XMRig, since we dont parse it... yet.
while let Some(Ok(line)) = stdout.next() {
// println!("{}", line); // For debugging.
if let Err(e) = writeln!(output_pub.lock().unwrap(), "{}", line) { error!("XMRig PTY | Output error: {}", e); }
if let Err(e) = writeln!(lock!(output_pub), "{}", line) { error!("XMRig PTY | Output error: {}", e); }
}
}
@ -267,11 +268,11 @@ impl Helper {
if regex.payout.is_match(&line) {
debug!("P2Pool PTY | Found payout, attempting write: {}", line);
let (date, atomic_unit, block) = PayoutOrd::parse_line(&line, &regex);
GupaxP2poolApi::add_payout(&mut gupax_p2pool_api.lock().unwrap(), atomic_unit.to_u128(), &line);
if let Err(e) = GupaxP2poolApi::write_to_all_files(&gupax_p2pool_api.lock().unwrap()) { error!("P2Pool PTY GupaxP2poolApi | Write error: {}", e); }
GupaxP2poolApi::add_payout(&mut lock!(gupax_p2pool_api), atomic_unit.to_u128(), &line);
if let Err(e) = GupaxP2poolApi::write_to_all_files(&lock!(gupax_p2pool_api)) { error!("P2Pool PTY GupaxP2poolApi | Write error: {}", e); }
}
if let Err(e) = writeln!(output_parse.lock().unwrap(), "{}", line) { error!("P2Pool PTY Parse | Output error: {}", e); }
if let Err(e) = writeln!(output_pub.lock().unwrap(), "{}", line) { error!("P2Pool PTY Pub | Output error: {}", e); }
if let Err(e) = writeln!(lock!(output_parse), "{}", line) { error!("P2Pool PTY Parse | Output error: {}", e); }
if let Err(e) = writeln!(lock!(output_pub), "{}", line) { error!("P2Pool PTY Pub | Output error: {}", e); }
}
}
@ -302,25 +303,25 @@ impl Helper {
// Just sets some signals for the watchdog thread to pick up on.
pub fn stop_p2pool(helper: &Arc<Mutex<Self>>) {
info!("P2Pool | Attempting to stop...");
helper.lock().unwrap().p2pool.lock().unwrap().signal = ProcessSignal::Stop;
helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
lock2!(helper,p2pool).signal = ProcessSignal::Stop;
lock2!(helper,p2pool).state = ProcessState::Middle;
}
// The "restart frontend" to a "frontend" function.
// Basically calls to kill the current p2pool, waits a little, then starts the below function in a a new thread, then exit.
pub fn restart_p2pool(helper: &Arc<Mutex<Self>>, state: &crate::disk::P2pool, path: &std::path::PathBuf) {
info!("P2Pool | Attempting to restart...");
helper.lock().unwrap().p2pool.lock().unwrap().signal = ProcessSignal::Restart;
helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
lock2!(helper,p2pool).signal = ProcessSignal::Restart;
lock2!(helper,p2pool).state = ProcessState::Middle;
let helper = Arc::clone(helper);
let state = state.clone();
let path = path.clone();
// This thread lives to wait, start p2pool then die.
thread::spawn(move || {
while helper.lock().unwrap().p2pool.lock().unwrap().is_alive() {
while lock2!(helper,p2pool).is_alive() {
warn!("P2Pool | Want to restart but process is still alive, waiting...");
thread::sleep(SECOND);
sleep!(1000);
}
// Ok, process is not alive, start the new one!
info!("P2Pool | Old process seems dead, starting new one!");
@ -331,7 +332,7 @@ impl Helper {
// The "frontend" function that parses the arguments, and spawns either the [Simple] or [Advanced] P2Pool watchdog thread.
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;
lock2!(helper,p2pool).state = ProcessState::Middle;
let (args, api_path_local, api_path_network, api_path_pool) = Self::build_p2pool_args_and_mutate_img(helper, state, path);
@ -345,10 +346,10 @@ impl Helper {
));
// Spawn watchdog thread
let process = Arc::clone(&helper.lock().unwrap().p2pool);
let gui_api = Arc::clone(&helper.lock().unwrap().gui_api_p2pool);
let pub_api = Arc::clone(&helper.lock().unwrap().pub_api_p2pool);
let gupax_p2pool_api = Arc::clone(&helper.lock().unwrap().gupax_p2pool_api);
let process = Arc::clone(&lock!(helper).p2pool);
let gui_api = Arc::clone(&lock!(helper).gui_api_p2pool);
let pub_api = Arc::clone(&lock!(helper).pub_api_p2pool);
let gupax_p2pool_api = Arc::clone(&lock!(helper).gupax_p2pool_api);
let path = path.clone();
thread::spawn(move || {
Self::spawn_p2pool_watchdog(process, gui_api, pub_api, args, path, api_path_local, api_path_network, api_path_pool, gupax_p2pool_api);
@ -385,7 +386,7 @@ impl Helper {
args.push("--local-api".to_string()); // Enable API
args.push("--no-color".to_string()); // Remove color escape sequences, Gupax terminal can't parse it :(
args.push("--mini".to_string()); // P2Pool Mini
*helper.lock().unwrap().img_p2pool.lock().unwrap() = ImgP2pool {
*lock2!(helper,img_p2pool) = ImgP2pool {
mini: "P2Pool Mini".to_string(),
address: Self::head_tail_of_monero_address(&state.address),
host: ip.to_string(),
@ -402,8 +403,8 @@ impl Helper {
// This parses the input and attemps to fill out
// the [ImgP2pool]... This is pretty bad code...
let mut last = "";
let lock = helper.lock().unwrap();
let mut p2pool_image = lock.img_p2pool.lock().unwrap();
let lock = lock!(helper);
let mut p2pool_image = lock!(lock.img_p2pool);
let mut mini = false;
for arg in state.arguments.split_whitespace() {
match last {
@ -434,7 +435,7 @@ impl Helper {
args.push("--local-api".to_string()); // Enable API
args.push("--no-color".to_string()); // Remove color escape sequences
if state.mini { args.push("--mini".to_string()); }; // Mini
*helper.lock().unwrap().img_p2pool.lock().unwrap() = ImgP2pool {
*lock2!(helper,img_p2pool) = ImgP2pool {
mini: if state.mini { "P2Pool Mini".to_string() } else { "P2Pool Main".to_string() },
address: Self::head_tail_of_monero_address(&state.address),
host: state.selected_ip.to_string(),
@ -472,11 +473,11 @@ impl Helper {
cmd.cwd(path.as_path().parent().unwrap());
// 1c. Create child
debug!("P2Pool | Creating child...");
let child_pty = Arc::new(Mutex::new(pair.slave.spawn_command(cmd).unwrap()));
let child_pty = arc_mut!(pair.slave.spawn_command(cmd).unwrap());
// 2. Set process state
debug!("P2Pool | Setting process state...");
let mut lock = process.lock().unwrap();
let mut lock = lock!(process);
lock.state = ProcessState::Alive;
lock.signal = ProcessSignal::None;
lock.start = Instant::now();
@ -489,15 +490,15 @@ impl Helper {
// 3. Spawn PTY read thread
debug!("P2Pool | Spawning PTY read thread...");
let output_parse = Arc::clone(&process.lock().unwrap().output_parse);
let output_pub = Arc::clone(&process.lock().unwrap().output_pub);
let output_parse = Arc::clone(&lock!(process).output_parse);
let output_pub = Arc::clone(&lock!(process).output_pub);
let gupax_p2pool_api = Arc::clone(&gupax_p2pool_api);
let regex_clone = regex.clone();
thread::spawn(move || {
Self::read_pty_p2pool(output_parse, output_pub, reader, regex_clone, gupax_p2pool_api);
});
let output_parse = Arc::clone(&process.lock().unwrap().output_parse);
let output_pub = Arc::clone(&process.lock().unwrap().output_pub);
let output_parse = Arc::clone(&lock!(process).output_parse);
let output_pub = Arc::clone(&lock!(process).output_pub);
debug!("P2Pool | Cleaning old [local] API files...");
// Attempt to remove stale API file
@ -514,11 +515,11 @@ impl Helper {
Err(e) => warn!("P2Pool | Creating default empty API file ... FAIL ... {}", e),
}
}
let start = process.lock().unwrap().start;
let start = lock!(process).start;
// Reset stats before loop
*pub_api.lock().unwrap() = PubP2poolApi::new();
*gui_api.lock().unwrap() = PubP2poolApi::new();
*lock!(pub_api) = PubP2poolApi::new();
*lock!(gui_api) = PubP2poolApi::new();
// 4. Loop as watchdog
info!("P2Pool | Entering watchdog mode... woof!");
@ -530,17 +531,17 @@ impl Helper {
tick += 1;
// Check if the process is secretly died without us knowing :)
if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
if let Ok(Some(code)) = lock!(child_pty).try_wait() {
debug!("P2Pool Watchdog | Process secretly died! Getting exit status");
let exit_status = match code.success() {
true => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
false => { process.lock().unwrap().state = ProcessState::Failed; "Failed" },
true => { lock!(process).state = ProcessState::Dead; "Successful" },
false => { lock!(process).state = ProcessState::Failed; "Failed" },
};
let uptime = HumanTime::into_human(start.elapsed());
info!("P2Pool Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
// This is written directly into the GUI, because sometimes the 900ms event loop can't catch it.
if let Err(e) = writeln!(
gui_api.lock().unwrap().output,
lock!(gui_api).output,
"{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
HORI_CONSOLE,
uptime,
@ -549,32 +550,32 @@ impl Helper {
) {
error!("P2Pool Watchdog | GUI Uptime/Exit status write failed: {}", e);
}
process.lock().unwrap().signal = ProcessSignal::None;
lock!(process).signal = ProcessSignal::None;
debug!("P2Pool Watchdog | Secret dead process reap OK, breaking");
break
}
// Check SIGNAL
if process.lock().unwrap().signal == ProcessSignal::Stop {
if lock!(process).signal == ProcessSignal::Stop {
debug!("P2Pool Watchdog | Stop SIGNAL caught");
// This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
if let Err(e) = child_pty.lock().unwrap().kill() { error!("P2Pool Watchdog | Kill error: {}", e); }
if let Err(e) = lock!(child_pty).kill() { error!("P2Pool Watchdog | Kill error: {}", e); }
// Wait to get the exit status
let exit_status = match child_pty.lock().unwrap().wait() {
let exit_status = match lock!(child_pty).wait() {
Ok(e) => {
if e.success() {
process.lock().unwrap().state = ProcessState::Dead; "Successful"
lock!(process).state = ProcessState::Dead; "Successful"
} else {
process.lock().unwrap().state = ProcessState::Failed; "Failed"
lock!(process).state = ProcessState::Failed; "Failed"
}
},
_ => { process.lock().unwrap().state = ProcessState::Failed; "Unknown Error" },
_ => { lock!(process).state = ProcessState::Failed; "Unknown Error" },
};
let uptime = HumanTime::into_human(start.elapsed());
info!("P2Pool Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
// This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it.
if let Err(e) = writeln!(
gui_api.lock().unwrap().output,
lock!(gui_api).output,
"{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
HORI_CONSOLE,
uptime,
@ -583,16 +584,16 @@ impl Helper {
) {
error!("P2Pool Watchdog | GUI Uptime/Exit status write failed: {}", e);
}
process.lock().unwrap().signal = ProcessSignal::None;
lock!(process).signal = ProcessSignal::None;
debug!("P2Pool Watchdog | Stop SIGNAL done, breaking");
break
// Check RESTART
} else if process.lock().unwrap().signal == ProcessSignal::Restart {
} else if lock!(process).signal == ProcessSignal::Restart {
debug!("P2Pool Watchdog | Restart SIGNAL caught");
// This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
if let Err(e) = child_pty.lock().unwrap().kill() { error!("P2Pool Watchdog | Kill error: {}", e); }
if let Err(e) = lock!(child_pty).kill() { error!("P2Pool Watchdog | Kill error: {}", e); }
// Wait to get the exit status
let exit_status = match child_pty.lock().unwrap().wait() {
let exit_status = match lock!(child_pty).wait() {
Ok(e) => if e.success() { "Successful" } else { "Failed" },
_ => "Unknown Error",
};
@ -600,7 +601,7 @@ impl Helper {
info!("P2Pool Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
// This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it.
if let Err(e) = writeln!(
gui_api.lock().unwrap().output,
lock!(gui_api).output,
"{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
HORI_CONSOLE,
uptime,
@ -609,13 +610,13 @@ impl Helper {
) {
error!("P2Pool Watchdog | GUI Uptime/Exit status write failed: {}", e);
}
process.lock().unwrap().state = ProcessState::Waiting;
lock!(process).state = ProcessState::Waiting;
debug!("P2Pool Watchdog | Restart SIGNAL done, breaking");
break
}
// Check vector of user input
let mut lock = process.lock().unwrap();
let mut lock = lock!(process);
if !lock.input.is_empty() {
let input = std::mem::take(&mut lock.input);
for line in input {
@ -628,7 +629,7 @@ impl Helper {
// Check if logs need resetting
debug!("P2Pool Watchdog | Attempting GUI log reset check");
let mut lock = gui_api.lock().unwrap();
let mut lock = lock!(gui_api);
Self::check_reset_gui_output(&mut lock.output, ProcessName::P2pool);
drop(lock);
@ -662,7 +663,7 @@ impl Helper {
if elapsed < 900 {
let sleep = (900-elapsed) as u64;
debug!("P2Pool Watchdog | END OF LOOP - Tick: [{}/60] - Sleeping for [{}]ms...", tick, sleep);
std::thread::sleep(std::time::Duration::from_millis(sleep));
sleep!(sleep);
} else {
debug!("P2Pool Watchdog | END OF LOOP - Tick: [{}/60] Not sleeping!", tick);
}
@ -686,7 +687,7 @@ impl Helper {
// Write the [sudo] password to STDIN.
let mut stdin = child.stdin.take().unwrap();
use std::io::Write;
if let Err(e) = writeln!(stdin, "{}\n", sudo.lock().unwrap().pass) { error!("Sudo Kill | STDIN error: {}", e); }
if let Err(e) = writeln!(stdin, "{}\n", lock!(sudo).pass) { error!("Sudo Kill | STDIN error: {}", e); }
// Return exit code of [sudo/kill].
child.wait().unwrap().success()
@ -695,25 +696,25 @@ impl Helper {
// Just sets some signals for the watchdog thread to pick up on.
pub fn stop_xmrig(helper: &Arc<Mutex<Self>>) {
info!("XMRig | Attempting to stop...");
helper.lock().unwrap().xmrig.lock().unwrap().signal = ProcessSignal::Stop;
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
lock2!(helper,xmrig).signal = ProcessSignal::Stop;
lock2!(helper,xmrig).state = ProcessState::Middle;
}
// The "restart frontend" to a "frontend" function.
// Basically calls to kill the current xmrig, waits a little, then starts the below function in a a new thread, then exit.
pub fn restart_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
info!("XMRig | Attempting to restart...");
helper.lock().unwrap().xmrig.lock().unwrap().signal = ProcessSignal::Restart;
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
lock2!(helper,xmrig).signal = ProcessSignal::Restart;
lock2!(helper,xmrig).state = ProcessState::Middle;
let helper = Arc::clone(helper);
let state = state.clone();
let path = path.clone();
// This thread lives to wait, start xmrig then die.
thread::spawn(move || {
while helper.lock().unwrap().xmrig.lock().unwrap().state != ProcessState::Waiting {
while lock2!(helper,xmrig).state != ProcessState::Waiting {
warn!("XMRig | Want to restart but process is still alive, waiting...");
thread::sleep(SECOND);
sleep!(1000);
}
// Ok, process is not alive, start the new one!
info!("XMRig | Old process seems dead, starting new one!");
@ -723,7 +724,7 @@ impl Helper {
}
pub fn start_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
lock2!(helper,xmrig).state = ProcessState::Middle;
let (args, api_ip_port) = Self::build_xmrig_args_and_mutate_img(helper, state, path);
@ -732,10 +733,10 @@ impl Helper {
info!("XMRig | Using path: [{}]", path.display());
// Spawn watchdog thread
let process = Arc::clone(&helper.lock().unwrap().xmrig);
let gui_api = Arc::clone(&helper.lock().unwrap().gui_api_xmrig);
let pub_api = Arc::clone(&helper.lock().unwrap().pub_api_xmrig);
let priv_api = Arc::clone(&helper.lock().unwrap().priv_api_xmrig);
let process = Arc::clone(&lock!(helper).xmrig);
let gui_api = Arc::clone(&lock!(helper).gui_api_xmrig);
let pub_api = Arc::clone(&lock!(helper).pub_api_xmrig);
let priv_api = Arc::clone(&lock!(helper).priv_api_xmrig);
let path = path.clone();
thread::spawn(move || {
Self::spawn_xmrig_watchdog(process, gui_api, pub_api, priv_api, args, path, sudo, api_ip_port);
@ -771,7 +772,7 @@ impl Helper {
args.push("--http-host".to_string()); args.push("127.0.0.1".to_string()); // HTTP API IP
args.push("--http-port".to_string()); args.push("18088".to_string()); // HTTP API Port
if state.pause != 0 { args.push("--pause-on-active".to_string()); args.push(state.pause.to_string()); } // Pause on active
*helper.lock().unwrap().img_xmrig.lock().unwrap() = ImgXmrig {
*lock2!(helper,img_xmrig) = ImgXmrig {
threads: state.current_threads.to_string(),
url: "127.0.0.1:3333 (Local P2Pool)".to_string(),
};
@ -785,8 +786,8 @@ impl Helper {
// This parses the input and attemps to fill out
// the [ImgXmrig]... This is pretty bad code...
let mut last = "";
let lock = helper.lock().unwrap();
let mut xmrig_image = lock.img_xmrig.lock().unwrap();
let lock = lock!(helper);
let mut xmrig_image = lock!(lock.img_xmrig);
for arg in state.arguments.split_whitespace() {
match last {
"--threads" => xmrig_image.threads = arg.to_string(),
@ -814,7 +815,7 @@ impl Helper {
if state.tls { args.push("--tls".to_string()); } // TLS
if state.keepalive { args.push("--keepalive".to_string()); } // Keepalive
if state.pause != 0 { args.push("--pause-on-active".to_string()); args.push(state.pause.to_string()); } // Pause on active
*helper.lock().unwrap().img_xmrig.lock().unwrap() = ImgXmrig {
*lock2!(helper,img_xmrig) = ImgXmrig {
url,
threads: state.current_threads.to_string(),
};
@ -862,21 +863,21 @@ impl Helper {
let cmd = Self::create_xmrig_cmd_unix(args, path);
// 1c. Create child
debug!("XMRig | Creating child...");
let child_pty = Arc::new(Mutex::new(pair.slave.spawn_command(cmd).unwrap()));
let child_pty = arc_mut!(pair.slave.spawn_command(cmd).unwrap());
// 2. Input [sudo] pass, wipe, then drop.
if cfg!(unix) {
debug!("XMRig | Inputting [sudo] and wiping...");
// 1d. Sleep to wait for [sudo]'s non-echo prompt (on Unix).
// this prevents users pass from showing up in the STDOUT.
std::thread::sleep(std::time::Duration::from_secs(3));
if let Err(e) = writeln!(pair.master, "{}", sudo.lock().unwrap().pass) { error!("XMRig | Sudo STDIN error: {}", e); };
sleep!(3000);
if let Err(e) = writeln!(pair.master, "{}", lock!(sudo).pass) { error!("XMRig | Sudo STDIN error: {}", e); };
SudoState::wipe(&sudo);
}
// 3. Set process state
debug!("XMRig | Setting process state...");
let mut lock = process.lock().unwrap();
let mut lock = lock!(process);
lock.state = ProcessState::Alive;
lock.signal = ProcessSignal::None;
lock.start = Instant::now();
@ -887,17 +888,17 @@ impl Helper {
// 4. Spawn PTY read thread
debug!("XMRig | Spawning PTY read thread...");
let output_parse = Arc::clone(&process.lock().unwrap().output_parse);
let output_pub = Arc::clone(&process.lock().unwrap().output_pub);
let output_parse = Arc::clone(&lock!(process).output_parse);
let output_pub = Arc::clone(&lock!(process).output_pub);
thread::spawn(move || {
Self::read_pty_xmrig(output_parse, output_pub, reader);
});
// We don't parse anything in XMRigs output... yet.
// let output_parse = Arc::clone(&process.lock().unwrap().output_parse);
let output_pub = Arc::clone(&process.lock().unwrap().output_pub);
// let output_parse = Arc::clone(&lock!(process).output_parse);
let output_pub = Arc::clone(&lock!(process).output_pub);
let client: hyper::Client<hyper::client::HttpConnector> = hyper::Client::builder().build(hyper::client::HttpConnector::new());
let start = process.lock().unwrap().start;
let start = lock!(process).start;
let api_uri = {
if !api_ip_port.ends_with('/') { api_ip_port.push('/'); }
"http://".to_owned() + &api_ip_port + XMRIG_API_URI
@ -905,8 +906,8 @@ impl Helper {
info!("XMRig | Final API URI: {}", api_uri);
// Reset stats before loop
*pub_api.lock().unwrap() = PubXmrigApi::new();
*gui_api.lock().unwrap() = PubXmrigApi::new();
*lock!(pub_api) = PubXmrigApi::new();
*lock!(gui_api) = PubXmrigApi::new();
// 5. Loop as watchdog
info!("XMRig | Entering watchdog mode... woof!");
@ -916,16 +917,16 @@ impl Helper {
debug!("XMRig Watchdog | ----------- Start of loop -----------");
// Check if the process secretly died without us knowing :)
if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
if let Ok(Some(code)) = lock!(child_pty).try_wait() {
debug!("XMRig Watchdog | Process secretly died on us! Getting exit status...");
let exit_status = match code.success() {
true => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
false => { process.lock().unwrap().state = ProcessState::Failed; "Failed" },
true => { lock!(process).state = ProcessState::Dead; "Successful" },
false => { lock!(process).state = ProcessState::Failed; "Failed" },
};
let uptime = HumanTime::into_human(start.elapsed());
info!("XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
if let Err(e) = writeln!(
gui_api.lock().unwrap().output,
lock!(gui_api).output,
"{}\nXMRig stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
HORI_CONSOLE,
uptime,
@ -934,13 +935,13 @@ impl Helper {
) {
error!("XMRig Watchdog | GUI Uptime/Exit status write failed: {}", e);
}
process.lock().unwrap().signal = ProcessSignal::None;
lock!(process).signal = ProcessSignal::None;
debug!("XMRig Watchdog | Secret dead process reap OK, breaking");
break
}
// Stop on [Stop/Restart] SIGNAL
let signal = process.lock().unwrap().signal;
let signal = lock!(process).signal;
if signal == ProcessSignal::Stop || signal == ProcessSignal::Restart {
debug!("XMRig Watchdog | Stop/Restart SIGNAL caught");
// macOS requires [sudo] again to kill [XMRig]
@ -948,16 +949,16 @@ impl Helper {
// If we're at this point, that means the user has
// entered their [sudo] pass again, after we wiped it.
// So, we should be able to find it in our [Arc<Mutex<SudoState>>].
Self::sudo_kill(child_pty.lock().unwrap().process_id().unwrap(), &sudo);
Self::sudo_kill(lock!(child_pty).process_id().unwrap(), &sudo);
// And... wipe it again (only if we're stopping full).
// If we're restarting, the next start will wipe it for us.
if signal != ProcessSignal::Restart { SudoState::wipe(&sudo); }
} else if let Err(e) = child_pty.lock().unwrap().kill() {
} else if let Err(e) = lock!(child_pty).kill() {
error!("XMRig Watchdog | Kill error: {}", e);
}
let exit_status = match child_pty.lock().unwrap().wait() {
let exit_status = match lock!(child_pty).wait() {
Ok(e) => {
let mut process = process.lock().unwrap();
let mut process = lock!(process);
if e.success() {
if process.signal == ProcessSignal::Stop { process.state = ProcessState::Dead; }
"Successful"
@ -967,7 +968,7 @@ impl Helper {
}
},
_ => {
let mut process = process.lock().unwrap();
let mut process = lock!(process);
if process.signal == ProcessSignal::Stop { process.state = ProcessState::Failed; }
"Unknown Error"
},
@ -975,7 +976,7 @@ impl Helper {
let uptime = HumanTime::into_human(start.elapsed());
info!("XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
if let Err(e) = writeln!(
gui_api.lock().unwrap().output,
lock!(gui_api).output,
"{}\nXMRig stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
HORI_CONSOLE,
uptime,
@ -984,7 +985,7 @@ impl Helper {
) {
error!("XMRig Watchdog | GUI Uptime/Exit status write failed: {}", e);
}
let mut process = process.lock().unwrap();
let mut process = lock!(process);
match process.signal {
ProcessSignal::Stop => process.signal = ProcessSignal::None,
ProcessSignal::Restart => process.state = ProcessState::Waiting,
@ -995,7 +996,7 @@ impl Helper {
}
// Check vector of user input
let mut lock = process.lock().unwrap();
let mut lock = lock!(process);
if !lock.input.is_empty() {
let input = std::mem::take(&mut lock.input);
for line in input {
@ -1007,7 +1008,7 @@ impl Helper {
// Check if logs need resetting
debug!("XMRig Watchdog | Attempting GUI log reset check");
let mut lock = gui_api.lock().unwrap();
let mut lock = lock!(gui_api);
Self::check_reset_gui_output(&mut lock.output, ProcessName::Xmrig);
drop(lock);
@ -1030,7 +1031,7 @@ impl Helper {
if elapsed < 900 {
let sleep = (900-elapsed) as u64;
debug!("XMRig Watchdog | END OF LOOP - Sleeping for [{}]ms...", sleep);
std::thread::sleep(std::time::Duration::from_millis(sleep));
sleep!(sleep);
} else {
debug!("XMRig Watchdog | END OF LOOP - Not sleeping!");
}
@ -1089,7 +1090,7 @@ impl Helper {
// order as the main GUI thread (top to bottom).
let helper = Arc::clone(helper);
let lock = helper.lock().unwrap();
let lock = lock!(helper);
let p2pool = Arc::clone(&lock.p2pool);
let xmrig = Arc::clone(&lock.xmrig);
let pub_sys = Arc::clone(&lock.pub_sys);
@ -1115,14 +1116,14 @@ impl Helper {
// down the culprit of an [Arc<Mutex>] deadlock. I know, they're ugly.
// 2. Lock... EVERYTHING!
let mut lock = helper.lock().unwrap(); debug!("Helper | Locking (1/8) ... [helper]");
let p2pool = p2pool.lock().unwrap(); debug!("Helper | Locking (2/8) ... [p2pool]");
let xmrig = xmrig.lock().unwrap(); debug!("Helper | Locking (3/8) ... [xmrig]");
let mut lock_pub_sys = pub_sys.lock().unwrap(); debug!("Helper | Locking (4/8) ... [pub_sys]");
let mut gui_api_p2pool = gui_api_p2pool.lock().unwrap(); debug!("Helper | Locking (5/8) ... [gui_api_p2pool]");
let mut gui_api_xmrig = gui_api_xmrig.lock().unwrap(); debug!("Helper | Locking (6/8) ... [gui_api_xmrig]");
let mut pub_api_p2pool = pub_api_p2pool.lock().unwrap(); debug!("Helper | Locking (7/8) ... [pub_api_p2pool]");
let mut pub_api_xmrig = pub_api_xmrig.lock().unwrap(); debug!("Helper | Locking (8/8) ... [pub_api_xmrig]");
let mut lock = lock!(helper); debug!("Helper | Locking (1/8) ... [helper]");
let p2pool = lock!(p2pool); debug!("Helper | Locking (2/8) ... [p2pool]");
let xmrig = lock!(xmrig); debug!("Helper | Locking (3/8) ... [xmrig]");
let mut lock_pub_sys = lock!(pub_sys); debug!("Helper | Locking (4/8) ... [pub_sys]");
let mut gui_api_p2pool = lock!(gui_api_p2pool); debug!("Helper | Locking (5/8) ... [gui_api_p2pool]");
let mut gui_api_xmrig = lock!(gui_api_xmrig); debug!("Helper | Locking (6/8) ... [gui_api_xmrig]");
let mut pub_api_p2pool = lock!(pub_api_p2pool); debug!("Helper | Locking (7/8) ... [pub_api_p2pool]");
let mut pub_api_xmrig = lock!(pub_api_xmrig); debug!("Helper | Locking (8/8) ... [pub_api_xmrig]");
// Calculate Gupax's uptime always.
lock.uptime = HumanTime::into_human(lock.instant.elapsed());
// If [P2Pool] is alive...
@ -1165,7 +1166,7 @@ impl Helper {
// is less than 1000, meaning it can fit into a u64 easy.
let sleep = (1000-elapsed) as u64;
debug!("Helper | END OF LOOP - Sleeping for [{}]ms...", sleep);
std::thread::sleep(std::time::Duration::from_millis(sleep));
sleep!(sleep);
} else {
debug!("Helper | END OF LOOP - Not sleeping!");
}
@ -1341,19 +1342,19 @@ impl PubP2poolApi {
// Mutate "watchdog"'s [PubP2poolApi] with data the process output.
fn update_from_output(public: &Arc<Mutex<Self>>, output_parse: &Arc<Mutex<String>>, output_pub: &Arc<Mutex<String>>, elapsed: std::time::Duration, regex: &P2poolRegex) {
// 1. Take the process's current output buffer and combine it with Pub (if not empty)
let mut output_pub = output_pub.lock().unwrap();
let mut output_pub = lock!(output_pub);
if !output_pub.is_empty() {
public.lock().unwrap().output.push_str(&std::mem::take(&mut *output_pub));
lock!(public).output.push_str(&std::mem::take(&mut *output_pub));
}
// 2. Parse the full STDOUT
let mut output_parse = output_parse.lock().unwrap();
let mut output_parse = lock!(output_parse);
let (payouts_new, xmr_new) = Self::calc_payouts_and_xmr(&output_parse, regex);
// 3. Throw away [output_parse]
output_parse.clear();
drop(output_parse);
// 4. Add to current values
let mut public = public.lock().unwrap();
let mut public = lock!(public);
let (payouts, xmr) = (public.payouts + payouts_new, public.xmr + xmr_new);
// 5. Calculate hour/day/month given elapsed time
@ -1397,7 +1398,7 @@ impl PubP2poolApi {
// Mutate [PubP2poolApi] with data from a [PrivP2poolLocalApi] and the process output.
fn update_from_local(public: &Arc<Mutex<Self>>, local: PrivP2poolLocalApi) {
let mut public = public.lock().unwrap();
let mut public = lock!(public);
*public = Self {
hashrate_15m: HumanNumber::from_u64(local.hashrate_15m),
hashrate_1h: HumanNumber::from_u64(local.hashrate_1h),
@ -1413,7 +1414,7 @@ impl PubP2poolApi {
// Mutate [PubP2poolApi] with data from a [PrivP2pool(Network|Pool)Api].
fn update_from_network_pool(public: &Arc<Mutex<Self>>, net: PrivP2poolNetworkApi, pool: PrivP2poolPoolApi) {
let user_hashrate = public.lock().unwrap().hashrate; // The user's total P2Pool hashrate
let user_hashrate = lock!(public).hashrate; // The user's total P2Pool hashrate
let monero_difficulty = net.difficulty;
let monero_hashrate = monero_difficulty / MONERO_BLOCK_TIME_IN_SECONDS;
let p2pool_hashrate = pool.pool_statistics.hashRate;
@ -1449,7 +1450,7 @@ impl PubP2poolApi {
solo_block_mean = HumanTime::into_human(std::time::Duration::from_secs(monero_difficulty / user_hashrate));
p2pool_share_mean = HumanTime::into_human(std::time::Duration::from_secs(p2pool_difficulty / user_hashrate));
}
let mut public = public.lock().unwrap();
let mut public = lock!(public);
*public = Self {
monero_difficulty: HumanNumber::from_u64(monero_difficulty),
monero_hashrate: HumanNumber::from_u64_to_gigahash_3_point(monero_hashrate),
@ -1642,8 +1643,8 @@ impl PubXmrigApi {
// with the actual [PubApiXmrig] output field.
fn update_from_output(public: &Arc<Mutex<Self>>, output_pub: &Arc<Mutex<String>>, elapsed: std::time::Duration) {
// 1. Take process output buffer if not empty
let mut output_pub = output_pub.lock().unwrap();
let mut public = public.lock().unwrap();
let mut output_pub = lock!(output_pub);
let mut public = lock!(public);
// 2. Append
if !output_pub.is_empty() {
public.output.push_str(&std::mem::take(&mut *output_pub));
@ -1654,7 +1655,7 @@ impl PubXmrigApi {
// Formats raw private data into ready-to-print human readable version.
fn update_from_priv(public: &Arc<Mutex<Self>>, private: PrivXmrigApi) {
let mut public = public.lock().unwrap();
let mut public = lock!(public);
*public = Self {
worker_id: private.worker_id,
resources: HumanNumber::from_load(private.resources.load_average),

121
src/macros.rs Normal file
View file

@ -0,0 +1,121 @@
// Gupax - GUI Uniting P2Pool And XMRig
//
// Copyright (c) 2022 hinto-janaiyo
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// These are general QoL macros, nothing too scary, I promise.
//
// | MACRO | PURPOSE | EQUIVALENT CODE |
// |---------|----------------------------------------------|------------------------------------------------------------|
// | lock | Lock an [Arc<Mutex>] | a.lock().unwrap() |
// | lock2 | Lock a field inside a struct, both Arc<Mutex | a.lock().unwrap().b.lock().unwrap() |
// | arc_mut | Create a new [Arc<Mutex>] | std::sync::Arc::new(std::sync::Mutex::new(my_value)) |
// | sleep | Sleep the current thread for x milliseconds | std::thread::sleep(std::time::Duration::from_millis(1000)) |
// | flip | Flip a bool in place | my_bool = !my_bool |
//
// Hopefully the long ass code on the right justifies usage of macros :D
//
// [lock2!()] works like this: "lock2!(my_first, my_second)"
// and expects it be a [Struct]-[field] relationship, e.g:
//
// let my_first = Struct {
// my_second: Arc::new(Mutex::new(true)),
// };
// lock2!(my_first, my_second);
//
// The equivalent code is: "my_first.lock().unwrap().my_second.lock().unwrap()" (see? this is long as hell)
// Locks and unwraps an [Arc<Mutex<T>]
macro_rules! lock {
($arc_mutex:expr) => {
$arc_mutex.lock().unwrap()
};
}
pub(crate) use lock;
// Creates a new [Arc<Mutex<T>]
macro_rules! arc_mut {
($arc_mutex:expr) => {
std::sync::Arc::new(std::sync::Mutex::new($arc_mutex))
};
}
pub(crate) use arc_mut;
// Locks and unwraps a field of a struct, both of them being [Arc<Mutex>]
// Yes, I know this is bad code.
macro_rules! lock2 {
($arc_mutex:expr, $arc_mutex_two:ident) => {
$arc_mutex.lock().unwrap().$arc_mutex_two.lock().unwrap()
};
}
pub(crate) use lock2;
// Sleeps a [std::thread] using milliseconds
macro_rules! sleep {
($millis:expr) => {
std::thread::sleep(std::time::Duration::from_millis($millis))
};
}
pub(crate) use sleep;
// Flips a [bool] in place
macro_rules! flip {
($b:expr) => {
match $b {
true|false => $b = !$b,
};
};
}
pub(crate) use flip;
//---------------------------------------------------------------------------------------------------- TESTS
#[cfg(test)]
mod test {
#[test]
fn lock() {
use std::sync::{Arc,Mutex};
let arc_mutex = Arc::new(Mutex::new(false));
*lock!(arc_mutex) = true;
assert!(*lock!(arc_mutex) == true);
}
#[test]
fn lock2() {
struct Ab {
a: Arc<Mutex<bool>>,
}
use std::sync::{Arc,Mutex};
let arc_mutex = Arc::new(Mutex::new(
Ab {
a: Arc::new(Mutex::new(false)),
}
));
*lock2!(arc_mutex,a) = true;
assert!(*lock2!(arc_mutex,a) == true);
}
#[test]
fn arc_mut() {
let a = arc_mut!(false);
assert!(*lock!(a) == false);
}
#[test]
fn flip() {
let mut b = true;
flip!(b);
assert!(b == false);
}
}

View file

@ -65,7 +65,8 @@ mod helper;
mod human;
mod regex;
mod xmr;
use {crate::regex::*,ferris::*,constants::*,node::*,disk::*,update::*,gupax::*,helper::*};
mod macros;
use {macros::*,crate::regex::*,ferris::*,constants::*,node::*,disk::*,update::*,gupax::*,helper::*};
// Sudo (dummy values for Windows)
mod sudo;
@ -176,12 +177,12 @@ impl App {
fn new(now: Instant) -> Self {
info!("Initializing App Struct...");
debug!("App Init | P2Pool & XMRig processes...");
let p2pool = Arc::new(Mutex::new(Process::new(ProcessName::P2pool, String::new(), PathBuf::new())));
let xmrig = Arc::new(Mutex::new(Process::new(ProcessName::Xmrig, String::new(), PathBuf::new())));
let p2pool_api = Arc::new(Mutex::new(PubP2poolApi::new()));
let xmrig_api = Arc::new(Mutex::new(PubXmrigApi::new()));
let p2pool_img = Arc::new(Mutex::new(ImgP2pool::new()));
let xmrig_img = Arc::new(Mutex::new(ImgXmrig::new()));
let p2pool = arc_mut!(Process::new(ProcessName::P2pool, String::new(), PathBuf::new()));
let xmrig = arc_mut!(Process::new(ProcessName::Xmrig, String::new(), PathBuf::new()));
let p2pool_api = arc_mut!(PubP2poolApi::new());
let xmrig_api = arc_mut!(PubXmrigApi::new());
let p2pool_img = arc_mut!(ImgP2pool::new());
let xmrig_img = arc_mut!(ImgXmrig::new());
debug!("App Init | Sysinfo...");
// We give this to the [Helper] thread.
@ -195,27 +196,27 @@ impl App {
Ok(pid) => pid,
Err(e) => { error!("App Init | Failed to get sysinfo PID: {}", e); exit(1) }
};
let pub_sys = Arc::new(Mutex::new(Sys::new()));
let pub_sys = arc_mut!(Sys::new());
debug!("App Init | The rest of the [App]...");
let mut app = Self {
tab: Tab::default(),
ping: Arc::new(Mutex::new(Ping::new())),
ping: arc_mut!(Ping::new()),
width: APP_DEFAULT_WIDTH,
height: APP_DEFAULT_HEIGHT,
must_resize: false,
og: Arc::new(Mutex::new(State::new())),
og: arc_mut!(State::new()),
state: State::new(),
update: Arc::new(Mutex::new(Update::new(String::new(), PathBuf::new(), PathBuf::new(), true))),
update: arc_mut!(Update::new(String::new(), PathBuf::new(), PathBuf::new(), true)),
file_window: FileWindow::new(),
og_node_vec: Node::new_vec(),
node_vec: Node::new_vec(),
og_pool_vec: Pool::new_vec(),
pool_vec: Pool::new_vec(),
restart: Arc::new(Mutex::new(Restart::No)),
restart: arc_mut!(Restart::No),
diff: false,
error_state: ErrorState::new(),
helper: Arc::new(Mutex::new(Helper::new(now, pub_sys.clone(), p2pool.clone(), xmrig.clone(), p2pool_api.clone(), xmrig_api.clone(), p2pool_img.clone(), xmrig_img.clone(), Arc::new(Mutex::new(GupaxP2poolApi::new()))))),
helper: arc_mut!(Helper::new(now, pub_sys.clone(), p2pool.clone(), xmrig.clone(), p2pool_api.clone(), xmrig_api.clone(), p2pool_img.clone(), xmrig_img.clone(), arc_mut!(GupaxP2poolApi::new()))),
p2pool,
xmrig,
p2pool_api,
@ -224,11 +225,11 @@ impl App {
xmrig_img,
p2pool_stdin: String::with_capacity(10),
xmrig_stdin: String::with_capacity(10),
sudo: Arc::new(Mutex::new(SudoState::new())),
sudo: arc_mut!(SudoState::new()),
resizing: false,
alpha: 0,
no_startup: false,
gupax_p2pool_api: Arc::new(Mutex::new(GupaxP2poolApi::new())),
gupax_p2pool_api: arc_mut!(GupaxP2poolApi::new()),
pub_sys,
pid,
max_threads: num_cpus::get(),
@ -301,7 +302,7 @@ impl App {
State::new()
},
};
app.og = Arc::new(Mutex::new(app.state.clone()));
app.og = arc_mut!(app.state.clone());
// Read node list
debug!("App Init | Reading node list...");
app.node_vec = match Node::get(&app.node_path) {
@ -348,7 +349,7 @@ impl App {
//----------------------------------------------------------------------------------------------------
// Read [GupaxP2poolApi] disk files
app.gupax_p2pool_api_path = crate::disk::get_gupax_p2pool_path(&app.os_data_path);
let mut gupax_p2pool_api = app.gupax_p2pool_api.lock().unwrap();
let mut gupax_p2pool_api = lock!(app.gupax_p2pool_api);
gupax_p2pool_api.fill_paths(&app.gupax_p2pool_api_path);
match GupaxP2poolApi::create_all_files(&app.gupax_p2pool_api_path) {
Ok(_) => debug!("App Init | Creating Gupax-P2Pool API files ... OK"),
@ -388,10 +389,10 @@ impl App {
},
};
drop(gupax_p2pool_api);
app.helper.lock().unwrap().gupax_p2pool_api = Arc::clone(&app.gupax_p2pool_api);
lock!(app.helper).gupax_p2pool_api = Arc::clone(&app.gupax_p2pool_api);
//----------------------------------------------------------------------------------------------------
let mut og = app.og.lock().unwrap(); // Lock [og]
let mut og = lock!(app.og); // Lock [og]
// Handle max threads
debug!("App Init | Handling max thread overflow...");
og.xmrig.max_threads = app.max_threads;
@ -436,13 +437,13 @@ impl App {
let p2pool_path = og.gupax.absolute_p2pool_path.clone();
let xmrig_path = og.gupax.absolute_xmrig_path.clone();
let tor = og.gupax.update_via_tor;
app.update = Arc::new(Mutex::new(Update::new(app.exe.clone(), p2pool_path, xmrig_path, tor)));
app.update = arc_mut!(Update::new(app.exe.clone(), p2pool_path, xmrig_path, tor));
debug!("App Init | Setting state Gupax version...");
// Set state version as compiled in version
og.version.lock().unwrap().gupax = GUPAX_VERSION.to_string();
app.state.version.lock().unwrap().gupax = GUPAX_VERSION.to_string();
lock!(og.version).gupax = GUPAX_VERSION.to_string();
lock!(app.state.version).gupax = GUPAX_VERSION.to_string();
debug!("App Init | Setting saved [Tab]...");
// Set saved [Tab]
@ -804,7 +805,7 @@ fn init_auto(app: &mut App) {
} else if cfg!(windows) {
Helper::start_xmrig(&app.helper, &app.state.xmrig, &app.state.gupax.absolute_xmrig_path, Arc::clone(&app.sudo));
} else {
app.sudo.lock().unwrap().signal = ProcessSignal::Start;
lock!(app.sudo).signal = ProcessSignal::Start;
app.error_state.ask_sudo(&app.sudo);
}
} else {
@ -1062,9 +1063,9 @@ impl eframe::App for App {
Submenu::Monero => self.state.status.submenu = Submenu::P2pool,
}
},
Tab::Gupax => self.state.gupax.simple = !self.state.gupax.simple,
Tab::P2pool => self.state.p2pool.simple = !self.state.p2pool.simple,
Tab::Xmrig => self.state.xmrig.simple = !self.state.xmrig.simple,
Tab::Gupax => flip!(self.state.gupax.simple),
Tab::P2pool => flip!(self.state.p2pool.simple),
Tab::Xmrig => flip!(self.state.xmrig.simple),
_ => (),
};
// Change Submenu RIGHT
@ -1077,9 +1078,9 @@ impl eframe::App for App {
Submenu::Monero => self.state.status.submenu = Submenu::Processes,
}
},
Tab::Gupax => self.state.gupax.simple = !self.state.gupax.simple,
Tab::P2pool => self.state.p2pool.simple = !self.state.p2pool.simple,
Tab::Xmrig => self.state.xmrig.simple = !self.state.xmrig.simple,
Tab::Gupax => flip!(self.state.gupax.simple),
Tab::P2pool => flip!(self.state.p2pool.simple),
Tab::Xmrig => flip!(self.state.xmrig.simple),
_ => (),
};
}
@ -1093,13 +1094,13 @@ impl eframe::App for App {
// might as well check only once here to save
// on a bunch of [.lock().unwrap()]s.
debug!("App | Locking and collecting P2Pool state...");
let p2pool = self.p2pool.lock().unwrap();
let p2pool = lock!(self.p2pool);
let p2pool_is_alive = p2pool.is_alive();
let p2pool_is_waiting = p2pool.is_waiting();
let p2pool_state = p2pool.state;
drop(p2pool);
debug!("App | Locking and collecting XMRig state...");
let xmrig = self.xmrig.lock().unwrap();
let xmrig = lock!(self.xmrig);
let xmrig_is_alive = xmrig.is_alive();
let xmrig_is_waiting = xmrig.is_waiting();
let xmrig_state = xmrig.state;
@ -1190,7 +1191,7 @@ impl eframe::App for App {
match self.error_state.buttons {
StayQuit => {
let mut text = "".to_string();
if *self.update.lock().unwrap().updating.lock().unwrap() { text = format!("{}\nUpdate is in progress...! Quitting may cause file corruption!", text); }
if *lock2!(self.update,updating) { text = format!("{}\nUpdate is in progress...! Quitting may cause file corruption!", text); }
if p2pool_is_alive { text = format!("{}\nP2Pool is online...!", text); }
if xmrig_is_alive { text = format!("{}\nXMRig is online...!", text); }
ui.add_sized([width, height], Label::new("--- Are you sure you want to quit? ---"));
@ -1270,7 +1271,7 @@ impl eframe::App for App {
match State::get(&self.state_path) {
Ok(s) => {
self.state = s;
self.og = Arc::new(Mutex::new(self.state.clone()));
self.og = arc_mut!(self.state.clone());
self.error_state.set("State read OK", ErrorFerris::Happy, ErrorButtons::Okay);
},
Err(e) => self.error_state.set(format!("State read fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
@ -1302,7 +1303,7 @@ impl eframe::App for App {
ErrorButtons::Sudo => {
let sudo_width = width/10.0;
let height = ui.available_height()/4.0;
let mut sudo = self.sudo.lock().unwrap();
let mut sudo = lock!(self.sudo);
let hide = sudo.hide;
ui.style_mut().override_text_style = Some(Monospace);
if sudo.testing {
@ -1325,7 +1326,7 @@ impl eframe::App for App {
}
}
let color = if hide { BLACK } else { BRIGHT_YELLOW };
if ui.add_sized([box_width, height], Button::new(RichText::new("👁").color(color))).on_hover_text(PASSWORD_HIDE).clicked() { sudo.hide = !sudo.hide; }
if ui.add_sized([box_width, height], Button::new(RichText::new("👁").color(color))).on_hover_text(PASSWORD_HIDE).clicked() { flip!(sudo.hide) }
});
if (key.is_esc() && !sudo.testing) || ui.add_sized([width, height*4.0], Button::new("Leave")).on_hover_text(PASSWORD_LEAVE).clicked() { self.error_state.reset(); };
// If [test_sudo()] finished, reset error state.
@ -1346,7 +1347,7 @@ impl eframe::App for App {
// 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();
let og = lock!(self.og);
if og.status != self.state.status ||
og.gupax != self.state.gupax ||
og.p2pool != self.state.p2pool ||
@ -1394,7 +1395,7 @@ impl eframe::App for App {
let width = ((self.width/2.0)/4.0)-(SPACE*2.0);
// [Gupax Version]
// Is yellow if the user updated and should (but isn't required to) restart.
match *self.restart.lock().unwrap() {
match *lock!(self.restart) {
Restart::Yes => ui.add_sized([width, height], Label::new(RichText::new(&self.name_version).color(YELLOW))).on_hover_text(GUPAX_SHOULD_RESTART),
_ => ui.add_sized([width, height], Label::new(&self.name_version)).on_hover_text(GUPAX_UP_TO_DATE),
};
@ -1436,7 +1437,7 @@ impl eframe::App for App {
ui.set_enabled(self.diff);
let width = width / 2.0;
if key.is_r() && !wants_input && self.diff || ui.add_sized([width, height], Button::new("Reset")).on_hover_text("Reset changes").clicked() {
let og = self.og.lock().unwrap().clone();
let og = lock!(self.og).clone();
self.state.status = og.status;
self.state.gupax = og.gupax;
self.state.p2pool = og.p2pool;
@ -1447,7 +1448,7 @@ impl eframe::App for App {
if key.is_s() && !wants_input && self.diff || ui.add_sized([width, height], Button::new("Save")).on_hover_text("Save changes").clicked() {
match State::save(&mut self.state, &self.state_path) {
Ok(_) => {
let mut og = self.og.lock().unwrap();
let mut og = lock!(self.og);
og.status = self.state.status.clone();
og.gupax = self.state.gupax.clone();
og.p2pool = self.state.p2pool.clone();
@ -1577,13 +1578,13 @@ impl eframe::App for App {
if cfg!(windows) {
Helper::restart_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path, Arc::clone(&self.sudo));
} else {
self.sudo.lock().unwrap().signal = ProcessSignal::Restart;
lock!(self.sudo).signal = ProcessSignal::Restart;
self.error_state.ask_sudo(&self.sudo);
}
}
if key.is_down() && !wants_input || ui.add_sized([width, height], Button::new("")).on_hover_text("Stop XMRig").clicked() {
if cfg!(target_os = "macos") {
self.sudo.lock().unwrap().signal = ProcessSignal::Stop;
lock!(self.sudo).signal = ProcessSignal::Stop;
self.error_state.ask_sudo(&self.sudo);
} else {
Helper::stop_xmrig(&self.helper);
@ -1614,7 +1615,7 @@ impl eframe::App for App {
}
#[cfg(target_family = "unix")]
if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new(RichText::new("").color(color))).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
self.sudo.lock().unwrap().signal = ProcessSignal::Start;
lock!(self.sudo).signal = ProcessSignal::Start;
self.error_state.ask_sudo(&self.sudo);
}
}
@ -1643,8 +1644,8 @@ impl eframe::App for App {
let distro = true;
#[cfg(not(feature = "distro"))]
let distro = false;
let p2pool_gui_len = self.p2pool_api.lock().unwrap().output.len();
let xmrig_gui_len = self.xmrig_api.lock().unwrap().output.len();
let p2pool_gui_len = lock!(self.p2pool_api).output.len();
let xmrig_gui_len = lock!(self.xmrig_api).output.len();
let debug_info = format!(
"Gupax version: {}\n
Bundled P2Pool version: {}\n
@ -1704,11 +1705,11 @@ XMRig console byte length: {}\n
self.state.gupax.absolute_xmrig_path.display(),
p2pool_gui_len,
xmrig_gui_len,
self.p2pool_img.lock().unwrap(),
self.xmrig_img.lock().unwrap(),
self.gupax_p2pool_api.lock().unwrap(),
lock!(self.p2pool_img),
lock!(self.xmrig_img),
lock!(self.gupax_p2pool_api),
self.state,
self.og.lock().unwrap(),
lock!(self.og),
);
self.error_state.set(debug_info, ErrorFerris::Cute, ErrorButtons::Debug);
}

View file

@ -17,6 +17,7 @@
use crate::{
constants::*,
macros::*,
};
use serde::{Serialize,Deserialize};
use rand::{thread_rng, Rng};
@ -310,19 +311,19 @@ impl Ping {
match Self::ping(&ping) {
Ok(msg) => {
info!("Ping ... OK");
ping.lock().unwrap().msg = msg;
ping.lock().unwrap().pinged = true;
ping.lock().unwrap().auto_selected = false;
ping.lock().unwrap().prog = 100.0;
lock!(ping).msg = msg;
lock!(ping).pinged = true;
lock!(ping).auto_selected = false;
lock!(ping).prog = 100.0;
},
Err(err) => {
error!("Ping ... FAIL ... {}", err);
ping.lock().unwrap().pinged = false;
ping.lock().unwrap().msg = err.to_string();
lock!(ping).pinged = false;
lock!(ping).msg = err.to_string();
},
}
info!("Ping ... Took [{}] seconds...", now.elapsed().as_secs_f32());
ping.lock().unwrap().pinging = false;
lock!(ping).pinging = false;
});
}
@ -347,13 +348,13 @@ impl Ping {
pub async fn ping(ping: &Arc<Mutex<Self>>) -> Result<String, anyhow::Error> {
// Start ping
let ping = Arc::clone(ping);
ping.lock().unwrap().pinging = true;
ping.lock().unwrap().prog = 0.0;
lock!(ping).pinging = true;
lock!(ping).prog = 0.0;
let percent = (100.0 / (COMMUNITY_NODE_LENGTH as f32)).floor();
// Create HTTP client
let info = "Creating HTTP Client".to_string();
ping.lock().unwrap().msg = info;
lock!(ping).msg = info;
let client: Client<HttpConnector> = Client::builder()
.build(HttpConnector::new());
@ -361,7 +362,7 @@ impl Ping {
let rand_user_agent = crate::Pkg::get_user_agent();
// Handle vector
let mut handles = Vec::with_capacity(COMMUNITY_NODE_LENGTH);
let node_vec = Arc::new(Mutex::new(Vec::with_capacity(COMMUNITY_NODE_LENGTH)));
let node_vec = arc_mut!(Vec::with_capacity(COMMUNITY_NODE_LENGTH));
for ip in NODE_IPS {
let client = client.clone();
@ -381,12 +382,12 @@ impl Ping {
handle.await?;
}
let node_vec = std::mem::take(&mut *node_vec.lock().unwrap());
let node_vec = std::mem::take(&mut *lock!(node_vec));
let fastest_info = format!("Fastest node: {}ms ... {} @ {}", node_vec[0].ms, node_vec[0].id, node_vec[0].ip);
let info = "Cleaning up connections".to_string();
info!("Ping | {}...", info);
let mut ping = ping.lock().unwrap();
let mut ping = lock!(ping);
ping.fastest = node_vec[0].id;
ping.nodes = node_vec;
ping.msg = info;
@ -421,11 +422,11 @@ impl Ping {
} else {
color = BLACK;
}
let mut ping = ping.lock().unwrap();
let mut ping = lock!(ping);
ping.msg = info;
ping.prog += percent;
drop(ping);
node_vec.lock().unwrap().push(NodeData { id: ip_to_enum(ip), ip, ms, color, });
lock!(node_vec).push(NodeData { id: ip_to_enum(ip), ip, ms, color, });
}
}

View file

@ -21,6 +21,7 @@ use crate::{
disk::*,
node::*,
helper::*,
macros::*,
};
use egui::{
TextEdit,SelectableLabel,ComboBox,Label,Button,
@ -44,7 +45,7 @@ impl crate::disk::P2pool {
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
egui::ScrollArea::vertical().stick_to_bottom(true).max_width(width).max_height(height).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
ui.add_sized([width, height], TextEdit::multiline(&mut api.lock().unwrap().output.as_str()));
ui.add_sized([width, height], TextEdit::multiline(&mut lock!(api).output.as_str()));
});
});
//---------------------------------------------------------------------------------------------------- [Advanced] Console
@ -55,7 +56,7 @@ impl crate::disk::P2pool {
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
egui::ScrollArea::vertical().stick_to_bottom(true).max_width(width).max_height(height).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
ui.add_sized([width, height], TextEdit::multiline(&mut api.lock().unwrap().output.as_str()));
ui.add_sized([width, height], TextEdit::multiline(&mut lock!(api).output.as_str()));
});
});
ui.separator();
@ -64,7 +65,7 @@ impl crate::disk::P2pool {
if response.lost_focus() && ui.input().key_pressed(egui::Key::Enter) {
response.request_focus(); // Get focus back
let buffer = std::mem::take(buffer); // Take buffer
let mut process = process.lock().unwrap(); // Lock
let mut process = lock!(process); // Lock
if process.is_alive() { process.input.push(buffer); } // Push only if alive
}
}
@ -122,7 +123,7 @@ impl crate::disk::P2pool {
// Two atomic bools = enough to represent this data
debug!("P2Pool Tab | Running [auto-select] check");
if self.auto_select {
let mut ping = ping.lock().unwrap();
let mut ping = lock!(ping);
// If we haven't auto_selected yet, auto-select and turn it off
if ping.pinged && !ping.auto_selected {
self.node = ping.fastest;
@ -139,8 +140,8 @@ impl crate::disk::P2pool {
let ip = enum_to_ip(id);
let mut ms = 0;
let mut color = Color32::LIGHT_GRAY;
if ping.lock().unwrap().pinged {
for data in ping.lock().unwrap().nodes.iter() {
if lock!(ping).pinged {
for data in lock!(ping).nodes.iter() {
if data.id == id {
ms = data.ms;
color = data.color;
@ -151,7 +152,7 @@ impl crate::disk::P2pool {
debug!("P2Pool Tab | Rendering [ComboBox] of Community Nodes");
let text = RichText::new(format!("{}ms | {} | {}", ms, id, ip)).color(color);
ComboBox::from_id_source("community_nodes").selected_text(RichText::text_style(text, Monospace)).show_ui(ui, |ui| {
for data in ping.lock().unwrap().nodes.iter() {
for data in lock!(ping).nodes.iter() {
let ms = crate::node::format_ms(data.ms);
let id = crate::node::format_enum(data.id);
let text = RichText::text_style(RichText::new(format!("{} | {} | {}", ms, id, data.ip)).color(data.color), Monospace);
@ -170,18 +171,18 @@ impl crate::disk::P2pool {
self.node = NodeEnum::get_random(&self.node);
}
// [Select fastest node]
if ui.add_sized([width, height], Button::new("Select fastest node")).on_hover_text(P2POOL_SELECT_FASTEST).clicked() && ping.lock().unwrap().pinged {
self.node = ping.lock().unwrap().fastest;
if ui.add_sized([width, height], Button::new("Select fastest node")).on_hover_text(P2POOL_SELECT_FASTEST).clicked() && lock!(ping).pinged {
self.node = lock!(ping).fastest;
}
// [Ping Button]
ui.add_enabled_ui(!ping.lock().unwrap().pinging, |ui| {
ui.add_enabled_ui(!lock!(ping).pinging, |ui| {
if ui.add_sized([width, height], Button::new("Ping community nodes")).on_hover_text(P2POOL_PING).clicked() {
Ping::spawn_thread(ping);
}
});
// [Last <-]
if ui.add_sized([width, height], Button::new("⬅ Last")).on_hover_text(P2POOL_SELECT_LAST).clicked() {
let ping = ping.lock().unwrap();
let ping = lock!(ping);
match ping.pinged {
true => self.node = NodeEnum::get_last_from_ping(&self.node, &ping.nodes),
false => self.node = NodeEnum::get_last(&self.node),
@ -190,7 +191,7 @@ impl crate::disk::P2pool {
}
// [Next ->]
if ui.add_sized([width, height], Button::new("Next ➡")).on_hover_text(P2POOL_SELECT_NEXT).clicked() {
let ping = ping.lock().unwrap();
let ping = lock!(ping);
match ping.pinged {
true => self.node = NodeEnum::get_next_from_ping(&self.node, &ping.nodes),
false => self.node = NodeEnum::get_next(&self.node),
@ -201,10 +202,10 @@ impl crate::disk::P2pool {
ui.vertical(|ui| {
let height = height / 2.0;
let pinging = ping.lock().unwrap().pinging;
let pinging = lock!(ping).pinging;
ui.set_enabled(pinging);
let prog = ping.lock().unwrap().prog.round();
let msg = RichText::text_style(RichText::new(format!("{} ... {}%", ping.lock().unwrap().msg, prog)), Monospace);
let prog = lock!(ping).prog.round();
let msg = RichText::text_style(RichText::new(format!("{} ... {}%", lock!(ping).msg, prog)), Monospace);
let height = height / 1.25;
ui.add_space(5.0);
ui.add_sized([width, height], Label::new(msg));

View file

@ -24,6 +24,7 @@ use crate::{
Sys,
Hash,
Submenu,
macros::*,
};
use std::sync::{Arc,Mutex};
use log::*;
@ -47,7 +48,7 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
ui.set_min_height(min_height);
ui.add_sized([width, height], Label::new(RichText::new("[Gupax]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into())))).on_hover_text("Gupax is online");
ui.style_mut().override_text_style = Some(Monospace);
let sys = sys.lock().unwrap();
let sys = lock!(sys);
ui.add_sized([width, height], Label::new(RichText::new("Uptime").underline().color(BONE))).on_hover_text(STATUS_GUPAX_UPTIME);
ui.add_sized([width, height], Label::new(sys.gupax_uptime.to_string()));
ui.add_sized([width, height], Label::new(RichText::new("Gupax CPU").underline().color(BONE))).on_hover_text(STATUS_GUPAX_CPU_USAGE);
@ -70,7 +71,7 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
ui.add_sized([width, height], Label::new(RichText::new("[P2Pool]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into())))).on_hover_text("P2Pool is online").on_disabled_hover_text("P2Pool is offline");
let height = height/1.4;
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
let api = p2pool_api.lock().unwrap();
let api = lock!(p2pool_api);
ui.add_sized([width, height], Label::new(RichText::new("Uptime").underline().color(BONE))).on_hover_text(STATUS_P2POOL_UPTIME);
ui.add_sized([width, height], Label::new(format!("{}", api.uptime)));
ui.add_sized([width, height], Label::new(RichText::new("Shares Found").underline().color(BONE))).on_hover_text(STATUS_P2POOL_SHARES);
@ -87,7 +88,7 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
ui.add_sized([width, height], Label::new(format!("{}", api.connections)));
ui.add_sized([width, height], Label::new(RichText::new("Effort").underline().color(BONE))).on_hover_text(STATUS_P2POOL_EFFORT);
ui.add_sized([width, height], Label::new(format!("[Average: {}] [Current: {}]", api.average_effort, api.current_effort)));
let img = p2pool_img.lock().unwrap();
let img = lock!(p2pool_img);
ui.add_sized([width, height], Label::new(RichText::new("Monero Node").underline().color(BONE))).on_hover_text(STATUS_P2POOL_MONERO_NODE);
ui.add_sized([width, height], Label::new(format!("[IP: {}]\n[RPC: {}] [ZMQ: {}]", &img.host, &img.rpc, &img.zmq)));
ui.add_sized([width, height], Label::new(RichText::new("Sidechain").underline().color(BONE))).on_hover_text(STATUS_P2POOL_POOL);
@ -104,7 +105,7 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
ui.set_min_height(min_height);
ui.add_sized([width, height], Label::new(RichText::new("[XMRig]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into())))).on_hover_text("XMRig is online").on_disabled_hover_text("XMRig is offline");
ui.style_mut().override_text_style = Some(Monospace);
let api = xmrig_api.lock().unwrap();
let api = lock!(xmrig_api);
ui.add_sized([width, height], Label::new(RichText::new("Uptime").underline().color(BONE))).on_hover_text(STATUS_XMRIG_UPTIME);
ui.add_sized([width, height], Label::new(format!("{}", api.uptime)));
ui.add_sized([width, height], Label::new(RichText::new("CPU Load Averages").underline().color(BONE))).on_hover_text(STATUS_XMRIG_CPU);
@ -116,9 +117,9 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
ui.add_sized([width, height], Label::new(RichText::new("Shares").underline().color(BONE))).on_hover_text(STATUS_XMRIG_SHARES);
ui.add_sized([width, height], Label::new(format!("[Accepted: {}] [Rejected: {}]", api.accepted, api.rejected)));
ui.add_sized([width, height], Label::new(RichText::new("Pool").underline().color(BONE))).on_hover_text(STATUS_XMRIG_POOL);
ui.add_sized([width, height], Label::new(&xmrig_img.lock().unwrap().url));
ui.add_sized([width, height], Label::new(&lock!(xmrig_img).url));
ui.add_sized([width, height], Label::new(RichText::new("Threads").underline().color(BONE))).on_hover_text(STATUS_XMRIG_THREADS);
ui.add_sized([width, height], Label::new(format!("{}/{}", &xmrig_img.lock().unwrap().threads, max_threads)));
ui.add_sized([width, height], Label::new(format!("{}/{}", &lock!(xmrig_img).threads, max_threads)));
drop(api);
})});
});

View file

@ -32,6 +32,7 @@ use crate::{
disk::Xmrig,
ProcessSignal,
constants::*,
macros::*,
};
use log::*;
@ -81,7 +82,7 @@ impl SudoState {
// Resets the state.
pub fn reset(state: &Arc<Mutex<Self>>) {
Self::wipe(state);
let mut state = state.lock().unwrap();
let mut state = lock!(state);
state.testing = false;
state.success = false;
// state.signal = ProcessSignal::None;
@ -92,7 +93,7 @@ impl SudoState {
pub fn wipe(state: &Arc<Mutex<Self>>) {
let mut new = String::with_capacity(256);
// new is now == old, and vice-versa.
std::mem::swap(&mut new, &mut state.lock().unwrap().pass);
std::mem::swap(&mut new, &mut lock!(state).pass);
// we're wiping & dropping the old pass here.
new.zeroize();
std::mem::drop(new);
@ -108,7 +109,7 @@ impl SudoState {
let path = path.clone();
thread::spawn(move || {
// Set to testing
state.lock().unwrap().testing = true;
lock!(state).testing = true;
// Make sure sudo timestamp is reset
let reset = Command::new("sudo")
@ -122,8 +123,8 @@ impl SudoState {
Err(e) => {
error!("Sudo | Couldn't reset timestamp: {}", e);
Self::wipe(&state);
state.lock().unwrap().msg = format!("Sudo error: {}", e);
state.lock().unwrap().testing = false;
lock!(state).msg = format!("Sudo error: {}", e);
lock!(state).testing = false;
return
},
}
@ -139,7 +140,7 @@ impl SudoState {
// Write pass to STDIN
let mut stdin = sudo.stdin.take().unwrap();
stdin.write_all(state.lock().unwrap().pass.as_bytes()).unwrap();
stdin.write_all(lock!(state).pass.as_bytes()).unwrap();
drop(stdin);
// Sudo re-prompts and will hang.
@ -149,7 +150,7 @@ impl SudoState {
match sudo.try_wait() {
Ok(Some(code)) => if code.success() {
info!("Sudo | Password ... OK!");
state.lock().unwrap().success = true;
lock!(state).success = true;
break
},
Ok(None) => {
@ -159,25 +160,25 @@ impl SudoState {
Err(e) => {
error!("Sudo | Couldn't reset timestamp: {}", e);
Self::wipe(&state);
state.lock().unwrap().msg = format!("Sudo error: {}", e);
state.lock().unwrap().testing = false;
lock!(state).msg = format!("Sudo error: {}", e);
lock!(state).testing = false;
return
},
}
}
if let Err(e) = sudo.kill() { warn!("Sudo | Kill error (it probably already exited): {}", e); }
if state.lock().unwrap().success {
match state.lock().unwrap().signal {
if lock!(state).success {
match lock!(state).signal {
ProcessSignal::Restart => crate::helper::Helper::restart_xmrig(&helper, &xmrig, &path, Arc::clone(&state)),
ProcessSignal::Stop => crate::helper::Helper::stop_xmrig(&helper),
_ => crate::helper::Helper::start_xmrig(&helper, &xmrig, &path, Arc::clone(&state)),
}
} else {
state.lock().unwrap().msg = "Incorrect password! (or sudo timeout)".to_string();
lock!(state).msg = "Incorrect password! (or sudo timeout)".to_string();
Self::wipe(&state);
}
state.lock().unwrap().signal = ProcessSignal::None;
state.lock().unwrap().testing = false;
lock!(state).signal = ProcessSignal::None;
lock!(state).testing = false;
});
}
}

View file

@ -33,6 +33,7 @@ use crate::{
update::Name::*,
ErrorState,ErrorFerris,ErrorButtons,
Restart,
macros::*,
};
use hyper::{
Client,Body,Request,
@ -265,9 +266,9 @@ impl Update {
path_p2pool: path_p2pool.display().to_string(),
path_xmrig: path_xmrig.display().to_string(),
tmp_dir: "".to_string(),
updating: Arc::new(Mutex::new(false)),
prog: Arc::new(Mutex::new(0.0)),
msg: Arc::new(Mutex::new(MSG_NONE.to_string())),
updating: arc_mut!(false),
prog: arc_mut!(0.0),
msg: arc_mut!(MSG_NONE.to_string()),
tor,
}
}
@ -392,13 +393,13 @@ impl Update {
return;
}
update.lock().unwrap().path_p2pool = p2pool_path.display().to_string();
update.lock().unwrap().path_xmrig = xmrig_path.display().to_string();
update.lock().unwrap().tor = gupax.update_via_tor;
lock!(update).path_p2pool = p2pool_path.display().to_string();
lock!(update).path_xmrig = xmrig_path.display().to_string();
lock!(update).tor = gupax.update_via_tor;
// Clone before thread spawn
let og = Arc::clone(og);
let state_ver = Arc::clone(&og.lock().unwrap().version);
let state_ver = Arc::clone(&lock!(og).version);
let state_path = state_path.to_path_buf();
let update = Arc::clone(update);
let restart = Arc::clone(restart);
@ -407,23 +408,23 @@ impl Update {
match Update::start(update.clone(), og.clone(), state_ver.clone(), restart) {
Ok(_) => {
info!("Update | Saving state...");
let original_version = og.lock().unwrap().version.clone();
og.lock().unwrap().version = state_ver;
match State::save(&mut og.lock().unwrap(), &state_path) {
let original_version = lock!(og).version.clone();
lock!(og).version = state_ver;
match State::save(&mut lock!(og), &state_path) {
Ok(_) => info!("Update ... OK"),
Err(e) => {
warn!("Update | Saving state ... FAIL: {}", e);
og.lock().unwrap().version = original_version;
*update.lock().unwrap().msg.lock().unwrap() = "Saving new versions into state failed".to_string();
lock!(og).version = original_version;
*lock2!(update,msg) = "Saving new versions into state failed".to_string();
},
};
}
Err(e) => {
info!("Update ... FAIL: {}", e);
*update.lock().unwrap().msg.lock().unwrap() = format!("{} | {}", MSG_FAILED, e);
*lock2!(update,msg) = format!("{} | {}", MSG_FAILED, e);
},
};
*update.lock().unwrap().updating.lock().unwrap() = false;
*lock2!(update,updating) = false;
});
}
@ -442,19 +443,19 @@ impl Update {
return Err(anyhow!("This is the [Linux distro] version of Gupax, updates are disabled"));
//---------------------------------------------------------------------------------------------------- Init
*update.lock().unwrap().updating.lock().unwrap() = true;
*lock2!(update,updating) = true;
// Set timer
let now = std::time::Instant::now();
// Set progress bar
*update.lock().unwrap().msg.lock().unwrap() = MSG_START.to_string();
*update.lock().unwrap().prog.lock().unwrap() = 0.0;
*lock2!(update,msg) = MSG_START.to_string();
*lock2!(update,prog) = 0.0;
info!("Update | {}", INIT);
// Get temporary directory
let msg = MSG_TMP.to_string();
info!("Update | {}", msg);
*update.lock().unwrap().msg.lock().unwrap() = msg;
*lock2!(update,msg) = msg;
let tmp_dir = Self::get_tmp_dir()?;
std::fs::create_dir(&tmp_dir)?;
@ -467,27 +468,27 @@ impl Update {
// Generate fake user-agent
let user_agent = Pkg::get_user_agent();
*update.lock().unwrap().prog.lock().unwrap() = 5.0;
*lock2!(update,prog) = 5.0;
// Create Tor/HTTPS client
let lock = update.lock().unwrap();
let lock = lock!(update);
let tor = lock.tor;
if tor {
let msg = MSG_TOR.to_string();
info!("Update | {}", msg);
*lock.msg.lock().unwrap() = msg;
*lock!(lock.msg) = msg;
} else {
let msg = MSG_HTTPS.to_string();
info!("Update | {}", msg);
*lock.msg.lock().unwrap() = msg;
*lock!(lock.msg) = msg;
}
drop(lock);
let mut client = Self::get_client(tor)?;
*update.lock().unwrap().prog.lock().unwrap() += 5.0;
info!("Update | Init ... OK ... {}%", update.lock().unwrap().prog.lock().unwrap());
*lock2!(update,prog) += 5.0;
info!("Update | Init ... OK ... {}%", lock2!(update,prog));
//---------------------------------------------------------------------------------------------------- Metadata
*update.lock().unwrap().msg.lock().unwrap() = MSG_METADATA.to_string();
*lock2!(update,msg) = MSG_METADATA.to_string();
info!("Update | {}", METADATA);
let mut vec2 = vec![];
// Loop process:
@ -502,7 +503,7 @@ impl Update {
// function itself but for some reason, it was getting skipped over,
// so the [new_ver] check is now here, in the outer scope.
for i in 1..=3 {
if i > 1 { *update.lock().unwrap().msg.lock().unwrap() = format!("{} [{}/3]", MSG_METADATA_RETRY, i); }
if i > 1 { *lock2!(update,msg) = format!("{} [{}/3]", MSG_METADATA_RETRY, i); }
let mut handles: Vec<JoinHandle<Result<(), anyhow::Error>>> = vec![];
for pkg in vec.iter() {
// Clone data before sending to async
@ -528,13 +529,13 @@ impl Update {
// Check for empty version
let mut indexes = vec![];
for (index, pkg) in vec.iter().enumerate() {
if pkg.new_ver.lock().unwrap().is_empty() {
if lock!(pkg.new_ver).is_empty() {
warn!("Update | {} failed, attempt [{}/3]...", pkg.name, i+1);
} else {
indexes.push(index);
vec2.push(pkg.clone());
*update.lock().unwrap().prog.lock().unwrap() += 10.0;
info!("Update | {} {} ... OK", pkg.name, pkg.new_ver.lock().unwrap());
*lock2!(update,prog) += 10.0;
info!("Update | {} {} ... OK", pkg.name, lock!(pkg.new_ver));
}
}
// Order indexes from biggest to smallest
@ -553,19 +554,19 @@ impl Update {
}
}
if vec.is_empty() {
info!("Update | Metadata ... OK ... {}%", update.lock().unwrap().prog.lock().unwrap());
info!("Update | Metadata ... OK ... {}%", lock2!(update,prog));
} else {
error!("Update | Metadata ... FAIL");
return Err(anyhow!("Metadata fetch failed"))
}
//---------------------------------------------------------------------------------------------------- Compare
*update.lock().unwrap().msg.lock().unwrap() = MSG_COMPARE.to_string();
*lock2!(update,msg) = MSG_COMPARE.to_string();
info!("Update | {}", COMPARE);
let mut vec3 = vec![];
let mut new_pkgs = vec![];
for pkg in vec2.iter() {
let new_ver = pkg.new_ver.lock().unwrap().clone();
let new_ver = lock!(pkg.new_ver).clone();
let diff;
let old_ver;
let name;
@ -575,17 +576,17 @@ impl Update {
// that gets updated during an update. This prevents the updater always thinking
// there's a new Gupax update since the user didnt restart and is still technically
// using the old version (even though the underlying binary was updated).
old_ver = state_ver.lock().unwrap().gupax.clone();
old_ver = lock!(state_ver).gupax.clone();
diff = old_ver != new_ver && GUPAX_VERSION != new_ver;
name = "Gupax";
}
P2pool => {
old_ver = state_ver.lock().unwrap().p2pool.clone();
old_ver = lock!(state_ver).p2pool.clone();
diff = old_ver != new_ver;
name = "P2Pool";
}
Xmrig => {
old_ver = state_ver.lock().unwrap().xmrig.clone();
old_ver = lock!(state_ver).xmrig.clone();
diff = old_ver != new_ver;
name = "XMRig";
}
@ -598,32 +599,32 @@ impl Update {
info!("Update | {} {} == {} ... SKIPPING", pkg.name, old_ver, new_ver);
}
}
*update.lock().unwrap().prog.lock().unwrap() += 5.0;
info!("Update | Compare ... OK ... {}%", update.lock().unwrap().prog.lock().unwrap());
*lock2!(update,prog) += 5.0;
info!("Update | Compare ... OK ... {}%", lock2!(update,prog));
// Return if 0 (all packages up-to-date)
// Get amount of packages to divide up the percentage increases
let pkg_amount = vec3.len() as f32;
if pkg_amount == 0.0 {
info!("Update | All packages up-to-date ... RETURNING");
*update.lock().unwrap().prog.lock().unwrap() = 100.0;
*update.lock().unwrap().msg.lock().unwrap() = MSG_UP_TO_DATE.to_string();
*lock2!(update,prog) = 100.0;
*lock2!(update,msg) = MSG_UP_TO_DATE.to_string();
return Ok(())
}
let new_pkgs: String = new_pkgs.concat();
//---------------------------------------------------------------------------------------------------- Download
*update.lock().unwrap().msg.lock().unwrap() = format!("{}{}", MSG_DOWNLOAD, new_pkgs);
*lock2!(update,msg) = format!("{}{}", MSG_DOWNLOAD, new_pkgs);
info!("Update | {}", DOWNLOAD);
let mut vec4 = vec![];
for i in 1..=3 {
if i > 1 { *update.lock().unwrap().msg.lock().unwrap() = format!("{} [{}/3]{}", MSG_DOWNLOAD_RETRY, i, new_pkgs); }
if i > 1 { *lock2!(update,msg) = format!("{} [{}/3]{}", MSG_DOWNLOAD_RETRY, i, new_pkgs); }
let mut handles: Vec<JoinHandle<Result<(), anyhow::Error>>> = vec![];
for pkg in vec3.iter() {
// Clone data before async
let bytes = Arc::clone(&pkg.bytes);
let client = client.clone();
let version = pkg.new_ver.lock().unwrap();
let version = lock!(pkg.new_ver);
// 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-x64-standalone
// XMRig doesn't have a [v], so slice it out
@ -647,12 +648,12 @@ impl Update {
// Check for empty bytes
let mut indexes = vec![];
for (index, pkg) in vec3.iter().enumerate() {
if pkg.bytes.lock().unwrap().is_empty() {
if lock!(pkg.bytes).is_empty() {
warn!("Update | {} failed, attempt [{}/3]...", pkg.name, i);
} else {
indexes.push(index);
vec4.push(pkg.clone());
*update.lock().unwrap().prog.lock().unwrap() += (30.0 / pkg_amount).round();
*lock2!(update,prog) += (30.0 / pkg_amount).round();
info!("Update | {} ... OK", pkg.name);
}
}
@ -666,14 +667,14 @@ impl Update {
if vec3.is_empty() { break }
}
if vec3.is_empty() {
info!("Update | Download ... OK ... {}%", *update.lock().unwrap().prog.lock().unwrap());
info!("Update | Download ... OK ... {}%", *lock2!(update,prog));
} else {
error!("Update | Download ... FAIL");
return Err(anyhow!("Download failed"))
}
//---------------------------------------------------------------------------------------------------- Extract
*update.lock().unwrap().msg.lock().unwrap() = format!("{}{}", MSG_EXTRACT, new_pkgs);
*lock2!(update,msg) = format!("{}{}", MSG_EXTRACT, new_pkgs);
info!("Update | {}", EXTRACT);
for pkg in vec4.iter() {
let tmp = match pkg.name {
@ -681,20 +682,20 @@ impl Update {
_ => 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)?;
ZipArchive::extract(&mut ZipArchive::new(std::io::Cursor::new(lock!(pkg.bytes).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();
tar::Archive::new(flate2::read::GzDecoder::new(lock!(pkg.bytes).as_ref())).unpack(tmp)?;
*lock2!(update,prog) += (5.0 / pkg_amount).round();
info!("Update | {} ... OK", pkg.name);
}
info!("Update | Extract ... OK ... {}%", *update.lock().unwrap().prog.lock().unwrap());
info!("Update | Extract ... OK ... {}%", *lock2!(update,prog));
//---------------------------------------------------------------------------------------------------- Upgrade
// 1. Walk directories
// 2. If basename matches known binary name, start
// 3. Rename tmp path into current path
// 4. Update [State/Version]
*update.lock().unwrap().msg.lock().unwrap() = format!("{}{}", MSG_UPGRADE, new_pkgs);
*lock2!(update,msg) = format!("{}{}", MSG_UPGRADE, new_pkgs);
info!("Update | {}", UPGRADE);
// If this bool doesn't get set, something has gone wrong because
// we _didn't_ find a binary even though we downloaded it.
@ -715,9 +716,9 @@ impl Update {
_ => Xmrig,
};
let path = match name {
Gupax => update.lock().unwrap().path_gupax.clone(),
P2pool => update.lock().unwrap().path_p2pool.clone(),
Xmrig => update.lock().unwrap().path_xmrig.clone(),
Gupax => lock!(update).path_gupax.clone(),
P2pool => lock!(update).path_p2pool.clone(),
Xmrig => lock!(update).path_xmrig.clone(),
};
let path = Path::new(&path);
// Unix can replace running binaries no problem (they're loaded into memory)
@ -745,14 +746,14 @@ impl Update {
// Update [State] version
match name {
Gupax => {
state_ver.lock().unwrap().gupax = Pkg::get_new_pkg_version(Gupax, &vec4)?;
lock!(state_ver).gupax = Pkg::get_new_pkg_version(Gupax, &vec4)?;
// If we're updating Gupax, set the [Restart] state so that the user knows to restart
*restart.lock().unwrap() = Restart::Yes;
*lock!(restart) = Restart::Yes;
},
P2pool => state_ver.lock().unwrap().p2pool = Pkg::get_new_pkg_version(P2pool, &vec4)?,
Xmrig => state_ver.lock().unwrap().xmrig = Pkg::get_new_pkg_version(Xmrig, &vec4)?,
P2pool => lock!(state_ver).p2pool = Pkg::get_new_pkg_version(P2pool, &vec4)?,
Xmrig => lock!(state_ver).xmrig = Pkg::get_new_pkg_version(Xmrig, &vec4)?,
};
*update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round();
*lock2!(update,prog) += (5.0 / pkg_amount).round();
},
_ => (),
}
@ -768,11 +769,11 @@ impl Update {
let seconds = now.elapsed().as_secs();
info!("Update | Seconds elapsed ... [{}s]", seconds);
match seconds {
0 => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took 0 seconds... What...?!{}", MSG_SUCCESS, new_pkgs),
1 => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took 1 second... Wow!{}", MSG_SUCCESS, new_pkgs),
_ => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took {} seconds.{}", MSG_SUCCESS, seconds, new_pkgs),
0 => *lock2!(update,msg) = format!("{}! Took 0 seconds... What...?!{}", MSG_SUCCESS, new_pkgs),
1 => *lock2!(update,msg) = format!("{}! Took 1 second... Wow!{}", MSG_SUCCESS, new_pkgs),
_ => *lock2!(update,msg) = format!("{}! Took {} seconds.{}", MSG_SUCCESS, seconds, new_pkgs),
}
*update.lock().unwrap().prog.lock().unwrap() = 100.0;
*lock2!(update,prog) = 100.0;
Ok(())
}
}
@ -823,8 +824,8 @@ impl Pkg {
link_prefix,
link_suffix,
link_extension,
bytes: Arc::new(Mutex::new(bytes::Bytes::new())),
new_ver: Arc::new(Mutex::new(String::new())),
bytes: arc_mut!(bytes::Bytes::new()),
new_ver: arc_mut!(String::new()),
}
}
@ -855,7 +856,7 @@ impl Pkg {
let mut response = client.request(request).await?;
let body = hyper::body::to_bytes(response.body_mut()).await?;
let body: TagName = serde_json::from_slice(&body)?;
*new_ver.lock().unwrap() = body.tag_name;
*lock!(new_ver) = body.tag_name;
Ok(())
}
@ -873,7 +874,7 @@ impl Pkg {
response = client.request(request).await?;
}
let body = hyper::body::to_bytes(response.into_body()).await?;
*bytes.lock().unwrap() = body;
*lock!(bytes) = body;
Ok(())
}
@ -882,7 +883,7 @@ impl Pkg {
fn get_new_pkg_version(name: Name, vec: &[&Pkg]) -> Result<String, Error> {
for pkg in vec.iter() {
if pkg.name == name {
return Ok(pkg.new_ver.lock().unwrap().to_string())
return Ok(lock!(pkg.new_ver).to_string())
}
}
Err(anyhow!("Couldn't find new_pkg_version"))

View file

@ -21,6 +21,7 @@ use crate::{
disk::*,
Process,
PubXmrigApi,
macros::*,
};
use egui::{
TextEdit,SelectableLabel,ComboBox,Label,Button,RichText,Slider,Checkbox,
@ -45,7 +46,7 @@ impl crate::disk::Xmrig {
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
egui::ScrollArea::vertical().stick_to_bottom(true).max_width(width).max_height(height).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
ui.add_sized([width, height], TextEdit::multiline(&mut api.lock().unwrap().output.as_str()));
ui.add_sized([width, height], TextEdit::multiline(&mut lock!(api).output.as_str()));
});
});
//---------------------------------------------------------------------------------------------------- [Advanced] Console
@ -56,7 +57,7 @@ impl crate::disk::Xmrig {
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
egui::ScrollArea::vertical().stick_to_bottom(true).max_width(width).max_height(height).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
ui.add_sized([width, height], TextEdit::multiline(&mut api.lock().unwrap().output.as_str()));
ui.add_sized([width, height], TextEdit::multiline(&mut lock!(api).output.as_str()));
});
});
ui.separator();
@ -65,7 +66,7 @@ impl crate::disk::Xmrig {
if response.lost_focus() && ui.input().key_pressed(egui::Key::Enter) {
response.request_focus(); // Get focus back
let buffer = std::mem::take(buffer); // Take buffer
let mut process = process.lock().unwrap(); // Lock
let mut process = lock!(process); // Lock
if process.is_alive() { process.input.push(buffer); } // Push only if alive
}
}