feat: integrate monerod

This commit is contained in:
Cyrix126 2024-10-05 18:52:18 +02:00
parent bfcaebb82f
commit 40f85893c6
23 changed files with 1641 additions and 173 deletions

View file

@ -52,6 +52,12 @@ impl eframe::App for App {
let xvb_is_waiting = xvb.is_waiting();
let xvb_state = xvb.state;
drop(xvb);
debug!("App | Locking and collecting Node state...");
let node = lock!(self.node);
let node_is_alive = node.is_alive();
let node_is_waiting = node.is_waiting();
let node_state = node.state;
drop(node);
// This sets the top level Ui dimensions.
// Used as a reference for other uis.
@ -101,6 +107,7 @@ impl eframe::App for App {
self.top_panel(ctx);
self.bottom_panel(
ctx,
node_state,
p2pool_state,
xmrig_state,
xmrig_proxy_state,
@ -109,10 +116,12 @@ impl eframe::App for App {
wants_input,
p2pool_is_waiting,
xmrig_is_waiting,
node_is_waiting,
xmrig_proxy_is_waiting,
xvb_is_waiting,
p2pool_is_alive,
xmrig_is_alive,
node_is_alive,
xmrig_proxy_is_alive,
xvb_is_alive,
);
@ -124,6 +133,7 @@ impl eframe::App for App {
ctx,
frame,
key,
node_is_alive,
p2pool_is_alive,
xmrig_is_alive,
xmrig_proxy_is_alive,

View file

@ -126,7 +126,8 @@ impl App {
Tab::About => self.tab = Tab::Xvb,
Tab::Status => self.tab = Tab::About,
Tab::Gupax => self.tab = Tab::Status,
Tab::P2pool => self.tab = Tab::Gupax,
Tab::Node => self.tab = Tab::Gupax,
Tab::P2pool => self.tab = Tab::Node,
Tab::Xmrig => self.tab = Tab::P2pool,
Tab::XmrigProxy => self.tab = Tab::Xmrig,
Tab::Xvb => self.tab = Tab::XmrigProxy,
@ -136,7 +137,8 @@ impl App {
match self.tab {
Tab::About => self.tab = Tab::Status,
Tab::Status => self.tab = Tab::Gupax,
Tab::Gupax => self.tab = Tab::P2pool,
Tab::Gupax => self.tab = Tab::Node,
Tab::Node => self.tab = Tab::P2pool,
Tab::P2pool => self.tab = Tab::Xmrig,
Tab::Xmrig => self.tab = Tab::XmrigProxy,
Tab::XmrigProxy => self.tab = Tab::Xvb,
@ -151,6 +153,7 @@ impl App {
Submenu::Benchmarks => self.state.status.submenu = Submenu::P2pool,
},
Tab::Gupax => flip!(self.state.gupax.simple),
Tab::Node => flip!(self.state.node.simple),
Tab::P2pool => flip!(self.state.p2pool.simple),
Tab::Xmrig => flip!(self.state.xmrig.simple),
Tab::XmrigProxy => flip!(self.state.xmrig_proxy.simple),
@ -170,6 +173,7 @@ impl App {
Tab::Xmrig => flip!(self.state.xmrig.simple),
Tab::XmrigProxy => flip!(self.state.xmrig_proxy.simple),
Tab::Xvb => flip!(self.state.xvb.simple),
Tab::Node => flip!(self.state.node.simple),
Tab::About => (),
};
}

View file

@ -16,6 +16,7 @@ use crate::disk::state::State;
use crate::errors::ErrorButtons;
use crate::errors::ErrorFerris;
use crate::errors::ErrorState;
use crate::helper::node::PubNodeApi;
use crate::helper::p2pool::ImgP2pool;
use crate::helper::p2pool::PubP2poolApi;
use crate::helper::xrig::xmrig::ImgXmrig;
@ -103,10 +104,12 @@ pub struct App {
// This includes the "helper" threads public P2Pool/XMRig's API.
pub helper: Arc<Mutex<Helper>>, // [Helper] state, mostly for Gupax uptime
pub pub_sys: Arc<Mutex<Sys>>, // [Sys] state, read by [Status], mutated by [Helper]
pub node: Arc<Mutex<Process>>, // [Node] process state
pub p2pool: Arc<Mutex<Process>>, // [P2Pool] process state
pub xmrig: Arc<Mutex<Process>>, // [XMRig] process state
pub xmrig_proxy: Arc<Mutex<Process>>, // [XMRig-Proxy] process state
pub xvb: Arc<Mutex<Process>>, // [Xvb] process state
pub node_api: Arc<Mutex<PubNodeApi>>, // Public ready-to-print node API made by the "helper" thread
pub p2pool_api: Arc<Mutex<PubP2poolApi>>, // Public ready-to-print P2Pool API made by the "helper" thread
pub xmrig_api: Arc<Mutex<PubXmrigApi>>, // Public ready-to-print XMRig API made by the "helper" thread
pub xmrig_proxy_api: Arc<Mutex<PubXmrigProxyApi>>, // Public ready-to-print XMRigProxy API made by the "helper" thread
@ -114,8 +117,9 @@ pub struct App {
pub p2pool_img: Arc<Mutex<ImgP2pool>>, // A one-time snapshot of what data P2Pool started with
pub xmrig_img: Arc<Mutex<ImgXmrig>>, // A one-time snapshot of what data XMRig started with
// STDIN Buffer
pub node_stdin: String, // The buffer between the node console and the [Helper]
pub p2pool_stdin: String, // The buffer between the p2pool console and the [Helper]
pub xmrig_stdin: String, // The buffer between the xmrig console and the [Helper]
pub xmrig_stdin: String, // The buffer between the xmrig console and the [Helper]
pub xmrig_proxy_stdin: String, // The buffer between the xmrig-proxy console and the [Helper]
// Sudo State
pub sudo: Arc<Mutex<SudoState>>, // This is just a dummy struct on [Windows].
@ -200,10 +204,16 @@ impl App {
String::new(),
PathBuf::new()
));
let node = arc_mut!(Process::new(
ProcessName::Node,
String::new(),
PathBuf::new()
));
let p2pool_api = arc_mut!(PubP2poolApi::new());
let xmrig_api = arc_mut!(PubXmrigApi::new());
let xmrig_proxy_api = arc_mut!(PubXmrigProxyApi::new());
let xvb_api = arc_mut!(PubXvbApi::new());
let node_api = arc_mut!(PubNodeApi::new());
let p2pool_img = arc_mut!(ImgP2pool::new());
let xmrig_img = arc_mut!(ImgXmrig::new());
@ -248,6 +258,7 @@ impl App {
String::new(),
PathBuf::new(),
PathBuf::new(),
PathBuf::new(),
PathBuf::new()
)),
file_window: FileWindow::new(),
@ -265,24 +276,29 @@ impl App {
xmrig.clone(),
xmrig_proxy.clone(),
xvb.clone(),
node.clone(),
p2pool_api.clone(),
xmrig_api.clone(),
xvb_api.clone(),
xmrig_proxy_api.clone(),
node_api.clone(),
p2pool_img.clone(),
xmrig_img.clone(),
arc_mut!(GupaxP2poolApi::new())
)),
node,
p2pool,
xmrig,
xmrig_proxy,
xvb,
node_api,
p2pool_api,
xvb_api,
xmrig_api,
xmrig_proxy_api,
p2pool_img,
xmrig_img,
node_stdin: String::with_capacity(10),
p2pool_stdin: String::with_capacity(10),
xmrig_stdin: String::with_capacity(10),
xmrig_proxy_stdin: String::with_capacity(10),
@ -555,6 +571,7 @@ impl App {
// Apply TOML values to [Update]
info!("App Init | Applying TOML values to [Update]...");
let node_path = og.gupax.absolute_node_path.clone();
let p2pool_path = og.gupax.absolute_p2pool_path.clone();
let xmrig_path = og.gupax.absolute_xmrig_path.clone();
let xmrig_proxy_path = og.gupax.absolute_xp_path.clone();
@ -562,7 +579,8 @@ impl App {
app.exe.clone(),
p2pool_path,
xmrig_path,
xmrig_proxy_path
xmrig_proxy_path,
node_path
));
// Set state version as compiled in version
@ -688,6 +706,7 @@ pub enum Tab {
About,
Status,
Gupax,
Node,
P2pool,
Xmrig,
XmrigProxy,

View file

@ -22,6 +22,7 @@ impl crate::app::App {
pub fn bottom_panel(
&mut self,
ctx: &egui::Context,
node_state: ProcessState,
p2pool_state: ProcessState,
xmrig_state: ProcessState,
xmrig_proxy_state: ProcessState,
@ -30,10 +31,12 @@ impl crate::app::App {
wants_input: bool,
p2pool_is_waiting: bool,
xmrig_is_waiting: bool,
node_is_waiting: bool,
xmrig_proxy_is_waiting: bool,
xvb_is_waiting: bool,
p2pool_is_alive: bool,
xmrig_is_alive: bool,
node_is_alive: bool,
xmrig_proxy_is_alive: bool,
xvb_is_alive: bool,
) {
@ -74,6 +77,8 @@ impl crate::app::App {
ui.label(self.os);
// ui.add_sized(size, Label::new(self.os));
ui.separator();
status_node(node_state, ui, size);
ui.separator();
status_p2pool(p2pool_state, ui, size);
ui.separator();
status_xmrig(xmrig_state, ui, size);
@ -96,6 +101,17 @@ impl crate::app::App {
Tab::Gupax => {
self.gupax_submenu(ui, height);
}
Tab::Node => {
self.node_submenu(ui, size);
self.node_run_actions(
ui,
height,
node_is_waiting,
node_is_alive,
wants_input,
key,
);
}
Tab::P2pool => {
self.p2pool_submenu(ui, size);
self.p2pool_run_actions(
@ -309,6 +325,30 @@ impl crate::app::App {
}
});
}
fn node_submenu(&mut self, ui: &mut Ui, size: Vec2) {
ui.group(|ui| {
let width = size.x / 1.5;
let size = vec2(width, size.y);
if ui
.add_sized(
size,
SelectableLabel::new(!self.state.node.simple, "Advanced"),
)
.on_hover_text(NODE_ADVANCED)
.clicked()
{
self.state.node.simple = false;
}
ui.separator();
if ui
.add_sized(size, SelectableLabel::new(self.state.node.simple, "Simple"))
.on_hover_text(NODE_SIMPLE)
.clicked()
{
self.state.node.simple = true;
}
});
}
fn p2pool_run_actions(
&mut self,
ui: &mut Ui,
@ -405,6 +445,95 @@ impl crate::app::App {
}
});
}
fn node_run_actions(
&mut self,
ui: &mut Ui,
height: f32,
node_is_waiting: bool,
node_is_alive: bool,
wants_input: bool,
key: &KeyPressed,
) {
ui.group(|ui| {
let width = ((ui.available_width() / 3.0) - 5.0).max(0.0);
let size = vec2(width, height);
if node_is_waiting {
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(NODE_MIDDLE);
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(NODE_MIDDLE);
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(NODE_MIDDLE);
});
} else if node_is_alive {
if key.is_up() && !wants_input
|| ui
.add_sized(size, Button::new(""))
.on_hover_text("Restart node")
.clicked()
{
let _ = lock!(self.og).update_absolute_path();
let _ = self.state.update_absolute_path();
Helper::restart_node(
&self.helper,
&self.state.node,
&self.state.gupax.absolute_node_path,
);
}
if key.is_down() && !wants_input
|| ui
.add_sized(size, Button::new(""))
.on_hover_text("Stop node")
.clicked()
{
Helper::stop_node(&self.helper);
}
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Start node");
});
} else {
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Restart node");
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Stop node");
});
// Check if path is okay before allowing to start.
let mut text = String::new();
let mut ui_enabled = true;
if !Gupax::path_is_file(&self.state.gupax.node_path) {
ui_enabled = false;
text = format!("Error: {}", NODE_PATH_NOT_FILE);
} else if !crate::components::update::check_node_path(&self.state.gupax.node_path) {
ui_enabled = false;
text = format!("Error: {}", NODE_PATH_NOT_VALID);
} else if process_running(crate::helper::ProcessName::Node) {
ui_enabled = false;
text = format!("Error: {}", PROCESS_OUTSIDE);
}
ui.add_enabled_ui(ui_enabled, |ui| {
let color = if ui_enabled { GREEN } else { RED };
if (ui_enabled && key.is_up() && !wants_input)
|| ui
.add_sized(size, Button::new(RichText::new("").color(color)))
.on_hover_text("Start Node")
.on_disabled_hover_text(text)
.clicked()
{
let _ = lock!(self.og).update_absolute_path();
let _ = self.state.update_absolute_path();
Helper::start_node(
&self.helper,
&self.state.node,
&self.state.gupax.absolute_node_path,
);
}
});
}
});
}
fn xmrig_submenu(&mut self, ui: &mut Ui, size: Vec2) {
ui.group(|ui| {
let width = size.x / 1.5;
@ -790,6 +919,32 @@ fn status_p2pool(state: ProcessState, ui: &mut Ui, size: Vec2) {
};
status(ui, color, hover_text, size, "P2pool ⏺");
}
fn status_node(state: ProcessState, ui: &mut Ui, size: Vec2) {
let color;
let hover_text = match state {
Alive => {
color = GREEN;
NODE_ALIVE
}
Dead => {
color = GRAY;
NODE_DEAD
}
Failed => {
color = RED;
NODE_FAILED
}
Syncing => {
color = ORANGE;
NODE_SYNCING
}
Middle | Waiting | NotMining | OfflineNodesAll | Retry => {
color = YELLOW;
NODE_MIDDLE
}
};
status(ui, color, hover_text, size, "Node ⏺");
}
fn status_xmrig(state: ProcessState, ui: &mut Ui, size: Vec2) {
let color;

View file

@ -88,43 +88,48 @@ impl Gupax {
debug!("Gupaxx Tab | Rendering bool buttons");
ui.horizontal(|ui| {
ui.group(|ui| {
let width = (size.x - SPACE * 17.0) / 8.0;
let height = if self.simple {
size.y / 10.0
} else {
size.y / 15.0
};
let size = vec2(width, height);
ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
ui.add_sized(size, Checkbox::new(&mut self.auto_update, "Auto-Update"))
.on_hover_text(GUPAX_AUTO_UPDATE);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.bundled, "Bundle"))
.on_hover_text(GUPAX_BUNDLED_UPDATE);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_p2pool, "Auto-P2Pool"))
.on_hover_text(GUPAX_AUTO_P2POOL);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_xmrig, "Auto-XMRig"))
.on_hover_text(GUPAX_AUTO_XMRIG);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_xp, "Auto-Proxy"))
.on_hover_text(GUPAX_AUTO_XMRIG_PROXY);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_xvb, "Auto-XvB"))
.on_hover_text(GUPAX_AUTO_XVB);
ui.separator();
ui.add_sized(
size,
Checkbox::new(&mut self.ask_before_quit, "Confirm quit"),
)
.on_hover_text(GUPAX_ASK_BEFORE_QUIT);
ui.separator();
ui.add_sized(
size,
Checkbox::new(&mut self.save_before_quit, "Save on quit"),
)
.on_hover_text(GUPAX_SAVE_BEFORE_QUIT);
egui::ScrollArea::horizontal().show(ui, |ui| {
let width = (size.x - SPACE * 17.0) / 8.0;
let height = if self.simple {
size.y / 10.0
} else {
size.y / 15.0
};
let size = vec2(width, height);
ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
ui.add_sized(size, Checkbox::new(&mut self.auto_update, "Auto-Update"))
.on_hover_text(GUPAX_AUTO_UPDATE);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.bundled, "Bundle"))
.on_hover_text(GUPAX_BUNDLED_UPDATE);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_node, "Auto-Node"))
.on_hover_text(GUPAX_AUTO_NODE);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_p2pool, "Auto-P2Pool"))
.on_hover_text(GUPAX_AUTO_P2POOL);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_xmrig, "Auto-XMRig"))
.on_hover_text(GUPAX_AUTO_XMRIG);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_xp, "Auto-Proxy"))
.on_hover_text(GUPAX_AUTO_XMRIG_PROXY);
ui.separator();
ui.add_sized(size, Checkbox::new(&mut self.auto_xvb, "Auto-XvB"))
.on_hover_text(GUPAX_AUTO_XVB);
ui.separator();
ui.add_sized(
size,
Checkbox::new(&mut self.ask_before_quit, "Confirm quit"),
)
.on_hover_text(GUPAX_ASK_BEFORE_QUIT);
ui.separator();
ui.add_sized(
size,
Checkbox::new(&mut self.save_before_quit, "Save on quit"),
)
.on_hover_text(GUPAX_SAVE_BEFORE_QUIT);
});
});
});
@ -140,13 +145,51 @@ impl Gupax {
ui.add_sized(
[ui.available_width(), height / 2.0],
Label::new(
RichText::new("P2Pool/XMRig/XMRig-Proxy PATHs")
RichText::new("Node/P2Pool/XMRig/XMRig-Proxy PATHs")
.underline()
.color(LIGHT_GRAY),
),
)
.on_hover_text("Gupaxx is online");
ui.separator();
ui.horizontal(|ui| {
if self.node_path.is_empty() {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new("Node Binary Path ").color(LIGHT_GRAY)),
)
.on_hover_text(NODE_PATH_EMPTY);
} else if !Self::path_is_file(&self.node_path) {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new("Node Binary Path ❌").color(RED)),
)
.on_hover_text(NODE_PATH_NOT_FILE);
} else if !crate::components::update::check_node_path(&self.node_path) {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new("Node Binary Path ❌").color(RED)),
)
.on_hover_text(NODE_PATH_NOT_VALID);
} else {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new("Node Binary Path ✔").color(GREEN)),
)
.on_hover_text(NODE_PATH_OK);
}
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
ui.add_enabled_ui(!lock!(file_window).thread, |ui| {
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
Self::spawn_file_window_thread(file_window, FileType::Node);
}
ui.add_sized(
[ui.available_width(), height],
TextEdit::singleline(&mut self.node_path),
)
.on_hover_text(GUPAX_PATH_NODE);
});
});
ui.horizontal(|ui| {
if self.p2pool_path.is_empty() {
ui.add_sized(
@ -189,25 +232,25 @@ impl Gupax {
if self.xmrig_path.is_empty() {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig Binary Path ").color(LIGHT_GRAY)),
Label::new(RichText::new("XMRig Binary Path ").color(LIGHT_GRAY)),
)
.on_hover_text(XMRIG_PATH_EMPTY);
} else if !Self::path_is_file(&self.xmrig_path) {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig Binary Path ❌").color(RED)),
Label::new(RichText::new("XMRig Binary Path ❌").color(RED)),
)
.on_hover_text(XMRIG_PATH_NOT_FILE);
} else if !crate::components::update::check_xmrig_path(&self.xmrig_path) {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig Binary Path ❌").color(RED)),
Label::new(RichText::new("XMRig Binary Path ❌").color(RED)),
)
.on_hover_text(XMRIG_PATH_NOT_VALID);
} else {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig Binary Path ✔").color(GREEN)),
Label::new(RichText::new("XMRig Binary Path ✔").color(GREEN)),
)
.on_hover_text(XMRIG_PATH_OK);
}
@ -228,26 +271,26 @@ impl Gupax {
ui.add_sized(
[text_edit, height],
Label::new(
RichText::new(" XMRig-Proxy Binary Path ").color(LIGHT_GRAY),
RichText::new("XMRig-Proxy Binary Path ").color(LIGHT_GRAY),
),
)
.on_hover_text(XMRIG_PROXY_PATH_EMPTY);
} else if !Self::path_is_file(&self.xmrig_proxy_path) {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig-Proxy Binary Path ❌").color(RED)),
Label::new(RichText::new("XMRig-Proxy Binary Path ❌").color(RED)),
)
.on_hover_text(XMRIG_PROXY_PATH_NOT_FILE);
} else if !crate::components::update::check_xp_path(&self.xmrig_proxy_path) {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig-Proxy Binary Path ❌").color(RED)),
Label::new(RichText::new("XMRig-Proxy Binary Path ❌").color(RED)),
)
.on_hover_text(XMRIG_PROXY_PATH_NOT_VALID);
} else {
ui.add_sized(
[text_edit, height],
Label::new(RichText::new(" XMRig-Proxy Binary Path ✔").color(GREEN)),
Label::new(RichText::new("XMRig-Proxy Binary Path ✔").color(GREEN)),
)
.on_hover_text(XMRIG_PROXY_PATH_OK);
}
@ -273,6 +316,14 @@ impl Gupax {
self.xmrig_path.clone_from(&guard.xmrig_path);
guard.picked_xmrig = false;
}
if guard.picked_xp {
self.xmrig_proxy_path.clone_from(&guard.xmrig_proxy_path);
guard.picked_xp = false;
}
if guard.picked_node {
self.node_path.clone_from(&guard.node_path);
guard.picked_node = false;
}
drop(guard);
let height = ui.available_height() / 6.0;
@ -280,7 +331,7 @@ impl Gupax {
// Saved [Tab]
debug!("Gupaxx Tab | Rendering [Tab] selector");
ui.group(|ui| {
let width = (size.x / 6.0) - (SPACE * 1.93);
let width = (size.x / 7.0) - (SPACE * 1.93);
let size = vec2(width, height);
ui.add_sized(
[ui.available_width(), height / 2.0],
@ -316,6 +367,14 @@ impl Gupax {
self.tab = Tab::Gupax;
}
ui.separator();
if ui
.add_sized(size, SelectableLabel::new(self.tab == Tab::Node, "Node"))
.on_hover_text(GUPAX_TAB_NODE)
.clicked()
{
self.tab = Tab::Node;
}
ui.separator();
if ui
.add_sized(
size,

View file

@ -8,6 +8,7 @@ use egui::*;
use log::debug;
mod gupax;
mod node;
mod p2pool;
mod status;
mod xmrig;
@ -20,6 +21,7 @@ impl crate::app::App {
ctx: &egui::Context,
frame: &mut eframe::Frame,
key: KeyPressed,
node_is_alive: bool,
p2pool_is_alive: bool,
xmrig_is_alive: bool,
xmrig_proxy_is_alive: bool,
@ -156,12 +158,16 @@ path_xmr: {:#?}\n
}
Tab::Status => {
debug!("App | Entering [Status] Tab");
crate::disk::state::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api,&self.xmrig_proxy_api, &self.xvb_api,&self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, xmrig_proxy_is_alive,xvb_is_alive, self.max_threads, &self.gupax_p2pool_api, &self.benchmarks, self.size, ctx, ui);
crate::disk::state::Status::show(&mut self.state.status, &self.pub_sys, &self.node_api, &self.p2pool_api, &self.xmrig_api,&self.xmrig_proxy_api, &self.xvb_api,&self.p2pool_img, &self.xmrig_img, node_is_alive, p2pool_is_alive, xmrig_is_alive, xmrig_proxy_is_alive,xvb_is_alive, self.max_threads, &self.gupax_p2pool_api, &self.benchmarks, self.size, ctx, ui);
}
Tab::Gupax => {
debug!("App | Entering [Gupax] Tab");
crate::disk::state::Gupax::show(&mut self.state.gupax, &self.og, &self.state_path, &self.update, &self.file_window, &mut self.error_state, &self.restart, self.size, frame, ctx, ui);
}
Tab::Node=> {
debug!("App | Entering [Node] Tab");
crate::disk::state::Node::show(&mut self.state.node, &self.node, &self.node_api, &mut self.node_stdin, self.size, &self.file_window, ui);
}
Tab::P2pool => {
debug!("App | Entering [P2Pool] Tab");
crate::disk::state::P2pool::show(&mut self.state.p2pool, &mut self.node_vec, &self.og, &self.ping, &self.p2pool, &self.p2pool_api, &mut self.p2pool_stdin, self.size, ctx, ui);

View file

@ -0,0 +1,407 @@
use crate::{
GUPAX_SELECT, NODE_API_BIND, NODE_API_PORT, NODE_ARGUMENTS, NODE_DB_DIR, NODE_DB_PATH_EMPTY,
NODE_DNS_BLOCKLIST, NODE_DNS_CHECKPOINT, NODE_INPUT, NODE_PATH_OK, NODE_PRUNNING, NODE_URL,
NODE_ZMQ_BIND, NODE_ZMQ_PORT,
};
use egui::{Color32, Label, RichText, Slider, TextEdit, Ui, Vec2};
use regex::Regex;
use std::sync::{Arc, Mutex};
use egui::TextStyle::{self, Name};
use log::debug;
use crate::components::gupax::{FileType, FileWindow};
use crate::disk::state::{Gupax, Node};
use crate::helper::node::PubNodeApi;
use crate::helper::Process;
use crate::regex::{num_lines, REGEXES};
use crate::utils::constants::DARK_GRAY;
use crate::utils::macros::lock;
use crate::{GREEN, LIGHT_GRAY, P2POOL_IN, P2POOL_LOG, P2POOL_OUT, RED, SPACE};
impl Node {
#[inline(always)] // called once
pub fn show(
&mut self,
process: &Arc<Mutex<Process>>,
api: &Arc<Mutex<PubNodeApi>>,
buffer: &mut String,
size: Vec2,
file_window: &Arc<Mutex<FileWindow>>,
ui: &mut egui::Ui,
) {
let width = size.x;
let height = size.y;
let space_h = height / 48.0;
let text_height = size.y / 25.0;
let txt_description_width = size.x * 0.1;
egui::ScrollArea::vertical().show(ui, |ui| {
ui.vertical_centered(|ui| {
ui.add_space(space_h);
ui.style_mut().override_text_style = Some(TextStyle::Heading);
ui.hyperlink_to("Monerod", NODE_URL);
ui.style_mut().override_text_style = Some(TextStyle::Body);
ui.add(Label::new("C++ Monero Node"));
ui.add_space(space_h);
});
// console output for log
debug!("Node Tab | Rendering [Console]");
ui.group(|ui| {
let text = &lock!(api).output;
let nb_lines = num_lines(text);
let height = size.y / 2.8;
let width = size.x - (space_h / 2.0);
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, _| {
.show_rows(
ui,
ui.text_style_height(&TextStyle::Name("MonospaceSmall".into())),
nb_lines,
|ui, row_range| {
for i in row_range {
if let Some(line) = text.lines().nth(i) {
ui.label(line);
}
}
},
);
});
});
//---------------------------------------------------------------------------------------------------- [Advanced] Console
if !self.simple {
ui.separator();
let response = ui
.add_sized(
[width, text_height],
TextEdit::hint_text(
TextEdit::singleline(buffer),
r#"Commands: help, status, set_log <level>, diff"#,
),
)
.on_hover_text(NODE_INPUT);
// If the user pressed enter, dump buffer contents into the process STDIN
if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
response.request_focus(); // Get focus back
let buffer = std::mem::take(buffer); // Take buffer
let mut process = lock!(process); // Lock
if process.is_alive() {
process.input.push(buffer);
} // Push only if alive
}
//---------------------------------------------------------------------------------------------------- Arguments
debug!("Node Tab | Rendering [Arguments]");
ui.group(|ui| {
ui.horizontal(|ui| {
ui.add_sized(
[txt_description_width, text_height],
Label::new("Command arguments:"),
);
ui.add_sized(
[ui.available_width(), text_height],
TextEdit::hint_text(
TextEdit::singleline(&mut self.arguments),
r#"--zmq-pub tcp://127.0.0.1:18081"#,
),
)
.on_hover_text(NODE_ARGUMENTS);
self.arguments.truncate(1024);
})
});
if !self.arguments.is_empty() {
ui.disable();
}
//---------------------------------------------------------------------------------------------------- Prunned checkbox
ui.add_space(space_h);
ui.style_mut().spacing.icon_width_inner = width / 45.0;
ui.style_mut().spacing.icon_width = width / 35.0;
ui.style_mut().spacing.icon_spacing = space_h;
ui.checkbox(&mut self.pruned, "Prunned")
.on_hover_text(NODE_PRUNNING);
ui.add_space(space_h);
// idea
// need to warn the user if local firewall is blocking port
// need to warn the user if NAT is blocking port
// need to show local ip address
// need to show public ip
// text edit width is 4x bigger than description. Which makes half of the total width on screen less a space.
// (width - (width - ui.available_width()) - (ui.spacing().item_spacing.x * 4.5))
// / 2.0;
ui.horizontal(|ui| {
ui.group(|ui| {
ui.vertical(|ui| {
rpc_bind_field(self, ui, txt_description_width, text_height, width);
rpc_port_field(self, ui, txt_description_width, text_height, width);
ui.add_space(space_h);
zmq_bind_field(self, ui, txt_description_width, text_height, width);
zmq_port_field(self, ui, txt_description_width, text_height, width);
});
});
//---------------------------------------------------------------------------------------------------- In/Out peers
debug!("Node Tab | Rendering sliders elements");
ui.vertical(|ui| {
ui.group(|ui| {
ui.style_mut().override_text_style =
Some(Name("MonospaceSmall".into()));
ui.horizontal(|ui| {
// ui.label("Out peers [10-450]:");
ui.add_sized(
[txt_description_width, text_height],
Label::new("Out peers [10-450]:"),
);
// not sure what's the right calculation to make
ui.style_mut().spacing.slider_width = ui.available_width()
- ui.spacing().item_spacing.x * 4.0
- ui.spacing().scroll.bar_width
- (SPACE * 2.0);
ui.add(Slider::new(&mut self.out_peers, 10..=450))
.on_hover_text(P2POOL_OUT);
// ui.add_space(ui.available_width() - 4.0);
});
ui.horizontal(|ui| {
// ui.label("In peers [10-450]:");
ui.add_sized(
[txt_description_width, text_height],
Label::new("In peers [10-450]:"),
);
ui.style_mut().spacing.slider_width = ui.available_width()
- ui.spacing().item_spacing.x * 4.0
- ui.spacing().scroll.bar_width
- (SPACE * 2.0);
ui.add(Slider::new(&mut self.in_peers, 10..=450))
.on_hover_text(P2POOL_IN);
});
ui.horizontal(|ui| {
// ui.label("Log level [ 0-4 ]:");
ui.add_sized(
[txt_description_width, text_height],
Label::new("Log level [ 0-4 ] :"),
);
ui.style_mut().spacing.slider_width = ui.available_width()
- ui.spacing().item_spacing.x * 4.0
- ui.spacing().scroll.bar_width
- (SPACE * 2.0);
ui.add(Slider::new(&mut self.log_level, 0..=4))
.on_hover_text(P2POOL_LOG);
});
});
});
});
//---------------------------------------------------------------------------------------------------- DB path
ui.add_space(space_h);
ui.group(|ui| {
path_db_field(self, ui, txt_description_width, text_height, file_window);
});
ui.add_space(space_h);
debug!("Node Tab | Rendering DNS buttons");
ui.horizontal(|ui| {
ui.group(|ui| {
ui.checkbox(&mut self.dns_blocklist, "DNS blocklist")
.on_hover_text(NODE_DNS_BLOCKLIST);
ui.separator();
ui.checkbox(&mut self.disable_dns_checkpoint, "DNS checkpoint")
.on_hover_text(NODE_DNS_CHECKPOINT);
});
});
}
});
}
}
fn rpc_bind_field(
state: &mut Node,
ui: &mut Ui,
txt_description_width: f32,
text_height: f32,
width: f32,
) {
state_edit_field(
&mut state.api_ip,
ui,
txt_description_width,
text_height,
width,
"RPC BIND IP ",
255,
NODE_API_BIND,
vec![&REGEXES.ipv4, &REGEXES.domain],
);
}
fn rpc_port_field(
state: &mut Node,
ui: &mut Ui,
txt_description_width: f32,
text_height: f32,
width: f32,
) {
state_edit_field(
&mut state.api_port,
ui,
txt_description_width,
text_height,
width,
" RPC PORT ",
5,
NODE_API_PORT,
vec![&REGEXES.port],
);
}
fn zmq_bind_field(
state: &mut Node,
ui: &mut Ui,
txt_description_width: f32,
text_height: f32,
width: f32,
) {
state_edit_field(
&mut state.zmq_ip,
ui,
txt_description_width,
text_height,
width,
"API BIND IP ",
255,
NODE_ZMQ_BIND,
vec![&REGEXES.ipv4, &REGEXES.domain],
);
}
fn zmq_port_field(
state: &mut Node,
ui: &mut Ui,
txt_description_width: f32,
text_height: f32,
width: f32,
) {
state_edit_field(
&mut state.zmq_port,
ui,
txt_description_width,
text_height,
width,
" ZMQ PORT ",
5,
NODE_ZMQ_PORT,
vec![&REGEXES.port],
);
}
fn path_db_field(
state: &mut Node,
ui: &mut Ui,
txt_description_width: f32,
text_height: f32,
file_window: &Arc<Mutex<FileWindow>>,
) {
ui.horizontal(|ui| {
let symbol;
let color;
let hover;
if state.path_db.is_empty() {
symbol = "";
color = LIGHT_GRAY;
hover = NODE_DB_PATH_EMPTY;
} else if !Gupax::path_is_dir(&state.path_db) {
symbol = "";
color = RED;
hover = NODE_DB_DIR;
} else {
symbol = "";
color = GREEN;
hover = NODE_PATH_OK;
}
let text = ["Node Database Directory ", symbol].concat();
ui.add_sized(
[txt_description_width, text_height],
Label::new(RichText::new(text).color(color)),
);
ui.spacing_mut().text_edit_width =
ui.available_width() - (ui.spacing().item_spacing.x * 8.0) - SPACE * 2.0;
let window_busy = lock!(file_window).thread;
ui.add_enabled_ui(!window_busy, |ui| {
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
Gupax::spawn_file_window_thread(file_window, FileType::NodeDB);
}
ui.text_edit_singleline(&mut state.path_db)
.on_hover_text(hover);
});
});
let mut guard = lock!(file_window);
if guard.picked_nodedb {
state.path_db.clone_from(&guard.nodedb_path);
guard.picked_nodedb = false;
}
}
#[allow(clippy::too_many_arguments)]
fn state_edit_field(
state_field: &mut String,
ui: &mut Ui,
txt_description_width: f32,
text_height: f32,
width: f32,
description: &str,
max_ch: u8,
help_msg: &str,
validations: Vec<&Regex>,
) {
ui.horizontal(|ui| {
let color;
let symbol;
let mut input_validated = true;
let len;
let inside_space;
for v in validations {
if !v.is_match(state_field) {
input_validated = false;
}
}
if state_field.is_empty() {
symbol = "";
color = Color32::LIGHT_GRAY;
} else if input_validated {
symbol = "";
color = Color32::from_rgb(100, 230, 100);
} else {
symbol = "";
color = Color32::from_rgb(230, 50, 50);
}
match max_ch {
x if x >= 100 => {
len = format!("{:03}", state_field.len());
inside_space = "";
}
10..99 => {
len = format!("{:02}", state_field.len());
inside_space = " ";
}
_ => {
len = format!("{}", state_field.len());
inside_space = " ";
}
}
let text = format!(
"{}[{}{}/{}{}]{}",
description, inside_space, len, max_ch, inside_space, symbol
);
ui.add_sized(
[txt_description_width, text_height],
Label::new(RichText::new(text).color(color)),
);
// allocate the size to leave half of the total width free.
ui.spacing_mut().text_edit_width = (width / 2.0)
- (width - ui.available_width() - ui.spacing().scroll.bar_width)
- ui.spacing().item_spacing.x * 2.5;
ui.text_edit_singleline(state_field).on_hover_text(help_msg);
state_field.truncate(max_ch.into());
});
}

View file

@ -21,6 +21,7 @@ use crate::{
app::Benchmark,
disk::{gupax_p2pool_api::GupaxP2poolApi, state::Status, status::*},
helper::{
node::PubNodeApi,
p2pool::{ImgP2pool, PubP2poolApi},
xrig::{
xmrig::{ImgXmrig, PubXmrigApi},
@ -42,12 +43,14 @@ impl Status {
pub fn show(
&mut self,
sys: &Arc<Mutex<Sys>>,
node_api: &Arc<Mutex<PubNodeApi>>,
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
xmrig_api: &Arc<Mutex<PubXmrigApi>>,
xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
xvb_api: &Arc<Mutex<PubXvbApi>>,
p2pool_img: &Arc<Mutex<ImgP2pool>>,
xmrig_img: &Arc<Mutex<ImgXmrig>>,
node_alive: bool,
p2pool_alive: bool,
xmrig_alive: bool,
xmrig_proxy_alive: bool,
@ -65,6 +68,8 @@ impl Status {
sys,
size,
ui,
node_alive,
node_api,
p2pool_alive,
p2pool_api,
p2pool_img,

View file

@ -3,6 +3,7 @@ use readable::up::UptimeFull;
use std::sync::{Arc, Mutex};
use crate::disk::state::Status;
use crate::helper::node::PubNodeApi;
use crate::helper::p2pool::{ImgP2pool, PubP2poolApi};
use crate::helper::xrig::xmrig::{ImgXmrig, PubXmrigApi};
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
@ -21,6 +22,8 @@ impl Status {
sys: &Arc<Mutex<Sys>>,
size: Vec2,
ui: &mut egui::Ui,
node_alive: bool,
node_api: &Arc<Mutex<PubNodeApi>>,
p2pool_alive: bool,
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
p2pool_img: &Arc<Mutex<ImgP2pool>>,
@ -50,6 +53,8 @@ impl Status {
// [Gupax]
gupax(ui, min_size, size, sys);
// [Node]
node(ui, min_size, size, node_alive, node_api);
// [P2Pool]
p2pool(ui, min_size, size, p2pool_alive, p2pool_api, p2pool_img);
// [XMRig]
@ -554,3 +559,94 @@ fn xvb(ui: &mut Ui, min_size: Vec2, size: Vec2, xvb_alive: bool, xvb_api: &Arc<M
});
});
}
#[allow(clippy::too_many_arguments)]
fn node(
ui: &mut Ui,
min_size: Vec2,
size: Vec2,
node_alive: bool,
node_api: &Arc<Mutex<PubNodeApi>>,
) {
ui.group(|ui| {
ui.vertical(|ui| {
ui.set_min_height(min_size.y * 34.0);
debug!("Status Tab | Rendering [Node]");
ui.add_enabled_ui(node_alive, |ui| {
ui.set_min_size(min_size);
ui.add_sized(
size,
Label::new(
RichText::new("[Node]")
.color(LIGHT_GRAY)
.text_style(TextStyle::Name("MonospaceLarge".into())),
),
)
.on_hover_text("Node is online")
.on_disabled_hover_text("Node is offline");
let api = lock!(node_api);
ui.add_sized(
size,
Label::new(RichText::new("Uptime").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_UPTIME);
ui.add_sized(size, Label::new(api.uptime.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Block Height").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_BLOCK_HEIGHT);
ui.add_sized(size, Label::new(api.blockheight.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Network Difficulty").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_DIFFICULTY);
ui.add_sized(size, Label::new(api.difficulty.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Database size").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_DB_SIZE);
ui.add_sized(size, Label::new(api.database_size.to_owned()));
ui.add_sized(
size,
Label::new(RichText::new("Free space").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_FREESPACE);
ui.add_sized(size, Label::new(api.free_space.to_owned()));
ui.add_sized(
size,
Label::new(RichText::new("Network Type").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_NETTYPE);
ui.add_sized(size, Label::new(api.nettype.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Outgoing peers").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_OUT);
ui.add_sized(size, Label::new(api.outgoing_connections.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Incoming peers").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_IN);
ui.add_sized(size, Label::new(api.incoming_connections.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Synchronized").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_SYNC);
ui.add_sized(size, Label::new(api.synchronized.to_string()));
ui.add_sized(
size,
Label::new(RichText::new("Status").underline().color(BONE)),
)
.on_hover_text(STATUS_NODE_STATUS);
ui.add_sized(size, Label::new(api.status.to_string()));
drop(api);
});
})
});
}

View file

@ -1,5 +1,5 @@
use egui::TextStyle::Name;
use egui::{SelectableLabel, TopBottomPanel};
use egui::{ScrollArea, SelectableLabel, TopBottomPanel};
use log::debug;
use crate::{app::Tab, utils::constants::SPACE};
@ -8,82 +8,94 @@ impl crate::app::App {
pub fn top_panel(&mut self, ctx: &egui::Context) {
debug!("App | Rendering TOP tabs");
TopBottomPanel::top("top").show(ctx, |ui| {
let width = (self.size.x - (SPACE * 16.0)) / 7.0;
let width = (self.size.x - (SPACE * 18.0)) / 8.0;
let height = self.size.y / 15.0;
ui.add_space(4.0);
ui.horizontal(|ui| {
ui.style_mut().override_text_style = Some(Name("Tab".into()));
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::About, "About"),
)
.clicked()
{
self.tab = Tab::About;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Status, "Status"),
)
.clicked()
{
self.tab = Tab::Status;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Gupax, "Gupaxx"),
)
.clicked()
{
self.tab = Tab::Gupax;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::P2pool, "P2Pool"),
)
.clicked()
{
self.tab = Tab::P2pool;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Xmrig, "XMRig"),
)
.clicked()
{
self.tab = Tab::Xmrig;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::XmrigProxy, "Proxy"),
)
.clicked()
{
self.tab = Tab::XmrigProxy;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Xvb, "XvB"),
)
.clicked()
{
self.tab = Tab::Xvb;
}
ScrollArea::horizontal().show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("Tab".into()));
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::About, "About"),
)
.clicked()
{
self.tab = Tab::About;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Status, "Status"),
)
.clicked()
{
self.tab = Tab::Status;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Gupax, "Gupaxx"),
)
.clicked()
{
self.tab = Tab::Gupax;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Node, "Node"),
)
.clicked()
{
self.tab = Tab::Node;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::P2pool, "P2Pool"),
)
.clicked()
{
self.tab = Tab::P2pool;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Xmrig, "XMRig"),
)
.clicked()
{
self.tab = Tab::Xmrig;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::XmrigProxy, "Proxy"),
)
.clicked()
{
self.tab = Tab::XmrigProxy;
}
ui.separator();
if ui
.add_sized(
[width, height],
SelectableLabel::new(self.tab == Tab::Xvb, "XvB"),
)
.clicked()
{
self.tab = Tab::Xvb;
}
});
ui.add_space(4.0);
});
ui.add_space(4.0);
});
}
}

View file

@ -35,7 +35,11 @@ pub struct FileWindow {
pub picked_p2pool: bool, // Did the user pick a path for p2pool?
pub picked_xmrig: bool, // Did the user pick a path for xmrig?
pub picked_xp: bool, // Did the user pick a path for xmrig-proxy?
pub picked_node: bool, // Did the user pick a path for node?
pub picked_nodedb: bool, // Did the user pick a path for node?
pub p2pool_path: String, // The picked p2pool path
pub node_path: String, // The picked node path
pub nodedb_path: String, // The picked node path
pub xmrig_path: String, // The picked xmrig path
pub xmrig_proxy_path: String, // The picked xmrig-proxy path
}
@ -47,7 +51,11 @@ impl FileWindow {
picked_p2pool: false,
picked_xmrig: false,
picked_xp: false,
picked_node: false,
picked_nodedb: false,
p2pool_path: String::new(),
node_path: String::new(),
nodedb_path: String::new(),
xmrig_path: String::new(),
xmrig_proxy_path: String::new(),
})
@ -59,6 +67,8 @@ pub enum FileType {
P2pool,
Xmrig,
XmrigProxy,
Node,
NodeDB,
}
//---------------------------------------------------------------------------------------------------- Ratio Lock
@ -80,6 +90,14 @@ impl Gupax {
_ => false,
}
}
// Checks if a path is a valid path to a directory.
pub fn path_is_dir(path: &str) -> bool {
let path = path.to_string();
match crate::disk::into_absolute_path(path) {
Ok(path) => path.is_dir(),
_ => false,
}
}
#[cold]
#[inline(never)]
@ -89,33 +107,48 @@ impl Gupax {
P2pool => "P2Pool",
Xmrig => "XMRig",
XmrigProxy => "XMRigProxy",
Node => "Node",
NodeDB => "Node DB",
};
let file_window = file_window.clone();
lock!(file_window).thread = true;
thread::spawn(move || {
match rfd::FileDialog::new()
.set_title(format!("Select {} Binary for Gupaxx", name))
.pick_file()
{
Some(path) => {
info!("Gupaxx | Path selected for {} ... {}", name, path.display());
match file_type {
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;
}
XmrigProxy => {
lock!(file_window).xmrig_proxy_path = path.display().to_string();
lock!(file_window).picked_xp = true;
}
};
}
None => info!("Gupaxx | No path selected for {}", name),
let path = match file_type {
NodeDB => rfd::FileDialog::new()
.set_title("Select a directory for the DB of your Node")
.pick_folder(),
_ => rfd::FileDialog::new()
.set_title(format!("Select {} Binary for Gupaxx", name))
.pick_file(),
};
if let Some(path) = path {
info!("Gupaxx | Path selected for {} ... {}", name, path.display());
match file_type {
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;
}
XmrigProxy => {
lock!(file_window).xmrig_proxy_path = path.display().to_string();
lock!(file_window).picked_xp = true;
}
Node => {
lock!(file_window).node_path = path.display().to_string();
lock!(file_window).picked_node = true;
}
NodeDB => {
lock!(file_window).nodedb_path = path.display().to_string();
lock!(file_window).picked_nodedb = true;
}
};
} else {
info!("Gupaxx | No path selected for {}", name);
}
lock!(file_window).thread = false;
});
}

View file

@ -61,6 +61,7 @@ cfg_if::cfg_if! {
if #[cfg(target_family = "unix")] {
pub(super) const GUPAX_BINARY: &str = "gupaxx";
pub(super) const P2POOL_BINARY: &str = "p2pool";
pub(super) const NODE_BINARY: &str = "monerod";
pub(super) const XMRIG_BINARY: &str = "xmrig";
pub(super) const XMRIG_PROXY_BINARY: &str = "xmrig-proxy";
}
@ -71,6 +72,7 @@ cfg_if::cfg_if! {
pub(super) const ARCHIVE_EXT: &str = "zip";
pub(super) const GUPAX_BINARY: &str = "Gupaxx.exe";
pub(super) const P2POOL_BINARY: &str = "p2pool.exe";
pub(super) const NODE_BINARY: &str = "monerod.exe";
pub(super) const XMRIG_BINARY: &str = "xmrig.exe";
pub(super) const XMRIG_PROXY_BINARY: &str = "xmrig-proxy.exe";
} else if #[cfg(target_os = "linux")] {
@ -153,6 +155,22 @@ pub fn check_p2pool_path(path: &str) -> bool {
path == P2POOL_BINARY
}
pub fn check_node_path(path: &str) -> bool {
let path = match crate::disk::into_absolute_path(path.to_string()) {
Ok(p) => p,
Err(_) => return false,
};
let path = match path.file_name() {
Some(p) => p,
None => {
error!("Couldn't get Node file name");
return false;
}
};
path == NODE_BINARY
}
pub fn check_xmrig_path(path: &str) -> bool {
let path = match crate::disk::into_absolute_path(path.to_string()) {
Ok(p) => p,
@ -199,7 +217,8 @@ pub struct Update {
pub path_gupax: String, // Full path to current gupax
pub path_p2pool: String, // Full path to current p2pool
pub path_xmrig: String, // Full path to current xmrig
pub path_xp: String, // Full path to current xmrig
pub path_xp: String, // Full path to current xmrig-proxy
pub path_node: String, // Full path to current node
pub updating: Arc<Mutex<bool>>, // Is an update in progress?
pub prog: Arc<Mutex<f32>>, // Holds the 0-100% progress bar number
pub msg: Arc<Mutex<String>>, // Message to display on [Gupax] tab while updating
@ -212,12 +231,14 @@ impl Update {
path_p2pool: PathBuf,
path_xmrig: PathBuf,
path_xp: PathBuf,
path_node: PathBuf,
) -> Self {
Self {
path_gupax,
path_p2pool: path_p2pool.display().to_string(),
path_xmrig: path_xmrig.display().to_string(),
path_xp: path_xp.display().to_string(),
path_node: path_node.display().to_string(),
updating: arc_mut!(false),
prog: arc_mut!(0.0),
msg: arc_mut!(MSG_NONE.to_string()),
@ -299,6 +320,21 @@ impl Update {
return;
}
};
// Check node path for safety
let node_path = match into_absolute_path(gupax.node_path.clone()) {
Ok(p) => p,
Err(e) => {
error_state.set(
format!(
"Provided Node path could not be turned into an absolute path: {}",
e
),
ErrorFerris::Error,
ErrorButtons::Okay,
);
return;
}
};
// Check XMRig-Proxy path for safety
let xmrig_proxy_path = match into_absolute_path(gupax.xmrig_proxy_path.clone()) {
Ok(p) => p,
@ -317,6 +353,7 @@ impl Update {
lock!(update).path_p2pool = p2pool_path.display().to_string();
lock!(update).path_xmrig = xmrig_path.display().to_string();
lock!(update).path_xp = xmrig_proxy_path.display().to_string();
lock!(update).path_node = node_path.display().to_string();
}
// Clone before thread spawn
@ -536,6 +573,7 @@ impl Update {
P2POOL_BINARY => lock!(update).path_p2pool.clone(),
XMRIG_BINARY => lock!(update).path_xmrig.clone(),
XMRIG_PROXY_BINARY => lock!(update).path_xp.clone(),
NODE_BINARY => lock!(update).path_node.clone(),
_ => continue,
};
found = true;
@ -552,6 +590,7 @@ impl Update {
P2POOL_BINARY => tmp_dir.clone() + "p2pool_old.exe",
XMRIG_BINARY => tmp_dir.clone() + "xmrig_old.exe",
XMRIG_PROXY_BINARY => tmp_dir.clone() + "xmrig-proxy_old.exe",
NODE_BINARY => tmp_dir.clone() + "monerod_old.exe",
_ => continue,
};
info!(
@ -568,7 +607,10 @@ impl Update {
);
// if bundled, create directory for p2pool, xmrig and xmrig-proxy if not present
if lock!(og).gupax.bundled
&& (name == P2POOL_BINARY || name == XMRIG_BINARY || name == XMRIG_PROXY_BINARY)
&& (name == P2POOL_BINARY
|| name == XMRIG_BINARY
|| name == XMRIG_PROXY_BINARY
|| name == NODE_BINARY)
{
std::fs::create_dir_all(
path.parent()

View file

@ -41,11 +41,15 @@ pub const DEFAULT_P2POOL_PATH: &str = "p2pool/p2pool";
#[cfg(target_os = "windows")]
pub const DEFAULT_XMRIG_PATH: &str = r"XMRig\xmrig.exe";
#[cfg(target_os = "windows")]
pub const DEFAULT_NODE_PATH: &str = r"node\monerod.exe";
#[cfg(target_os = "windows")]
pub const DEFAULT_XMRIG_PROXY_PATH: &str = r"XMRig-Proxy\xmrig-proxy.exe";
#[cfg(target_os = "macos")]
pub const DEFAULT_XMRIG_PATH: &str = "xmrig/xmrig";
#[cfg(target_os = "macos")]
pub const DEFAULT_XMRIG_PROXY_PATH: &str = "xmrig-proxy/xmrig-proxy";
#[cfg(target_os = "macos")]
pub const DEFAULT_XMRIG_NODE_PATH: &str = "node/monerod";
// Default to [/usr/bin/] for Linux distro builds.
#[cfg(target_os = "linux")]
@ -58,6 +62,9 @@ pub const DEFAULT_XMRIG_PATH: &str = "xmrig/xmrig";
#[cfg(not(feature = "distro"))]
pub const DEFAULT_XMRIG_PROXY_PATH: &str = "xmrig-proxy/xmrig-proxy";
#[cfg(target_os = "linux")]
#[cfg(not(feature = "distro"))]
pub const DEFAULT_NODE_PATH: &str = "node/monerod";
#[cfg(target_os = "linux")]
#[cfg(feature = "distro")]
pub const DEFAULT_P2POOL_PATH: &str = "/usr/bin/p2pool";
#[cfg(target_os = "linux")]
@ -66,3 +73,6 @@ pub const DEFAULT_XMRIG_PATH: &str = "/usr/bin/xmrig";
#[cfg(target_os = "linux")]
#[cfg(feature = "distro")]
pub const DEFAULT_XMRIG_PROXY_PATH: &str = "/usr/bin/xmrig-proxy";
#[cfg(target_os = "linux")]
#[cfg(feature = "distro")]
pub const DEFAULT_NODE_PATH: &str = "/usr/bin/monerod";

View file

@ -21,6 +21,7 @@ impl State {
xmrig: Xmrig::with_threads(max_threads, current_threads),
xvb: Xvb::default(),
xmrig_proxy: XmrigProxy::default(),
node: Node::default(),
version: arc_mut!(Version::default()),
}
}
@ -29,6 +30,7 @@ impl State {
self.gupax.absolute_p2pool_path = into_absolute_path(self.gupax.p2pool_path.clone())?;
self.gupax.absolute_xmrig_path = into_absolute_path(self.gupax.xmrig_path.clone())?;
self.gupax.absolute_xp_path = into_absolute_path(self.gupax.xmrig_proxy_path.clone())?;
self.gupax.absolute_node_path = into_absolute_path(self.gupax.node_path.clone())?;
Ok(())
}
@ -163,6 +165,7 @@ pub struct State {
pub xmrig: Xmrig,
pub xmrig_proxy: XmrigProxy,
pub xvb: Xvb,
pub node: Node,
pub version: Arc<Mutex<Version>>,
}
@ -181,16 +184,18 @@ pub struct Gupax {
pub simple: bool,
pub auto_update: bool,
pub auto_p2pool: bool,
pub auto_node: bool,
pub auto_xmrig: bool,
pub auto_xp: bool,
pub auto_xvb: bool,
// pub auto_monero: bool,
pub ask_before_quit: bool,
pub save_before_quit: bool,
pub p2pool_path: String,
pub node_path: String,
pub xmrig_path: String,
pub xmrig_proxy_path: String,
pub absolute_p2pool_path: PathBuf,
pub absolute_node_path: PathBuf,
pub absolute_xmrig_path: PathBuf,
pub absolute_xp_path: PathBuf,
pub selected_width: u16,
@ -225,6 +230,43 @@ pub struct P2pool {
pub selected_zmq: String,
}
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
pub struct Node {
pub simple: bool,
pub api_ip: String,
pub api_port: String,
pub out_peers: u16,
pub in_peers: u16,
pub log_level: u8,
pub arguments: String,
pub zmq_ip: String,
pub zmq_port: String,
pub pruned: bool,
pub dns_blocklist: bool,
pub disable_dns_checkpoint: bool,
pub path_db: String,
}
impl Default for Node {
fn default() -> Self {
Self {
simple: true,
api_ip: String::from("127.0.0.1"),
api_port: 18081.to_string(),
out_peers: 32,
in_peers: 64,
log_level: 0,
arguments: String::new(),
zmq_ip: String::from("127.0.0.1"),
zmq_port: 18083.to_string(),
pruned: true,
dns_blocklist: true,
disable_dns_checkpoint: true,
path_db: String::new(),
}
}
}
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
pub struct Xmrig {
pub simple: bool,
@ -414,6 +456,7 @@ impl Default for Gupax {
simple: true,
auto_update: false,
auto_p2pool: false,
auto_node: false,
auto_xmrig: false,
auto_xp: false,
auto_xvb: false,
@ -421,10 +464,12 @@ impl Default for Gupax {
save_before_quit: true,
p2pool_path: DEFAULT_P2POOL_PATH.to_string(),
xmrig_path: DEFAULT_XMRIG_PATH.to_string(),
node_path: DEFAULT_NODE_PATH.to_string(),
xmrig_proxy_path: DEFAULT_XMRIG_PROXY_PATH.to_string(),
absolute_p2pool_path: into_absolute_path(DEFAULT_P2POOL_PATH.to_string()).unwrap(),
absolute_xmrig_path: into_absolute_path(DEFAULT_XMRIG_PATH.to_string()).unwrap(),
absolute_xp_path: into_absolute_path(DEFAULT_XMRIG_PROXY_PATH.to_string()).unwrap(),
absolute_node_path: into_absolute_path(DEFAULT_NODE_PATH.to_string()).unwrap(),
selected_width: APP_DEFAULT_WIDTH as u16,
selected_height: APP_DEFAULT_HEIGHT as u16,
selected_scale: APP_DEFAULT_SCALE,

View file

@ -30,6 +30,7 @@ mod test {
simple = true
auto_update = true
auto_p2pool = false
auto_node = false
auto_xmrig = false
auto_xvb = false
auto_xp = false
@ -37,8 +38,10 @@ mod test {
save_before_quit = true
p2pool_path = "p2pool/p2pool"
xmrig_path = "xmrig/xmrig"
node_path = "node/monerod"
xmrig_proxy_path = "xmrig-proxy/xmrig-proxy"
absolute_p2pool_path = "/home/hinto/p2pool/p2pool"
absolute_node_path = "/home/hinto/node/monerod"
absolute_xmrig_path = "/home/hinto/xmrig/xmrig"
absolute_xp_path = "/home/hinto/xmrig/xmrig-proxy/xmrig-proxy"
selected_width = 1280
@ -137,10 +140,26 @@ mod test {
node = "Europe"
p2pool_buffer = 5
[node]
simple = false
api_ip = "127.0.0.1"
api_port = "18081"
out_peers = 32
in_peers = 64
log_level = 0
arguments = ""
zmq_ip = "127.0.0.1"
zmq_port = "18083"
pruned = true
dns_blocklist = true
disable_dns_checkpoint = true
path_db = ""
[version]
gupax = "v1.3.0"
p2pool = "v2.5"
xmrig = "v6.18.0"
node = "v18.3.4"
"#;
let state = State::from_str(state).unwrap();
State::to_string(&state).unwrap();

View file

@ -41,6 +41,7 @@ use crate::helper::{
};
use crate::{constants::*, disk::gupax_p2pool_api::GupaxP2poolApi, human::*, macros::*};
use log::*;
use node::PubNodeApi;
use portable_pty::Child;
use readable::up::Uptime;
use std::fmt::Write;
@ -53,6 +54,7 @@ use std::{
};
use self::xvb::{nodes::XvbNode, PubXvbApi};
pub mod node;
pub mod p2pool;
pub mod tests;
pub mod xrig;
@ -76,6 +78,7 @@ pub struct Helper {
pub uptime: HumanTime, // Gupax uptime formatting for humans
pub pub_sys: Arc<Mutex<Sys>>, // The public API for [sysinfo] that the [Status] tab reads from
pub p2pool: Arc<Mutex<Process>>, // P2Pool process state
pub node: Arc<Mutex<Process>>, // P2Pool process state
pub xmrig: Arc<Mutex<Process>>, // XMRig process state
pub xmrig_proxy: Arc<Mutex<Process>>, // XMRig process state
pub xvb: Arc<Mutex<Process>>, // XvB process state
@ -83,11 +86,13 @@ pub struct Helper {
pub gui_api_xmrig: Arc<Mutex<PubXmrigApi>>, // XMRig API state (for GUI thread)
pub gui_api_xp: Arc<Mutex<PubXmrigProxyApi>>, // XMRig-Proxy API state (for GUI thread)
pub gui_api_xvb: Arc<Mutex<PubXvbApi>>, // XMRig API state (for GUI thread)
pub gui_api_node: Arc<Mutex<PubNodeApi>>, // Node API state (for GUI thread)
pub img_p2pool: Arc<Mutex<ImgP2pool>>, // A static "image" of the data P2Pool started with
pub img_xmrig: Arc<Mutex<ImgXmrig>>, // A static "image" of the data XMRig started with
pub_api_p2pool: Arc<Mutex<PubP2poolApi>>, // P2Pool API state (for Helper/P2Pool thread)
pub_api_xmrig: Arc<Mutex<PubXmrigApi>>, // XMRig API state (for Helper/XMRig thread)
pub_api_xp: Arc<Mutex<PubXmrigProxyApi>>, // XMRig-Proxy API state (for Helper/XMRig-Proxy thread)
pub_api_node: Arc<Mutex<PubNodeApi>>, // Node API state (for Helper/Node thread)
pub_api_xvb: Arc<Mutex<PubXvbApi>>, // XvB API state (for Helper/XvB thread)
pub gupax_p2pool_api: Arc<Mutex<GupaxP2poolApi>>, //
}
@ -251,6 +256,7 @@ pub enum ProcessName {
Xmrig,
XmrigProxy,
Xvb,
Node,
}
impl std::fmt::Display for ProcessState {
@ -270,6 +276,7 @@ impl std::fmt::Display for ProcessName {
ProcessName::Xmrig => write!(f, "XMRig"),
ProcessName::XmrigProxy => write!(f, "XMRig-Proxy"),
ProcessName::Xvb => write!(f, "XvB"),
ProcessName::Node => write!(f, "Node"),
}
}
}
@ -285,10 +292,12 @@ impl Helper {
xmrig: Arc<Mutex<Process>>,
xmrig_proxy: Arc<Mutex<Process>>,
xvb: Arc<Mutex<Process>>,
node: Arc<Mutex<Process>>,
gui_api_p2pool: Arc<Mutex<PubP2poolApi>>,
gui_api_xmrig: Arc<Mutex<PubXmrigApi>>,
gui_api_xvb: Arc<Mutex<PubXvbApi>>,
gui_api_xp: Arc<Mutex<PubXmrigProxyApi>>,
gui_api_node: Arc<Mutex<PubNodeApi>>,
img_p2pool: Arc<Mutex<ImgP2pool>>,
img_xmrig: Arc<Mutex<ImgXmrig>>,
gupax_p2pool_api: Arc<Mutex<GupaxP2poolApi>>,
@ -301,15 +310,18 @@ impl Helper {
pub_api_xmrig: arc_mut!(PubXmrigApi::new()),
pub_api_xp: arc_mut!(PubXmrigProxyApi::new()),
pub_api_xvb: arc_mut!(PubXvbApi::new()),
pub_api_node: arc_mut!(PubNodeApi::new()),
// These are created when initializing [App], since it needs a handle to it as well
p2pool,
xmrig,
xmrig_proxy,
xvb,
node,
gui_api_p2pool,
gui_api_xmrig,
gui_api_xvb,
gui_api_xp,
gui_api_node,
img_p2pool,
img_xmrig,
gupax_p2pool_api,
@ -419,15 +431,18 @@ impl Helper {
let helper = Arc::clone(helper);
let lock = lock!(helper);
let node = Arc::clone(&lock.node);
let p2pool = Arc::clone(&lock.p2pool);
let xmrig = Arc::clone(&lock.xmrig);
let xmrig_proxy = Arc::clone(&lock.xmrig_proxy);
let xvb = Arc::clone(&lock.xvb);
let pub_sys = Arc::clone(&lock.pub_sys);
let gui_api_node = Arc::clone(&lock.gui_api_node);
let gui_api_p2pool = Arc::clone(&lock.gui_api_p2pool);
let gui_api_xmrig = Arc::clone(&lock.gui_api_xmrig);
let gui_api_xp = Arc::clone(&lock.gui_api_xp);
let gui_api_xvb = Arc::clone(&lock.gui_api_xvb);
let pub_api_node = Arc::clone(&lock.pub_api_node);
let pub_api_p2pool = Arc::clone(&lock.pub_api_p2pool);
let pub_api_xmrig = Arc::clone(&lock.pub_api_xmrig);
let pub_api_xp = Arc::clone(&lock.pub_api_xp);
@ -451,35 +466,48 @@ impl Helper {
// 2. Lock... EVERYTHING!
let mut lock = lock!(helper);
debug!("Helper | Locking (1/12) ... [helper]");
debug!("Helper | Locking (1/15) ... [helper]");
let node = lock!(node);
debug!("Helper | Locking (2/15) ... [helper]");
let p2pool = lock!(p2pool);
debug!("Helper | Locking (2/12) ... [p2pool]");
debug!("Helper | Locking (3/15) ... [p2pool]");
let xmrig = lock!(xmrig);
debug!("Helper | Locking (3/12) ... [xmrig]");
debug!("Helper | Locking (4/15) ... [xmrig]");
let xmrig_proxy = lock!(xmrig_proxy);
debug!("Helper | Locking (3/12) ... [xmrig_proxy]");
debug!("Helper | Locking (5/15) ... [xmrig_proxy]");
let xvb = lock!(xvb);
debug!("Helper | Locking (4/12) ... [xvb]");
debug!("Helper | Locking (6/15) ... [xvb]");
let mut lock_pub_sys = lock!(pub_sys);
debug!("Helper | Locking (5/12) ... [pub_sys]");
debug!("Helper | Locking (8/15) ... [gui_api_node]");
let mut gui_api_node = lock!(gui_api_node);
debug!("Helper | Locking (7/15) ... [pub_sys]");
let mut gui_api_p2pool = lock!(gui_api_p2pool);
debug!("Helper | Locking (6/12) ... [gui_api_p2pool]");
debug!("Helper | Locking (8/15) ... [gui_api_p2pool]");
let mut gui_api_xmrig = lock!(gui_api_xmrig);
debug!("Helper | Locking (7/12) ... [gui_api_xmrig]");
debug!("Helper | Locking (9/15) ... [gui_api_xmrig]");
let mut gui_api_xp = lock!(gui_api_xp);
debug!("Helper | Locking (7/12) ... [gui_api_xp]");
debug!("Helper | Locking (10/15) ... [gui_api_xp]");
let mut gui_api_xvb = lock!(gui_api_xvb);
debug!("Helper | Locking (8/12) ... [gui_api_xvb]");
debug!("Helper | Locking (11/15) ... [gui_api_xvb]");
let mut pub_api_node = lock!(pub_api_node);
debug!("Helper | Locking (14/15) ... [pub_api_node]");
let mut pub_api_p2pool = lock!(pub_api_p2pool);
debug!("Helper | Locking (9/12) ... [pub_api_p2pool]");
debug!("Helper | Locking (14/15) ... [pub_api_p2pool]");
let mut pub_api_xmrig = lock!(pub_api_xmrig);
debug!("Helper | Locking (10/12) ... [pub_api_xmrig]");
debug!("Helper | Locking (13/15) ... [pub_api_xmrig]");
let mut pub_api_xp = lock!(pub_api_xp);
debug!("Helper | Locking (11/12) ... [pub_api_xp]");
debug!("Helper | Locking (14/15) ... [pub_api_xp]");
let mut pub_api_xvb = lock!(pub_api_xvb);
debug!("Helper | Locking (12/12) ... [pub_api_xvb]");
debug!("Helper | Locking (15/15) ... [pub_api_xvb]");
// Calculate Gupax's uptime always.
lock.uptime = HumanTime::into_human(lock.instant.elapsed());
// If [Node] is alive...
if node.is_alive() {
debug!("Helper | Node is alive! Running [combine_gui_pub_api()]");
PubNodeApi::combine_gui_pub_api(&mut gui_api_node, &mut pub_api_node);
} else {
debug!("Helper | Node is dead! Skipping...");
}
// If [P2Pool] is alive...
if p2pool.is_alive() {
debug!("Helper | P2Pool is alive! Running [combine_gui_pub_api()]");
@ -539,6 +567,8 @@ impl Helper {
debug!("Helper | Unlocking (3/12) ... [xmrig]");
drop(p2pool);
debug!("Helper | Unlocking (4/12) ... [p2pool]");
drop(node);
debug!("Helper | Unlocking (4/12) ... [node]");
drop(pub_api_xvb);
debug!("Helper | Unlocking (5/12) ... [pub_api_xvb]");
drop(pub_api_xp);
@ -547,6 +577,8 @@ impl Helper {
debug!("Helper | Unlocking (6/12) ... [pub_api_xmrig]");
drop(pub_api_p2pool);
debug!("Helper | Unlocking (7/12) ... [pub_api_p2pool]");
drop(pub_api_node);
debug!("Helper | Unlocking (7/12) ... [node]");
drop(gui_api_xvb);
debug!("Helper | Unlocking (8/12) ... [gui_api_xvb]");
drop(gui_api_xp);
@ -555,6 +587,8 @@ impl Helper {
debug!("Helper | Unlocking (10/12) ... [gui_api_xmrig]");
drop(gui_api_p2pool);
debug!("Helper | Unlocking (11/12) ... [gui_api_p2pool]");
drop(gui_api_node);
debug!("Helper | Unlocking (11/12) ... [node]");
drop(lock);
debug!("Helper | Unlocking (12/12) ... [helper]");

396
src/helper/node.rs Normal file
View file

@ -0,0 +1,396 @@
use std::{
path::Path,
sync::{Arc, Mutex},
thread,
time::{Duration, Instant},
};
use enclose::enc;
use log::{debug, error, info, warn};
use readable::byte::Byte;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use tokio::spawn;
use crate::{
disk::state::Node,
helper::{
check_died, check_user_input, signal_end, sleep_end_loop, ProcessName, ProcessSignal,
ProcessState,
},
macros::{arc_mut, lock2, sleep},
};
use std::fmt::Write;
use super::{lock, Helper, HumanNumber, HumanTime, Process};
impl Helper {
#[cold]
#[inline(never)]
fn read_pty_node(
output_parse: Arc<Mutex<String>>,
output_pub: Arc<Mutex<String>>,
reader: Box<dyn std::io::Read + Send>,
) {
use std::io::BufRead;
let mut stdout = std::io::BufReader::new(reader).lines();
// // Run a ANSI escape sequence filter for the first few lines.
let mut i = 0;
while let Some(Ok(line)) = stdout.next() {
let line = strip_ansi_escapes::strip_str(line);
if let Err(e) = writeln!(lock!(output_parse), "{}", line) {
error!("Node PTY Parse | Output error: {}", e);
}
if let Err(e) = writeln!(lock!(output_pub), "{}", line) {
error!("Node PTY Pub | Output error: {}", e);
}
if i > 20 {
break;
} else {
i += 1;
}
}
while let Some(Ok(line)) = stdout.next() {
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);
}
}
}
pub fn build_node_args(state: &crate::disk::state::Node) -> Vec<String> {
let mut args = Vec::with_capacity(500);
if !state.arguments.is_empty() {
args.push(state.arguments.clone());
return args;
}
// [Simple]
if state.simple {
// Build the node argument to be compatible with p2pool, prune by default
args.push("--zmq-pub".to_string());
args.push("tcp://127.0.0.1:18083".to_string()); // Local P2Pool (the default)
args.push("--out-peers".to_string());
args.push("32".to_string());
args.push("--in-peers".to_string());
args.push("64".to_string()); // Rig name
args.push("--add-priority-node".to_string());
args.push("p2pmd.xmrvsbeast.com:18080".to_string());
args.push("--add-priority-node".to_string());
args.push("nodes.hashvault.pro:18080".to_string());
args.push("--disable-dns-checkpoints".to_string());
args.push("--enable-dns-blocklist".to_string());
args.push("--sync-pruned-blocks".to_string());
args.push("--prune-blockchain".to_string());
// [Advanced]
} else {
let dir = if state.path_db.is_empty() {
String::from(".bitmonero")
} else {
state.path_db.to_string()
};
args.push("--data-dir".to_string());
args.push(dir);
args.push("--zmq-pub".to_string());
args.push(format!("tcp://{}:{}", state.zmq_ip, state.zmq_port));
args.push("--rpc-bind-ip".to_string());
args.push(state.api_ip.clone());
args.push("--rpc-bind-port".to_string());
args.push(state.api_port.to_string());
args.push("--out-peers".to_string());
args.push(state.out_peers.to_string());
args.push("--in-peers".to_string());
args.push(state.in_peers.to_string());
args.push("--sync-pruned-blocks".to_string());
if state.dns_blocklist {
args.push("--enable-dns-blocklist".to_string());
}
if state.disable_dns_checkpoint {
args.push("--disable-dns-checkpoints".to_string());
}
if state.pruned {
args.push("--prune-blockchain".to_string());
}
}
args
}
#[cold]
#[inline(never)]
// Just sets some signals for the watchdog thread to pick up on.
pub fn stop_node(helper: &Arc<Mutex<Self>>) {
info!("Node | Attempting to stop...");
lock2!(helper, node).signal = ProcessSignal::Stop;
lock2!(helper, node).state = ProcessState::Middle;
let gui_api = Arc::clone(&lock!(helper).gui_api_node);
let pub_api = Arc::clone(&lock!(helper).pub_api_node);
*lock!(pub_api) = PubNodeApi::new();
*lock!(gui_api) = PubNodeApi::new();
}
#[cold]
#[inline(never)]
// 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_node(helper: &Arc<Mutex<Self>>, state: &Node, path: &Path) {
info!("Node | Attempting to restart...");
lock2!(helper, node).signal = ProcessSignal::Restart;
lock2!(helper, node).state = ProcessState::Middle;
let helper = Arc::clone(helper);
let state = state.clone();
let path = path.to_path_buf();
// This thread lives to wait, start p2pool then die.
thread::spawn(move || {
while lock2!(helper, node).state != ProcessState::Waiting {
warn!("Node | Want to restart but process is still alive, waiting...");
sleep!(1000);
}
// Ok, process is not alive, start the new one!
info!("Node | Old process seems dead, starting new one!");
Self::start_node(&helper, &state, &path);
});
info!("Node | Restart ... OK");
}
#[cold]
#[inline(never)]
// The "frontend" function that parses the arguments, and spawns either the [Simple] or [Advanced] Node watchdog thread.
pub fn start_node(helper: &Arc<Mutex<Self>>, state: &Node, path: &Path) {
lock2!(helper, node).state = ProcessState::Middle;
let args = Self::build_node_args(state);
// Print arguments & user settings to console
crate::disk::print_dash(&format!("Node | Launch arguments: {:#?}", args));
// Spawn watchdog thread
let process = Arc::clone(&lock!(helper).node);
let gui_api = Arc::clone(&lock!(helper).gui_api_node);
let pub_api = Arc::clone(&lock!(helper).pub_api_node);
let path = path.to_path_buf();
let state = state.clone();
thread::spawn(move || {
Self::spawn_node_watchdog(&process, &gui_api, &pub_api, args, path, state);
});
}
#[tokio::main]
#[allow(clippy::await_holding_lock)]
#[allow(clippy::too_many_arguments)]
async fn spawn_node_watchdog(
process: &Arc<Mutex<Process>>,
gui_api: &Arc<Mutex<PubNodeApi>>,
pub_api: &Arc<Mutex<PubNodeApi>>,
args: Vec<String>,
path: std::path::PathBuf,
state: Node,
) {
lock!(process).start = Instant::now();
// spawn pty
debug!("Node | Creating PTY...");
let pty = portable_pty::native_pty_system();
let pair = pty
.openpty(portable_pty::PtySize {
rows: 100,
cols: 1000,
pixel_width: 0,
pixel_height: 0,
})
.unwrap();
// 4. Spawn PTY read thread
debug!("Node | Spawning PTY read thread...");
let reader = pair.master.try_clone_reader().unwrap(); // Get STDOUT/STDERR before moving the PTY
let output_parse = Arc::clone(&lock!(process).output_parse);
let output_pub = Arc::clone(&lock!(process).output_pub);
spawn(enc!((output_parse, output_pub) async move {
Self::read_pty_node(output_parse, output_pub, reader);
}));
// 1b. Create command
debug!("Node | Creating command...");
let mut cmd = portable_pty::cmdbuilder::CommandBuilder::new(path.clone());
cmd.args(args);
cmd.cwd(path.as_path().parent().unwrap());
// 1c. Create child
debug!("Node | Creating child...");
let child_pty = arc_mut!(pair.slave.spawn_command(cmd).unwrap());
drop(pair.slave);
let mut stdin = pair.master.take_writer().unwrap();
// set state
let client = Client::new();
lock!(process).state = ProcessState::Syncing;
lock!(process).signal = ProcessSignal::None;
// reset stats
*lock!(pub_api) = PubNodeApi::new();
*lock!(gui_api) = PubNodeApi::new();
// loop
let start = lock!(process).start;
info!("Node | Entering watchdog mode... woof!");
loop {
let now = Instant::now();
debug!("Node Watchdog | ----------- Start of loop -----------");
// check state
if check_died(
&child_pty,
&mut lock!(process),
&start,
&mut lock!(gui_api).output,
) {
break;
}
// check signal
if signal_end(process, &child_pty, &start, &mut lock!(gui_api).output) {
break;
}
// check user input
check_user_input(process, &mut stdin);
// get data output/api
// Check if logs need resetting
debug!("Node Watchdog | Attempting GUI log reset check");
{
let mut lock = lock!(gui_api);
Self::check_reset_gui_output(&mut lock.output, ProcessName::Node);
}
// No need to check output since monerod has a sufficient API
// Always update from output
debug!("Node Watchdog | Starting [update_from_output()]");
PubNodeApi::update_from_output(pub_api, &output_pub, start.elapsed());
// update data from api
debug!("Node Watchdog | Attempting HTTP API request...");
match PrivNodeApi::request_api(&client, &state).await {
Ok(priv_api) => {
debug!("Node Watchdog | HTTP API request OK, attempting [update_from_priv()]");
PubNodeApi::update_from_priv(pub_api, priv_api);
}
Err(err) => {
// if node is just starting, do not throw an error
if start.elapsed() > Duration::from_secs(10) {
warn!(
"Node Watchdog | Could not send HTTP API request to node\n{}",
err
);
}
}
}
// do not use more than 1 second for the loop
sleep_end_loop(now, ProcessName::Node).await;
}
// 5. If loop broke, we must be done here.
info!("XMRig-Proxy Watchdog | Watchdog thread exiting... Goodbye!");
// sleep
}
}
#[derive(Clone)]
pub struct PubNodeApi {
pub output: String,
pub uptime: HumanTime,
pub blockheight: HumanNumber,
pub difficulty: HumanNumber,
pub database_size: String,
pub free_space: String,
pub nettype: String,
pub outgoing_connections: u16,
pub incoming_connections: u16,
pub status: String,
pub synchronized: bool,
}
impl Default for PubNodeApi {
fn default() -> Self {
Self::new()
}
}
impl PubNodeApi {
pub fn new() -> Self {
Self {
output: String::new(),
uptime: HumanTime::new(),
blockheight: HumanNumber::unknown(),
difficulty: HumanNumber::unknown(),
database_size: HumanNumber::unknown().to_string(),
free_space: HumanNumber::unknown().to_string(),
nettype: String::from("???"),
outgoing_connections: 0,
incoming_connections: 0,
status: String::from("Offline"),
synchronized: false,
}
}
pub fn combine_gui_pub_api(gui_api: &mut Self, pub_api: &mut Self) {
let output = std::mem::take(&mut gui_api.output);
let buf = std::mem::take(&mut pub_api.output);
*gui_api = Self {
output,
..pub_api.clone()
};
if !buf.is_empty() {
gui_api.output.push_str(&buf);
}
}
fn update_from_priv(public: &Arc<Mutex<Self>>, private: PrivNodeApi) {
let mut public = lock!(public);
*public = Self {
blockheight: HumanNumber::from_u64(private.result.height),
difficulty: HumanNumber::from_u64(private.result.difficulty),
database_size: Byte::from(private.result.database_size).to_string(),
free_space: Byte::from(private.result.free_space).to_string(),
nettype: private.result.nettype,
outgoing_connections: private.result.outgoing_connections_count,
incoming_connections: private.result.incoming_connections_count,
status: private.result.status,
synchronized: private.result.synchronized,
..std::mem::take(&mut *public)
}
}
pub fn update_from_output(
public: &Arc<Mutex<Self>>,
output_pub: &Arc<Mutex<String>>,
elapsed: std::time::Duration,
) {
// 1. Take the process's current output buffer and combine it with Pub (if not empty)
let mut output_pub = lock!(output_pub);
{
let mut public = lock!(public);
if !output_pub.is_empty() {
public.output.push_str(&std::mem::take(&mut *output_pub));
}
// Update uptime
public.uptime = HumanTime::into_human(elapsed);
}
}
}
#[derive(Deserialize, Serialize)]
struct PrivNodeApi {
result: ResultNodeJson,
}
#[derive(Deserialize, Serialize)]
struct ResultNodeJson {
pub height: u64,
pub difficulty: u64,
pub database_size: u64,
pub free_space: u64,
pub nettype: String,
pub outgoing_connections_count: u16,
pub incoming_connections_count: u16,
pub status: String,
pub synchronized: bool,
}
impl PrivNodeApi {
async fn request_api(
client: &Client,
state: &Node,
) -> std::result::Result<Self, anyhow::Error> {
let adr = format!("http://{}:{}/json_rpc", state.api_ip, state.api_port);
let private = client
.post(adr)
.body(r#"{"jsonrpc":"2.0","id":"0","method":"get_info"}"#)
.send()
.await?
.json::<PrivNodeApi>()
.await?;
Ok(private)
}
}

View file

@ -1,4 +1,5 @@
use crate::components::update::Update;
use crate::errors::process_running;
use crate::helper::{Helper, ProcessSignal};
use crate::utils::constants::{
APP_MAX_HEIGHT, APP_MAX_WIDTH, APP_MIN_HEIGHT, APP_MIN_WIDTH, BYTES_ICON,
@ -43,7 +44,7 @@ pub fn init_text_styles(ctx: &egui::Context, width: f32, pixels_per_point: f32)
),
(
Name("Tab".into()),
FontId::new(scale * 1.2, egui::FontFamily::Monospace),
FontId::new(scale * 1.05, egui::FontFamily::Monospace),
),
(
Name("Bottom".into()),
@ -180,6 +181,26 @@ pub fn init_auto(app: &mut App) {
info!("Skipping auto-ping...");
}
// [Auto-Node]
if app.state.gupax.auto_node {
if !Gupax::path_is_file(&app.state.gupax.node_path) {
warn!("Gupaxx | Node path is not a file! Skipping auto-node...");
} else if !crate::components::update::check_node_path(&app.state.gupax.node_path) {
warn!("Gupaxx | Node path is not valid! Skipping auto-node...");
} else if process_running(crate::helper::ProcessName::Node) {
warn!("Gupaxx | Node instance is already running outside of Gupaxx ! Skipping auto-node...");
} else {
// enable hugepage on linux
// sudo sysctl vm.nr_hugepages=3072
Helper::start_node(
&app.helper,
&app.state.node,
&app.state.gupax.absolute_node_path,
);
}
} else {
info!("Skipping auto-p2pool...");
}
// [Auto-P2Pool]
if app.state.gupax.auto_p2pool {
if !Regexes::addr_ok(&app.state.p2pool.address) {
@ -188,6 +209,8 @@ pub fn init_auto(app: &mut App) {
warn!("Gupaxx | P2Pool path is not a file! Skipping auto-p2pool...");
} else if !crate::components::update::check_p2pool_path(&app.state.gupax.p2pool_path) {
warn!("Gupaxx | P2Pool path is not valid! Skipping auto-p2pool...");
} else if process_running(crate::helper::ProcessName::P2pool) {
warn!("Gupaxx | P2pool instance is already running outside of Gupaxx ! Skipping auto-node...");
} else {
let backup_hosts = app.gather_backup_hosts();
Helper::start_p2pool(
@ -207,6 +230,8 @@ pub fn init_auto(app: &mut App) {
warn!("Gupaxx | XMRig path is not an executable! Skipping auto-xmrig...");
} else if !crate::components::update::check_xmrig_path(&app.state.gupax.xmrig_path) {
warn!("Gupaxx | XMRig path is not valid! Skipping auto-xmrig...");
} else if process_running(crate::helper::ProcessName::Xmrig) {
warn!("Gupaxx | Xmrig instance is already running outside of Gupaxx ! Skipping auto-node...");
} else if cfg!(windows) {
Helper::start_xmrig(
&app.helper,
@ -227,6 +252,8 @@ pub fn init_auto(app: &mut App) {
warn!("Gupaxx | Xmrig-Proxy path is not a file! Skipping auto-xmrig_proxy...");
} else if !crate::components::update::check_xp_path(&app.state.gupax.xmrig_proxy_path) {
warn!("Gupaxx | Xmrig-Proxy path is not valid! Skipping auto-xmrig_proxy...");
} else if process_running(crate::helper::ProcessName::XmrigProxy) {
warn!("Gupaxx | Xmrig-Proxy instance is already running outside of Gupaxx ! Skipping auto-node...");
} else {
Helper::start_xp(
&app.helper,

View file

@ -19,6 +19,7 @@ pub const GUPAX_VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); // e.g:
pub const P2POOL_VERSION: &str = "v4.1";
pub const XMRIG_VERSION: &str = "v6.21.1";
pub const XMRIG_PROXY_VERSION: &str = "v6.21.1";
pub const NODE_VERSION: &str = "v18.3.4";
pub const COMMIT: &str = env!("COMMIT"); // set in build.rs
// e.g: Gupax_v1_0_0
// Would have been [Gupax_v1.0.0] but P2Pool truncates everything after [.]
@ -102,6 +103,12 @@ pub const P2POOL_MIDDLE: &str = "P2Pool is in the middle of (re)starting/stoppin
pub const P2POOL_SYNCING: &str =
"P2Pool is still syncing. This indicator will turn GREEN when P2Pool is ready";
pub const NODE_ALIVE: &str = "Node is online and fully synchronized";
pub const NODE_DEAD: &str = "Node is offline";
pub const NODE_FAILED: &str = "Node is offline and failed when exiting";
pub const NODE_MIDDLE: &str = "Node is in the middle of (re)starting/stopping";
pub const NODE_SYNCING: &str =
"Node is still syncing. This indicator will turn GREEN when Node is ready";
pub const XMRIG_ALIVE: &str = "XMRig is online and mining";
pub const XMRIG_DEAD: &str = "XMRig is offline";
pub const XMRIG_FAILED: &str = "XMRig is offline and failed when exiting";
@ -236,6 +243,17 @@ pub const STATUS_XVB_WINNER: &str = "Current Raffle Winner";
pub const STATUS_XVB_SHARE: &str = "Share effort";
pub const STATUS_XVB_BLOCK_REWARD: &str = "Block reward";
pub const STATUS_XVB_YEARLY: &str = "Estimated Reward (Yearly)";
// Status Node
pub const STATUS_NODE_UPTIME: &str = "How long the Node has been online";
pub const STATUS_NODE_BLOCK_HEIGHT: &str = "The height of where the node is synchronized";
pub const STATUS_NODE_DIFFICULTY: &str = "current difficulty of the network";
pub const STATUS_NODE_DB_SIZE: &str = "Size of the database";
pub const STATUS_NODE_FREESPACE: &str = "Free space left on the partition storing the database";
pub const STATUS_NODE_NETTYPE: &str = "Type of network (mainnet, stagenet, testnet)";
pub const STATUS_NODE_OUT: &str = "Current number of active outbound connections";
pub const STATUS_NODE_IN: &str = "Current number of active incoming connections";
pub const STATUS_NODE_SYNC: &str = "Does the node is synchronized with the network ?";
pub const STATUS_NODE_STATUS: &str = "General status of the node";
// Status Submenus
pub const STATUS_SUBMENU_PROCESSES: &str =
"View the status of process related data for [Gupaxx|P2Pool|XMRig]";
@ -311,6 +329,7 @@ pub const GUPAX_SHOULD_RESTART: &str =
pub const GUPAX_ASK_BEFORE_QUIT: &str = "Ask before quitting Gupaxx";
pub const GUPAX_SAVE_BEFORE_QUIT: &str = "Automatically save any changed settings before quitting";
pub const GUPAX_AUTO_P2POOL: &str = "Automatically start P2Pool on Gupaxx startup. If you are using [P2Pool Simple], this will NOT wait for your [Auto-Ping] to finish, it will start P2Pool on the pool you already have selected. This option will fail if your P2Pool settings aren't valid!";
pub const GUPAX_AUTO_NODE: &str = "Automatically start Node on Gupaxx startup. This option will fail if your P2Pool settings aren't valid!";
pub const GUPAX_AUTO_XMRIG: &str = "Automatically start XMRig on Gupaxx startup. This option will fail if your XMRig settings aren't valid!";
pub const GUPAX_AUTO_XMRIG_PROXY: &str = "Automatically start XMRig-Proxy on Gupaxx startup.";
pub const GUPAX_AUTO_XVB: &str = "Automatically start XvB on Gupaxx startup. This option will fail if your XvB settings aren't valid!";
@ -332,6 +351,7 @@ pub const GUPAX_TAB_GUPAX: &str = "Set the tab Gupaxx starts on to: Gupaxx";
pub const GUPAX_TAB_P2POOL: &str = "Set the tab Gupaxx starts on to: P2Pool";
pub const GUPAX_TAB_XMRIG: &str = "Set the tab Gupaxx starts on to: XMRig";
pub const GUPAX_TAB_XVB: &str = "Set the tab Gupaxx starts on to: XvB";
pub const GUPAX_TAB_NODE: &str = "Set the default tab Gupaxx starts on to: Node";
pub const GUPAX_SIMPLE: &str = r#"Use simple Gupaxx settings:
- Update button
@ -407,6 +427,39 @@ pub const LIST_ADD: &str = "Add the current values to the list";
pub const LIST_SAVE: &str = "Save the current values to the already existing entry";
pub const LIST_DELETE: &str = "Delete the currently selected entry";
pub const LIST_CLEAR: &str = "Clear all current values";
// Node
pub const NODE_ARGUMENTS: &str = r#"WARNING: Make sure to set [--zmq-pub <tcp://127.0.0.1:18081>] so that P2Pool can connect to it !"#;
pub const NODE_INPUT: &str = "Send a command to Node";
pub const NODE_PRUNNING: &str = "Reduce the database size to a third. Does not have any security/privacy impact.If you have enough storage, a full node is preferable to make the network even more decentralized.";
pub const NODE_DB_PATH_EMPTY: &str =
"If the PATH of the DB is empty, the default ~/.bitmonero will be used.";
pub const NODE_DB_DIR: &str = "The PATH needs to be a correct path to a directory";
pub const NODE_SIMPLE: &str = r#"Use simple Node settings:
- Default Node settings"#;
pub const NODE_ADVANCED: &str = r#"Use advanced Node settings:
- Prunning
- Custom path for database
- Terminal input
- Overriding command arguments
- Manual zmq port
- Out/In peer setting
- Log level setting
- Disable DNS checkpoint
- DNS blocking"#;
pub const GUPAX_PATH_NODE: &str = "The location of the DB for the Node: Both absolute and relative paths are accepted; A red [X] will appear if there is no directory found at the given path";
pub const NODE_PATH_OK: &str = "PATH for DB is valid.";
pub const NODE_PATH_NOT_FILE: &str = "Node binary not found at the given PATH in the Gupaxx tab! To fix: goto the [Gupaxx Advanced] tab, select [Open] and specify where NODE is located.";
pub const NODE_PATH_NOT_VALID: &str = "Node binary at the given PATH in the Gupaxx tab doesn't look like Node! To fix: goto the [Gupaxx Advanced] tab, select [Open] and specify where Node is located.";
pub const NODE_PATH_EMPTY: &str = "Node PATH is empty! To fix: goto the [Gupaxx Advanced] tab, select [Open] and specify where Node is located.";
pub const NODE_URL: &str = "https://github.com/monero-project/monero";
pub const NODE_DNS_BLOCKLIST: &str =
"Apply realtime blocklist from DNS to ban known malicious nodes. (recommended)";
pub const NODE_DNS_CHECKPOINT: &str =
"Do not retrieve checkpoints from DNS to prevent periodic lags (recommended)";
pub const NODE_API_BIND: &str = "bind address of RPC API";
pub const NODE_API_PORT: &str = "RPC API listen port";
pub const NODE_ZMQ_BIND: &str = "bind address of ZMQ API";
pub const NODE_ZMQ_PORT: &str = "ZMQ API listen port";
// XMRig
pub const XMRIG_SIMPLE: &str = r#"Use simple XMRig settings:
- Mine to local P2Pool (localhost:3333)

View file

@ -98,6 +98,7 @@ impl ErrorState {
pub fn process_running(process_name: ProcessName) -> bool {
let name = match process_name {
ProcessName::Node => "monerod",
ProcessName::P2pool => "p2pool",
ProcessName::Xmrig => "xmrig",
ProcessName::XmrigProxy => "xmrig-proxy",

View file

@ -1,5 +1,7 @@
//---------------------------------------------------------------------------------------------------- Use
use crate::constants::{COMMIT, GUPAX_VERSION, OS_NAME, P2POOL_VERSION, XMRIG_VERSION};
use crate::constants::{
COMMIT, GUPAX_VERSION, NODE_VERSION, OS_NAME, P2POOL_VERSION, XMRIG_VERSION,
};
//----------------------------------------------------------------------------------------------------
#[cold]
@ -17,13 +19,15 @@ pub(crate) fn set_panic_hook(now: std::time::Instant) {
"{panic_info:#?}
info:
OS | {OS_NAME}
args | {args:?}
commit | {COMMIT}
gupaxx | {GUPAX_VERSION}
p2pool | {P2POOL_VERSION} (bundled)
xmrig | {XMRIG_VERSION} (bundled)
uptime | {uptime} seconds
OS | {OS_NAME}
args | {args:?}
commit | {COMMIT}
gupaxx | {GUPAX_VERSION}
monerod | {NODE_VERSION} (bundled)
p2pool | {P2POOL_VERSION} (bundled)
xmrig | {XMRIG_VERSION} (bundled)
xmrig-proxy | {XMRIG_VERSION} (bundled)
uptime | {uptime} seconds
stack backtrace:\n{stack_trace}",
);

View file

@ -93,6 +93,32 @@ mv p2pool-v4.1-windows-x64/p2pool.exe /tmp/${FOLDER}/skel/windows_b/P2Pool/p2poo
rm -r p2pool-v4.1-windows-x64
rm p2pool-v4.1-windows-x64.zip
## Download Monero Binaries
# download monero into directory linux
wget https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.3.4.tar.bz2
tar -xf monero-linux-x64-v0.18.3.4.tar.bz2
mv monero-x86_64-linux-gnu-v0.18.3.4/monerod /tmp/${FOLDER}/skel/linux_b/node/monerod
rm -r monero-x86_64-linux-gnu-v0.18.3.4
rm monero-linux-x64-v0.18.3.4.tar.bz2
# download monero into directory macos-arm64
wget https://downloads.getmonero.org/cli/monero-mac-armv8-v0.18.3.4.tar.bz2
tar -xf monero-mac-armv8-v0.18.3.4.tar.bz2
mv monero-aarch64-apple-darwin11-v0.18.3.4/monerod /tmp/${FOLDER}/skel/macos-arm64_b/Gupaxx.app/Contents/MacOS/node/monerod
rm -r monero-aarch64-apple-darwin11-v0.18.3.4
rm monero-mac-armv8-v0.18.3.4.tar.bz2
# download monero into directory macos-x64
wget https://downloads.getmonero.org/cli/monero-mac-x64-v0.18.3.4.tar.bz2
tar -xf monero-mac-x64-v0.18.3.4.tar.bz2
mv monero-x86_64-apple-darwin11-v0.18.3.4/monerod /tmp/${FOLDER}/skel/macos-x64_b/Gupaxx.app/Contents/MacOS/node/monerod
rm -r monero-x86_64-apple-darwin11-v0.18.3.4
rm monero-mac-x64-v0.18.3.4.tar.bz2
# download monero into directory windows
wget https://downloads.getmonero.org/cli/monero-win-x64-v0.18.3.4.zip
unzip monero-win-x64-v0.18.3.4.zip
mv monero-x86_64-w64-mingw32-v0.18.3.4/monerod.exe /tmp/${FOLDER}/skel/windows_b/node/monerod.exe
rm -r monero-x86_64-w64-mingw32-v0.18.3.4
rm monero-win-x64-v0.18.3.4.zip
set +ex
echo

View file

@ -34,12 +34,14 @@ title "Linux folder check"
[[ -f linux_b/p2pool/p2pool ]]; check "linux_b/p2pool/p2pool"
[[ -f linux_b/xmrig/xmrig ]]; check "linux_b/xmrig/xmrig"
[[ -f linux_b/xmrig-proxy/xmrig-proxy ]]; check "linux_b/xmrig-proxy/xmrig-proxy"
[[ -f linux_b/node/monerod ]]; check "linux_b/node/monerod"
title "macOS-x64 folder check"
[[ -d macos-x64/Gupaxx.app ]]; check "macos-x64/Gupaxx.app"
[[ -d macos-x64_b/Gupaxx.app ]]; check "macos-x64_b/Gupaxx.app"
[[ -f macos-x64_b/Gupaxx.app/Contents/MacOS/p2pool/p2pool ]]; check "macos-x64_b/p2pool/p2pool"
[[ -f macos-x64_b/Gupaxx.app/Contents/MacOS/xmrig/xmrig ]]; check "macos-x64_b/xmrig/xmrig"
[[ -f macos-x64_b/Gupaxx.app/Contents/MacOS/xmrig-proxy/xmrig-proxy ]]; check "macos-x64_b/xmrig-proxy/xmrig-proxy"
[[ -f macos-x64_b/node/monerod ]]; check "macos-x64_b/node/monerod"
title "macOS-arm64 folder check"
[[ -d macos-arm64/Gupaxx.app ]]; check "macos-arm64/Gupaxx.app"
[[ -d macos-arm64_b/Gupaxx.app ]]; check "macos-arm64_b/Gupaxx.app"
@ -47,12 +49,14 @@ title "macOS-arm64 folder check"
[[ -f macos-arm64_b/Gupaxx.app/Contents/MacOS/xmrig/xmrig ]]; check "macos-arm64_b/xmrig/xmrig"
## no macos-arm64 xmrig-proxy released todo
# [[ -f macos-arm64_b/Gupaxx.app/Contents/MacOS/xmrig-proxy/xmrig-proxy ]]; check "macos-arm64_b/xmrig-proxy/xmrig-proxy"
[[ -f macos-arm64_b/node/monerod ]]; check "macos-arm64_b/node/monerod"
title "Windows folder check"
[[ -f windows/Gupaxx.exe ]]; check "windows/Gupaxx.exe"
[[ -f windows_b/Gupaxx.exe ]]; check "windows_b/Gupaxx.exe"
[[ -f windows_b/P2Pool/p2pool.exe ]]; check "windows_b/P2Pool/p2pool.exe"
[[ -f windows_b/XMRig/xmrig.exe ]]; check "windows_b/XMRig/xmrig.exe"
[[ -f windows_b/XMRig-Proxy/xmrig-proxy.exe ]]; check "windows_b/XMRig-Proxy/xmrig-proxy.exe"
[[ -f windows_b/node/monerod.exe ]]; check "windows_b/node/monerod.exe"
# Get random date for tar/zip
title "RNG Date"
@ -67,6 +71,7 @@ chmod +x linux_b/gupaxx
chmod +x linux_b/p2pool/p2pool
chmod +x linux_b/xmrig/xmrig
chmod +x linux_b/xmrig-proxy/xmrig-proxy
chmod +x linux_b/node/monderod
mv linux_b "gupaxx-$NEW_VER-linux-x64-bundle"; check "linux -> gupaxx-$NEW_VER-linux-x64-bundle"
tar -czpf "gupaxx-${NEW_VER}-linux-x64-bundle.tar.gz" "gupaxx-$NEW_VER-linux-x64-bundle" --owner=lm --group=lm ; check "tar linux-bundle"
# Tar Linux Standalone