mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-12-22 14:49:21 +00:00
feat: reworked UI for size/spacing/resizing/responsivness/alignment/coherence on every panels.
feat: reduction in code dupplication related to UI feat: update header of XvB tab feat: upgrade egui to git main feat: upgrade deps
This commit is contained in:
parent
55b39cf2c3
commit
50b3336156
38 changed files with 3477 additions and 4101 deletions
601
Cargo.lock
generated
601
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
15
Cargo.toml
15
Cargo.toml
|
@ -31,8 +31,11 @@ benri = "0.1.12"
|
||||||
bytes = "1.8.0"
|
bytes = "1.8.0"
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
#--------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------
|
||||||
egui = "0.29.1"
|
# egui = "0.29.1"
|
||||||
egui_extras = {version="0.29.1", features = ["image"] }
|
egui = {git="https://github.com/emilk/egui"}
|
||||||
|
# egui_extras = {version="0.29.1", features = ["image"] }
|
||||||
|
egui_extras = {git="https://github.com/emilk/egui", features = ["image"] }
|
||||||
|
|
||||||
## 2023-12-28: https://github.com/hinto-janai/gupax/issues/68
|
## 2023-12-28: https://github.com/hinto-janai/gupax/issues/68
|
||||||
##
|
##
|
||||||
## 2024-03-18: Both `glow` and `wgpu` seem to crash:
|
## 2024-03-18: Both `glow` and `wgpu` seem to crash:
|
||||||
|
@ -75,7 +78,8 @@ enclose = "1.2.0"
|
||||||
bounded-vec-deque = {version="0.1.1", default-features=false}
|
bounded-vec-deque = {version="0.1.1", default-features=false}
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
flexi_logger = "0.29"
|
flexi_logger = "0.29"
|
||||||
eframe = {version="0.29.1", features=["wgpu"]}
|
# eframe = {version="0.29.1", features=["wgpu"]}
|
||||||
|
eframe = {git="https://github.com/emilk/egui", features=["wgpu"]}
|
||||||
strum = {version="0.26", features=["derive"]}
|
strum = {version="0.26", features=["derive"]}
|
||||||
# Unix dependencies
|
# Unix dependencies
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
@ -97,7 +101,8 @@ sudo = "0.6.0"
|
||||||
# linked as well which causes problems, so statically link it.
|
# linked as well which causes problems, so statically link it.
|
||||||
lzma-sys = { version = "0.1", features = ["static"] }
|
lzma-sys = { version = "0.1", features = ["static"] }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
egui = {version="0.29.1", features=["callstack"]}
|
# egui = {version="0.29.1", features=["callstack"]}
|
||||||
|
egui = {git="https://github.com/emilk/egui", features=["callstack"]}
|
||||||
|
|
||||||
# [target.'cfg(not(target_os = "macos"))'.dependencies]
|
# [target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||||
# tls-api-native-tls = "0.9.0"
|
# tls-api-native-tls = "0.9.0"
|
||||||
|
@ -107,7 +112,7 @@ egui = {version="0.29.1", features=["callstack"]}
|
||||||
# glow start on windows but not wgpu
|
# glow start on windows but not wgpu
|
||||||
# need the same version that eframe is using with egui_wgpu
|
# need the same version that eframe is using with egui_wgpu
|
||||||
# feature angle to enable support for old cpu on Windows
|
# feature angle to enable support for old cpu on Windows
|
||||||
wgpu = {version = "22.1", features=["angle"]}
|
wgpu = {version = "23.0", features=["angle"]}
|
||||||
zip = "2.2.0"
|
zip = "2.2.0"
|
||||||
is_elevated = "0.1.2"
|
is_elevated = "0.1.2"
|
||||||
|
|
||||||
|
|
119
src/app/mod.rs
119
src/app/mod.rs
|
@ -1,5 +1,13 @@
|
||||||
use crate::APP_DEFAULT_HEIGHT;
|
use crate::APP_DEFAULT_HEIGHT;
|
||||||
use crate::APP_DEFAULT_WIDTH;
|
use crate::APP_DEFAULT_WIDTH;
|
||||||
|
use crate::GUPAX_TAB_ABOUT;
|
||||||
|
use crate::GUPAX_TAB_GUPAX;
|
||||||
|
use crate::GUPAX_TAB_NODE;
|
||||||
|
use crate::GUPAX_TAB_P2POOL;
|
||||||
|
use crate::GUPAX_TAB_STATUS;
|
||||||
|
use crate::GUPAX_TAB_XMRIG;
|
||||||
|
use crate::GUPAX_TAB_XMRIG_PROXY;
|
||||||
|
use crate::GUPAX_TAB_XVB;
|
||||||
use crate::GUPAX_VERSION;
|
use crate::GUPAX_VERSION;
|
||||||
use crate::OS;
|
use crate::OS;
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
|
@ -47,6 +55,7 @@ use log::debug;
|
||||||
use log::error;
|
use log::error;
|
||||||
use log::info;
|
use log::info;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
use panels::middle::common::list_poolnode::PoolNode;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -87,10 +96,10 @@ pub struct App {
|
||||||
pub update: Arc<Mutex<Update>>, // State for update data [update.rs]
|
pub update: Arc<Mutex<Update>>, // State for update data [update.rs]
|
||||||
pub file_window: Arc<Mutex<FileWindow>>, // State for the path selector in [Gupax]
|
pub file_window: Arc<Mutex<FileWindow>>, // State for the path selector in [Gupax]
|
||||||
pub ping: Arc<Mutex<Ping>>, // Ping data found in [node.rs]
|
pub ping: Arc<Mutex<Ping>>, // Ping data found in [node.rs]
|
||||||
pub og_node_vec: Vec<(String, Node)>, // Manual Node database
|
pub og_node_vec: Vec<(String, PoolNode)>, // Manual Node database
|
||||||
pub node_vec: Vec<(String, Node)>, // Manual Node database
|
pub node_vec: Vec<(String, PoolNode)>, // Manual Node database
|
||||||
pub og_pool_vec: Vec<(String, Pool)>, // Manual Pool database
|
pub og_pool_vec: Vec<(String, PoolNode)>, // Manual Pool database
|
||||||
pub pool_vec: Vec<(String, Pool)>, // Manual Pool database
|
pub pool_vec: Vec<(String, PoolNode)>, // Manual Pool database
|
||||||
pub diff: bool, // This bool indicates state changes
|
pub diff: bool, // This bool indicates state changes
|
||||||
// Restart state:
|
// Restart state:
|
||||||
// If Gupax updated itself, this represents that the
|
// If Gupax updated itself, this represents that the
|
||||||
|
@ -136,7 +145,7 @@ pub struct App {
|
||||||
// Static stuff
|
// Static stuff
|
||||||
pub benchmarks: Vec<Benchmark>, // XMRig CPU benchmarks
|
pub benchmarks: Vec<Benchmark>, // XMRig CPU benchmarks
|
||||||
pub pid: sysinfo::Pid, // Gupax's PID
|
pub pid: sysinfo::Pid, // Gupax's PID
|
||||||
pub max_threads: usize, // Max amount of detected system threads
|
pub max_threads: u16, // Max amount of detected system threads
|
||||||
pub now: Instant, // Internal timer
|
pub now: Instant, // Internal timer
|
||||||
pub exe: String, // Path for [Gupax] binary
|
pub exe: String, // Path for [Gupax] binary
|
||||||
pub dir: String, // Directory [Gupax] binary is in
|
pub dir: String, // Directory [Gupax] binary is in
|
||||||
|
@ -311,7 +320,7 @@ impl App {
|
||||||
pub_sys,
|
pub_sys,
|
||||||
benchmarks,
|
benchmarks,
|
||||||
pid,
|
pid,
|
||||||
max_threads: benri::threads!(),
|
max_threads: benri::threads!() as u16,
|
||||||
now,
|
now,
|
||||||
admin: false,
|
admin: false,
|
||||||
exe: String::new(),
|
exe: String::new(),
|
||||||
|
@ -511,65 +520,83 @@ impl App {
|
||||||
}
|
}
|
||||||
// Handle [node_vec] overflow
|
// Handle [node_vec] overflow
|
||||||
info!("App Init | Handling [node_vec] overflow");
|
info!("App Init | Handling [node_vec] overflow");
|
||||||
if og.p2pool.selected_index > app.og_node_vec.len() {
|
if og.p2pool.selected_node.index > app.og_node_vec.len() {
|
||||||
warn!(
|
warn!(
|
||||||
"App | Overflowing manual node index [{} > {}]",
|
"App | Overflowing manual node index [{} > {}]",
|
||||||
og.p2pool.selected_index,
|
og.p2pool.selected_node.index,
|
||||||
app.og_node_vec.len()
|
app.og_node_vec.len()
|
||||||
);
|
);
|
||||||
let (name, node) = match app.og_node_vec.first() {
|
let (name, node) = match app.og_node_vec.first() {
|
||||||
Some(zero) => zero.clone(),
|
Some(zero) => zero.clone(),
|
||||||
None => Node::new_tuple(),
|
None => Node::new_tuple(),
|
||||||
};
|
};
|
||||||
og.p2pool.selected_index = 0;
|
og.p2pool.selected_node.index = 0;
|
||||||
og.p2pool.selected_name.clone_from(&name);
|
og.p2pool.selected_node.name.clone_from(&name);
|
||||||
og.p2pool.selected_ip.clone_from(&node.ip);
|
og.p2pool
|
||||||
og.p2pool.selected_rpc.clone_from(&node.rpc);
|
.selected_node
|
||||||
og.p2pool.selected_zmq.clone_from(&node.zmq);
|
.ip
|
||||||
app.state.p2pool.selected_index = 0;
|
.clone_from(&node.ip().to_string());
|
||||||
app.state.p2pool.selected_name = name;
|
og.p2pool
|
||||||
app.state.p2pool.selected_ip = node.ip;
|
.selected_node
|
||||||
app.state.p2pool.selected_rpc = node.rpc;
|
.rpc
|
||||||
app.state.p2pool.selected_zmq = node.zmq;
|
.clone_from(&node.port().to_string());
|
||||||
|
og.p2pool
|
||||||
|
.selected_node
|
||||||
|
.zmq_rig
|
||||||
|
.clone_from(&node.custom().to_string());
|
||||||
|
app.state.p2pool.selected_node.index = 0;
|
||||||
|
app.state.p2pool.selected_node.name = name;
|
||||||
|
app.state.p2pool.selected_node.ip = node.ip().to_string();
|
||||||
|
app.state.p2pool.selected_node.rpc = node.port().to_string();
|
||||||
|
app.state.p2pool.selected_node.zmq_rig = node.custom().to_string();
|
||||||
}
|
}
|
||||||
// Handle [pool_vec] overflow
|
// Handle [pool_vec] overflow
|
||||||
info!("App Init | Handling [pool_vec] overflow...");
|
info!("App Init | Handling [pool_vec] overflow...");
|
||||||
if og.xmrig.selected_index > app.og_pool_vec.len() {
|
if og.xmrig.selected_pool.index > app.og_pool_vec.len() {
|
||||||
warn!(
|
warn!(
|
||||||
"App | Overflowing manual pool index [{} > {}], resetting to 1",
|
"App | Overflowing manual pool index [{} > {}], resetting to 1",
|
||||||
og.xmrig.selected_index,
|
og.xmrig.selected_pool.index,
|
||||||
app.og_pool_vec.len()
|
app.og_pool_vec.len()
|
||||||
);
|
);
|
||||||
let (name, pool) = match app.og_pool_vec.first() {
|
let (name, pool) = match app.og_pool_vec.first() {
|
||||||
Some(zero) => zero.clone(),
|
Some(zero) => zero.clone(),
|
||||||
None => Pool::new_tuple(),
|
None => Pool::new_tuple(),
|
||||||
};
|
};
|
||||||
og.xmrig.selected_index = 0;
|
og.xmrig.selected_pool.index = 0;
|
||||||
og.xmrig.selected_name.clone_from(&name);
|
og.xmrig.selected_pool.name.clone_from(&name);
|
||||||
og.xmrig.selected_ip.clone_from(&pool.ip);
|
og.xmrig.selected_pool.ip.clone_from(&pool.ip().to_string());
|
||||||
og.xmrig.selected_port.clone_from(&pool.port);
|
og.xmrig
|
||||||
app.state.xmrig.selected_index = 0;
|
.selected_pool
|
||||||
app.state.xmrig.selected_name = name;
|
.rpc
|
||||||
app.state.xmrig.selected_ip = pool.ip;
|
.clone_from(&pool.port().to_string());
|
||||||
app.state.xmrig.selected_port = pool.port;
|
app.state.xmrig.selected_pool.index = 0;
|
||||||
if og.xmrig_proxy.selected_index > app.og_pool_vec.len() {
|
app.state.xmrig.selected_pool.name = name;
|
||||||
|
app.state.xmrig.selected_pool.ip = pool.ip().to_string();
|
||||||
|
app.state.xmrig.selected_pool.rpc = pool.port().to_string();
|
||||||
|
if og.xmrig_proxy.selected_pool.index > app.og_pool_vec.len() {
|
||||||
warn!(
|
warn!(
|
||||||
"App | Overflowing manual pool index [{} > {}], resetting to 1",
|
"App | Overflowing manual pool index [{} > {}], resetting to 1",
|
||||||
og.xmrig_proxy.selected_index,
|
og.xmrig_proxy.selected_pool.index,
|
||||||
app.og_pool_vec.len()
|
app.og_pool_vec.len()
|
||||||
);
|
);
|
||||||
let (name, pool) = match app.og_pool_vec.first() {
|
let (name, pool) = match app.og_pool_vec.first() {
|
||||||
Some(zero) => zero.clone(),
|
Some(zero) => zero.clone(),
|
||||||
None => Pool::new_tuple(),
|
None => Pool::new_tuple(),
|
||||||
};
|
};
|
||||||
og.xmrig_proxy.selected_index = 0;
|
og.xmrig_proxy.selected_pool.index = 0;
|
||||||
og.xmrig_proxy.selected_name.clone_from(&name);
|
og.xmrig_proxy.selected_pool.name.clone_from(&name);
|
||||||
og.xmrig_proxy.selected_ip.clone_from(&pool.ip);
|
og.xmrig_proxy
|
||||||
og.xmrig_proxy.selected_port.clone_from(&pool.port);
|
.selected_pool
|
||||||
app.state.xmrig_proxy.selected_index = 0;
|
.ip
|
||||||
app.state.xmrig_proxy.selected_name = name;
|
.clone_from(&pool.ip().to_string());
|
||||||
app.state.xmrig_proxy.selected_ip = pool.ip;
|
og.xmrig_proxy
|
||||||
app.state.xmrig_proxy.selected_port = pool.port;
|
.selected_pool
|
||||||
|
.rpc
|
||||||
|
.clone_from(&pool.port().to_string());
|
||||||
|
app.state.xmrig_proxy.selected_pool.index = 0;
|
||||||
|
app.state.xmrig_proxy.selected_pool.name = name;
|
||||||
|
app.state.xmrig_proxy.selected_pool.ip = pool.ip().to_string();
|
||||||
|
app.state.xmrig_proxy.selected_pool.rpc = pool.port().to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,7 +675,7 @@ impl App {
|
||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn gather_backup_hosts(&self) -> Option<Vec<Node>> {
|
pub fn gather_backup_hosts(&self) -> Option<Vec<PoolNode>> {
|
||||||
if !self.state.p2pool.backup_host {
|
if !self.state.p2pool.backup_host {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -695,7 +722,7 @@ impl App {
|
||||||
zmq: zmq.into(),
|
zmq: zmq.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
vec.push(node);
|
vec.push(PoolNode::Node(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.is_empty() {
|
if vec.is_empty() {
|
||||||
|
@ -747,6 +774,18 @@ impl Tab {
|
||||||
Tab::Xvb => Some(ProcessName::Xvb),
|
Tab::Xvb => Some(ProcessName::Xvb),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn msg_default_tab(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Tab::About => GUPAX_TAB_ABOUT,
|
||||||
|
Tab::Status => GUPAX_TAB_STATUS,
|
||||||
|
Tab::Gupax => GUPAX_TAB_GUPAX,
|
||||||
|
Tab::Node => GUPAX_TAB_NODE,
|
||||||
|
Tab::P2pool => GUPAX_TAB_P2POOL,
|
||||||
|
Tab::Xmrig => GUPAX_TAB_XMRIG,
|
||||||
|
Tab::XmrigProxy => GUPAX_TAB_XMRIG_PROXY,
|
||||||
|
Tab::Xvb => GUPAX_TAB_XVB,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------------------------- [Restart] Enum
|
//---------------------------------------------------------------------------------------------------- [Restart] Enum
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
|
|
@ -207,16 +207,30 @@ impl crate::app::App {
|
||||||
let restart_msg = format!("Restart {}", name);
|
let restart_msg = format!("Restart {}", name);
|
||||||
if process.waiting {
|
if process.waiting {
|
||||||
ui.add_enabled_ui(false, |ui| {
|
ui.add_enabled_ui(false, |ui| {
|
||||||
ui.add_sized(size, Button::new("⟲"))
|
ui.add_sized(size, Button::new("▶"))
|
||||||
.on_disabled_hover_text(process.run_middle_msg());
|
.on_disabled_hover_text(process.run_middle_msg());
|
||||||
ui.add(Separator::default().grow(0.0));
|
ui.add(Separator::default().grow(0.0));
|
||||||
ui.add_sized(size, Button::new("⏹"))
|
ui.add_sized(size, Button::new("⏹"))
|
||||||
.on_disabled_hover_text(process.run_middle_msg());
|
.on_disabled_hover_text(process.run_middle_msg());
|
||||||
ui.add(Separator::default().grow(0.0));
|
ui.add(Separator::default().grow(0.0));
|
||||||
ui.add_sized(size, Button::new("▶"))
|
ui.add_sized(size, Button::new("⟲"))
|
||||||
.on_disabled_hover_text(process.run_middle_msg());
|
.on_disabled_hover_text(process.run_middle_msg());
|
||||||
});
|
});
|
||||||
} else if process.alive {
|
} else if process.alive {
|
||||||
|
ui.add_enabled_ui(false, |ui| {
|
||||||
|
ui.add_sized(size, Button::new("▶"))
|
||||||
|
.on_disabled_hover_text(start_msg)
|
||||||
|
});
|
||||||
|
ui.add(Separator::default().grow(0.0));
|
||||||
|
if key.is_down() && !wants_input
|
||||||
|
|| ui
|
||||||
|
.add_sized(size, Button::new("⏹"))
|
||||||
|
.on_hover_text(stop_msg)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
process.stop(&self.helper);
|
||||||
|
}
|
||||||
|
ui.add(Separator::default().grow(0.0));
|
||||||
if key.is_up() && !wants_input
|
if key.is_up() && !wants_input
|
||||||
|| ui
|
|| ui
|
||||||
.add_sized(size, Button::new("⟲"))
|
.add_sized(size, Button::new("⟲"))
|
||||||
|
@ -274,29 +288,7 @@ impl crate::app::App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui.add(Separator::default().grow(0.0));
|
|
||||||
if key.is_down() && !wants_input
|
|
||||||
|| ui
|
|
||||||
.add_sized(size, Button::new("⏹"))
|
|
||||||
.on_hover_text(stop_msg)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
process.stop(&self.helper);
|
|
||||||
}
|
|
||||||
ui.add(Separator::default().grow(0.0));
|
|
||||||
ui.add_enabled_ui(false, |ui| {
|
|
||||||
ui.add_sized(size, Button::new("▶"))
|
|
||||||
.on_disabled_hover_text(start_msg)
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
ui.add_enabled_ui(false, |ui| {
|
|
||||||
ui.add_sized(size, Button::new("⟲"))
|
|
||||||
.on_disabled_hover_text(restart_msg);
|
|
||||||
ui.add(Separator::default().grow(0.0));
|
|
||||||
ui.add_sized(size, Button::new("⏹"))
|
|
||||||
.on_disabled_hover_text(stop_msg);
|
|
||||||
ui.add(Separator::default().grow(0.0));
|
|
||||||
});
|
|
||||||
let text_err = self.start_ready(process).err().unwrap_or_default();
|
let text_err = self.start_ready(process).err().unwrap_or_default();
|
||||||
let ui_enabled = text_err.is_empty();
|
let ui_enabled = text_err.is_empty();
|
||||||
ui.add_enabled_ui(ui_enabled, |ui| {
|
ui.add_enabled_ui(ui_enabled, |ui| {
|
||||||
|
@ -354,6 +346,14 @@ impl crate::app::App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.add_enabled_ui(false, |ui| {
|
||||||
|
ui.add_sized(size, Button::new("⏹"))
|
||||||
|
.on_disabled_hover_text(stop_msg);
|
||||||
|
ui.add(Separator::default().grow(0.0));
|
||||||
|
ui.add_sized(size, Button::new("⟲"))
|
||||||
|
.on_disabled_hover_text(restart_msg);
|
||||||
|
ui.add(Separator::default().grow(0.0));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
73
src/app/panels/middle/common/console.rs
Normal file
73
src/app/panels/middle/common/console.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use egui::{Label, TextEdit, TextStyle, Ui};
|
||||||
|
|
||||||
|
use crate::{DARK_GRAY, helper::Process, miscs::height_txt_before_button, regex::num_lines};
|
||||||
|
|
||||||
|
pub fn console(ui: &mut Ui, text: &str) {
|
||||||
|
let nb_lines = num_lines(text);
|
||||||
|
let height = ui.available_height() / 2.8;
|
||||||
|
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
||||||
|
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
||||||
|
egui::ScrollArea::vertical()
|
||||||
|
.stick_to_bottom(true)
|
||||||
|
.max_width(ui.available_width())
|
||||||
|
.max_height(height)
|
||||||
|
.auto_shrink([false; 2])
|
||||||
|
// .show_viewport(ui, |ui, _| {
|
||||||
|
.show_rows(
|
||||||
|
ui,
|
||||||
|
ui.text_style_height(&TextStyle::Small),
|
||||||
|
nb_lines,
|
||||||
|
|ui, row_range| {
|
||||||
|
for i in row_range {
|
||||||
|
if let Some(line) = text.lines().nth(i) {
|
||||||
|
ui.label(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// input args
|
||||||
|
pub fn input_args_field(
|
||||||
|
ui: &mut Ui,
|
||||||
|
buffer: &mut String,
|
||||||
|
process: &Arc<Mutex<Process>>,
|
||||||
|
hint: &str,
|
||||||
|
hover: &str,
|
||||||
|
) {
|
||||||
|
ui.style_mut().spacing.text_edit_width = ui.available_width();
|
||||||
|
let response = ui
|
||||||
|
.add(TextEdit::hint_text(TextEdit::singleline(buffer), hint))
|
||||||
|
.on_hover_text(hover);
|
||||||
|
// 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 = process.lock().unwrap();
|
||||||
|
if process.is_alive() {
|
||||||
|
process.input.push(buffer);
|
||||||
|
} // Push only if alive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command arguments
|
||||||
|
pub fn start_options_field(ui: &mut Ui, arguments: &mut String, hint: &str, hover: &str) {
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height_txt_before_button(ui, &TextStyle::Body)],
|
||||||
|
Label::new("Command arguments:"),
|
||||||
|
);
|
||||||
|
ui.style_mut().spacing.text_edit_width = ui.available_width();
|
||||||
|
ui.add(TextEdit::hint_text(TextEdit::singleline(arguments), hint))
|
||||||
|
.on_hover_text(hover);
|
||||||
|
arguments.truncate(1024);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if !arguments.is_empty() {
|
||||||
|
ui.disable();
|
||||||
|
}
|
||||||
|
}
|
83
src/app/panels/middle/common/header_tab.rs
Normal file
83
src/app/panels/middle/common/header_tab.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
use egui::{Hyperlink, Image, Separator, TextStyle, TextWrapMode, Ui};
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
use crate::SPACE;
|
||||||
|
/// logo first, first hyperlink will be the header, description under.
|
||||||
|
/// will take care of centering widgets if boerder weight is more than 0.
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
|
pub fn header_tab(
|
||||||
|
ui: &mut Ui,
|
||||||
|
logo: Option<Image>,
|
||||||
|
// text, link, hover text
|
||||||
|
links: &[(&str, &str, &str)],
|
||||||
|
subtitle: Option<String>,
|
||||||
|
one_line_center: bool,
|
||||||
|
) {
|
||||||
|
// width - logo and links and separators divided by double the size of logo (can't know width of links).
|
||||||
|
ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
|
||||||
|
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
if one_line_center {
|
||||||
|
let height = 64.0;
|
||||||
|
let nb_links = links.len();
|
||||||
|
let border_weight = ((ui.available_width()
|
||||||
|
- ((height * 4.0 * nb_links as f32) + if logo.is_some() { height * 2.0 } else { 0.0 }))
|
||||||
|
/ (height * 2.0))
|
||||||
|
.max(0.0) as usize;
|
||||||
|
// nb_columns add logo if exist plus number of links with separator for each + number of column for border space
|
||||||
|
let nb_columns = if logo.is_some() { 1 } else { 0 } + (links.len() * 2) + border_weight * 2;
|
||||||
|
ui.columns(nb_columns, |col| {
|
||||||
|
// first column for left border
|
||||||
|
for n in 0..(border_weight) {
|
||||||
|
col[n].vertical_centered(|ui| ui.add_space(0.0));
|
||||||
|
debug!("left side space: {}", n);
|
||||||
|
}
|
||||||
|
// jump first column, stop less 2, because begin at 0 and end with space column.
|
||||||
|
let mut nb_col = border_weight;
|
||||||
|
if let Some(logo) = logo {
|
||||||
|
debug!("logo: {}", nb_col);
|
||||||
|
col[nb_col].vertical_centered(|ui| ui.add_sized([height, height], logo));
|
||||||
|
nb_col += 1;
|
||||||
|
}
|
||||||
|
for link in links {
|
||||||
|
debug!("separator: {}", nb_col);
|
||||||
|
col[nb_col].vertical_centered(|ui| {
|
||||||
|
ui.add_sized(
|
||||||
|
[height / 8.0, height],
|
||||||
|
Separator::default().vertical().spacing(height / 8.0),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
nb_col += 1;
|
||||||
|
|
||||||
|
debug!("link: {}", nb_col);
|
||||||
|
col[nb_col].vertical_centered(|ui| {
|
||||||
|
ui.add_sized(
|
||||||
|
[ui.available_width(), height],
|
||||||
|
Hyperlink::from_label_and_url(link.0, link.1),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
nb_col += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for n in nb_col..(nb_col + border_weight) {
|
||||||
|
debug!("right side border space: {}", n);
|
||||||
|
col[n].vertical_centered(|ui| ui.add_space(0.0));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// top down
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
if let Some(source) = logo {
|
||||||
|
ui.add(source);
|
||||||
|
}
|
||||||
|
for link in links {
|
||||||
|
ui.hyperlink_to(link.0, link.1);
|
||||||
|
}
|
||||||
|
ui.style_mut().override_text_style = Some(TextStyle::Body);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(desc) = subtitle {
|
||||||
|
ui.label(desc);
|
||||||
|
}
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
}
|
330
src/app/panels/middle/common/list_poolnode.rs
Normal file
330
src/app/panels/middle/common/list_poolnode.rs
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
use egui::{Button, ComboBox, RichText, SelectableLabel, Ui};
|
||||||
|
use log::{debug, info};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
LIST_ADD, LIST_CLEAR, LIST_DELETE, LIST_SAVE,
|
||||||
|
disk::{node::Node, pool::Pool, state::SelectedPoolNode},
|
||||||
|
};
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PoolNode {
|
||||||
|
Node(Node),
|
||||||
|
Pool(Pool),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PoolNode {
|
||||||
|
pub fn ip(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
PoolNode::Node(n) => &n.ip,
|
||||||
|
PoolNode::Pool(p) => &p.ip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn port(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
PoolNode::Node(n) => &n.rpc,
|
||||||
|
PoolNode::Pool(p) => &p.port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn custom(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
PoolNode::Node(n) => &n.zmq,
|
||||||
|
PoolNode::Pool(p) => &p.rig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn custom_name(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
PoolNode::Node(_) => "ZMQ",
|
||||||
|
PoolNode::Pool(_) => "rig",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_ip(&mut self, new_ip: String) {
|
||||||
|
match self {
|
||||||
|
PoolNode::Node(n) => n.ip = new_ip,
|
||||||
|
PoolNode::Pool(p) => p.ip = new_ip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_port(&mut self, new_port: String) {
|
||||||
|
match self {
|
||||||
|
PoolNode::Node(n) => n.rpc = new_port,
|
||||||
|
PoolNode::Pool(p) => p.port = new_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_custom(&mut self, new_custom: String) {
|
||||||
|
match self {
|
||||||
|
PoolNode::Node(n) => n.zmq = new_custom,
|
||||||
|
PoolNode::Pool(p) => p.rig = new_custom,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// pub fn from_vec_node(vec_node: Vec<(String, Node)>) -> Vec<(String, Self)> {
|
||||||
|
// vec_node
|
||||||
|
// .into_iter()
|
||||||
|
// .map(|(name, node)| (name, PoolNode::Node(node)))
|
||||||
|
// .collect()
|
||||||
|
// }
|
||||||
|
// pub fn from_vec_pool(vec_node: Vec<(String, Pool)>) -> Vec<(String, Self)> {
|
||||||
|
// vec_node
|
||||||
|
// .into_iter()
|
||||||
|
// .map(|(name, pool)| (name, PoolNode::Pool(pool)))
|
||||||
|
// .collect()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
/// compatible for P2Pool and Xmrig/Proxy
|
||||||
|
/// current is (name, ip, port, zmq/rig)
|
||||||
|
pub fn list_poolnode(
|
||||||
|
ui: &mut Ui,
|
||||||
|
current: &mut (&mut String, &mut String, &mut String, &mut String),
|
||||||
|
selected: &mut SelectedPoolNode,
|
||||||
|
node_vec: &mut Vec<(String, PoolNode)>,
|
||||||
|
incorrect_input: bool,
|
||||||
|
) {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing.y = 0.0;
|
||||||
|
// ui.spacing_mut().button_padding.x = ui.available_width() / 2.0;
|
||||||
|
let width = ui.available_width();
|
||||||
|
// [Manual node selection]
|
||||||
|
// [Ping List]
|
||||||
|
debug!("P2Pool Tab | Rendering [Node List]");
|
||||||
|
// [Menu]
|
||||||
|
menu_list_node(ui, node_vec, width, selected, current);
|
||||||
|
let node_vec_len = node_vec.len();
|
||||||
|
// [Add/Save]
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
add_save_node(
|
||||||
|
ui,
|
||||||
|
selected,
|
||||||
|
node_vec,
|
||||||
|
current,
|
||||||
|
node_vec_len,
|
||||||
|
incorrect_input,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
// [Delete]
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
delete_node(ui, selected, node_vec, current, node_vec_len);
|
||||||
|
});
|
||||||
|
// [Clear]
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
clear_node(ui, current);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// slider H/s
|
||||||
|
|
||||||
|
fn clear_node(ui: &mut Ui, current: &mut (&mut String, &mut String, &mut String, &mut String)) {
|
||||||
|
ui.add_enabled_ui(
|
||||||
|
!current.0.is_empty()
|
||||||
|
|| !current.1.is_empty()
|
||||||
|
|| !current.2.is_empty()
|
||||||
|
|| !current.3.is_empty(),
|
||||||
|
|ui| {
|
||||||
|
if ui
|
||||||
|
.add_sized([ui.available_width(), 0.0], Button::new("Clear"))
|
||||||
|
.on_hover_text(LIST_CLEAR)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
current.0.clear();
|
||||||
|
current.1.clear();
|
||||||
|
current.2.clear();
|
||||||
|
current.3.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fn menu_list_node(
|
||||||
|
ui: &mut Ui,
|
||||||
|
node_vec: &mut [(String, PoolNode)],
|
||||||
|
width: f32,
|
||||||
|
selected: &mut SelectedPoolNode,
|
||||||
|
current: &mut (&mut String, &mut String, &mut String, &mut String),
|
||||||
|
) {
|
||||||
|
let text = RichText::new(format!("{}. {}", selected.index + 1, selected.name));
|
||||||
|
ComboBox::from_id_salt("manual_nodes")
|
||||||
|
.selected_text(text)
|
||||||
|
.width(width)
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for (n, (name, node)) in node_vec.iter().enumerate() {
|
||||||
|
let text = RichText::new(format!(
|
||||||
|
"{}. {}\n IP: {}\n RPC: {}\n {}: {}",
|
||||||
|
n + 1,
|
||||||
|
name,
|
||||||
|
node.ip(),
|
||||||
|
node.port(),
|
||||||
|
node.custom_name(),
|
||||||
|
node.custom()
|
||||||
|
));
|
||||||
|
if ui
|
||||||
|
.add(SelectableLabel::new(selected.name == **name, text))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
selected.index = n;
|
||||||
|
let node = node.clone();
|
||||||
|
selected.name.clone_from(name);
|
||||||
|
selected.ip.clone_from(&node.ip().to_string());
|
||||||
|
selected.rpc.clone_from(&node.port().to_string());
|
||||||
|
selected.zmq_rig.clone_from(&node.custom().to_string());
|
||||||
|
current.0.clone_from(name);
|
||||||
|
*current.1 = node.ip().to_string();
|
||||||
|
*current.2 = node.port().to_string();
|
||||||
|
*current.3 = node.custom().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn add_save_node(
|
||||||
|
ui: &mut Ui,
|
||||||
|
selected: &mut SelectedPoolNode,
|
||||||
|
node_vec: &mut Vec<(String, PoolNode)>,
|
||||||
|
current: &mut (&mut String, &mut String, &mut String, &mut String),
|
||||||
|
node_vec_len: usize,
|
||||||
|
incorrect_input: bool,
|
||||||
|
) {
|
||||||
|
// list should never be empty unless state edited by hand.
|
||||||
|
let is_node = matches!(node_vec[0].1, PoolNode::Node(_));
|
||||||
|
// [Add/Save]
|
||||||
|
let mut exists = false;
|
||||||
|
let mut save_diff = true;
|
||||||
|
let mut existing_index = 0;
|
||||||
|
for (name, node) in node_vec.iter() {
|
||||||
|
if *name == *current.0 {
|
||||||
|
exists = true;
|
||||||
|
if *current.1 == node.ip() && *current.2 == node.port() && *current.3 == node.custom() {
|
||||||
|
save_diff = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
existing_index += 1;
|
||||||
|
}
|
||||||
|
let text = if exists { LIST_SAVE } else { LIST_ADD };
|
||||||
|
let text = format!(
|
||||||
|
"{}\n Currently selected node: {}. {}\n Current amount of {}: {}/1000",
|
||||||
|
text,
|
||||||
|
selected.index + 1,
|
||||||
|
selected.name,
|
||||||
|
if is_node { "nodes" } else { "pools" },
|
||||||
|
node_vec_len
|
||||||
|
);
|
||||||
|
// If the node already exists, show [Save] and mutate the already existing node
|
||||||
|
if exists {
|
||||||
|
ui.add_enabled_ui(!incorrect_input && save_diff, |ui| {
|
||||||
|
if ui
|
||||||
|
.add_sized([ui.available_width(), 0.0], Button::new("Save"))
|
||||||
|
.on_hover_text(text)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
let ip = current.1.clone();
|
||||||
|
let rpc = current.2.clone();
|
||||||
|
// zmq can be rig in case of Pool
|
||||||
|
let zmq = current.3.clone();
|
||||||
|
let poolnode = &mut node_vec[existing_index].1;
|
||||||
|
poolnode.set_ip(ip);
|
||||||
|
poolnode.set_port(rpc);
|
||||||
|
poolnode.set_custom(zmq);
|
||||||
|
info!(
|
||||||
|
"Node | S | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, {}: {}]",
|
||||||
|
existing_index + 1,
|
||||||
|
current.0,
|
||||||
|
current.1,
|
||||||
|
current.2,
|
||||||
|
poolnode.custom_name(),
|
||||||
|
current.3
|
||||||
|
);
|
||||||
|
selected.index = existing_index;
|
||||||
|
selected.ip.clone_from(current.1);
|
||||||
|
selected.rpc.clone_from(current.2);
|
||||||
|
selected.zmq_rig.clone_from(current.3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Else, add to the list
|
||||||
|
} else {
|
||||||
|
ui.add_enabled_ui(!incorrect_input && node_vec_len < 1000, |ui| {
|
||||||
|
if ui
|
||||||
|
.add_sized([ui.available_width(), 0.0], Button::new("Add"))
|
||||||
|
.on_hover_text(text)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
let ip = current.1.clone();
|
||||||
|
let rpc = current.2.clone();
|
||||||
|
// zmq can be rig in case of Pool
|
||||||
|
let zmq = current.3.clone();
|
||||||
|
let poolnode = match node_vec[existing_index].1 {
|
||||||
|
PoolNode::Node(_) => PoolNode::Node(Node { ip, rpc, zmq }),
|
||||||
|
PoolNode::Pool(_) => PoolNode::Pool(Pool {
|
||||||
|
rig: zmq,
|
||||||
|
ip,
|
||||||
|
port: rpc,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Node | A | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, {}: {}]",
|
||||||
|
node_vec_len,
|
||||||
|
current.0,
|
||||||
|
current.1,
|
||||||
|
current.2,
|
||||||
|
poolnode.custom_name(),
|
||||||
|
current.3
|
||||||
|
);
|
||||||
|
node_vec.push((current.0.clone(), poolnode));
|
||||||
|
selected.index = node_vec_len;
|
||||||
|
selected.name.clone_from(current.0);
|
||||||
|
selected.ip.clone_from(current.1);
|
||||||
|
selected.rpc.clone_from(current.2);
|
||||||
|
selected.zmq_rig.clone_from(current.3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_node(
|
||||||
|
ui: &mut Ui,
|
||||||
|
selected: &mut SelectedPoolNode,
|
||||||
|
node_vec: &mut Vec<(String, PoolNode)>,
|
||||||
|
current: &mut (&mut String, &mut String, &mut String, &mut String),
|
||||||
|
node_vec_len: usize,
|
||||||
|
) {
|
||||||
|
ui.add_enabled_ui(node_vec_len > 1, |ui| {
|
||||||
|
let text = format!(
|
||||||
|
"{}\n Currently selected node: {}. {}\n Current amount of nodes: {}/1000",
|
||||||
|
LIST_DELETE,
|
||||||
|
selected.index + 1,
|
||||||
|
selected.name,
|
||||||
|
node_vec_len
|
||||||
|
);
|
||||||
|
if ui
|
||||||
|
.add_sized([ui.available_width(), 0.0], Button::new("Delete"))
|
||||||
|
.on_hover_text(text)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
let new_name;
|
||||||
|
let new_node;
|
||||||
|
match selected.index {
|
||||||
|
0 => {
|
||||||
|
new_name = node_vec[1].0.clone();
|
||||||
|
new_node = node_vec[1].1.clone();
|
||||||
|
node_vec.remove(0);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
node_vec.remove(selected.index);
|
||||||
|
selected.index -= 1;
|
||||||
|
new_name = node_vec[selected.index].0.clone();
|
||||||
|
new_node = node_vec[selected.index].1.clone();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
selected.name.clone_from(&new_name);
|
||||||
|
selected.ip = new_node.ip().to_string();
|
||||||
|
selected.rpc = new_node.port().to_string();
|
||||||
|
selected.zmq_rig = new_node.custom().to_string();
|
||||||
|
*current.0 = new_name;
|
||||||
|
*current.1 = new_node.ip().to_string();
|
||||||
|
*current.2 = new_node.port().to_string();
|
||||||
|
*current.3 = new_node.custom().to_string();
|
||||||
|
info!(
|
||||||
|
"Node | D | [index: {}, name: \"{}\", ip: \"{}\", port: {}, {}: {}]",
|
||||||
|
selected.index,
|
||||||
|
selected.name,
|
||||||
|
selected.ip,
|
||||||
|
selected.rpc,
|
||||||
|
new_node.custom_name(),
|
||||||
|
selected.zmq_rig
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
4
src/app/panels/middle/common/mod.rs
Normal file
4
src/app/panels/middle/common/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
pub mod console;
|
||||||
|
pub mod header_tab;
|
||||||
|
pub mod list_poolnode;
|
||||||
|
pub mod state_edit_field;
|
212
src/app/panels/middle/common/state_edit_field.rs
Normal file
212
src/app/panels/middle/common/state_edit_field.rs
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use egui::{Color32, Label, RichText, Slider, TextEdit};
|
||||||
|
use egui::{TextStyle, Ui};
|
||||||
|
|
||||||
|
use crate::components::gupax::{FileType, FileWindow};
|
||||||
|
use crate::disk::state::Gupax;
|
||||||
|
use crate::miscs::height_txt_before_button;
|
||||||
|
use crate::regex::Regexes;
|
||||||
|
use crate::{
|
||||||
|
GREEN, GUPAX_SELECT, LIGHT_GRAY, NODE_DB_DIR, NODE_DB_PATH_EMPTY, NODE_PATH_OK, RED, SPACE,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn slider_state_field(
|
||||||
|
ui: &mut Ui,
|
||||||
|
description: &str,
|
||||||
|
hover_msg: &str,
|
||||||
|
field: &mut u16,
|
||||||
|
range: RangeInclusive<u16>,
|
||||||
|
) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height_txt_before_button(ui, &TextStyle::Body)],
|
||||||
|
Label::new(description),
|
||||||
|
);
|
||||||
|
// 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
|
||||||
|
+ 2.0)
|
||||||
|
.max(80.0);
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height_txt_before_button(ui, &TextStyle::Body)],
|
||||||
|
Slider::new(field, range),
|
||||||
|
)
|
||||||
|
.on_hover_text(hover_msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StateTextEdit<'a> {
|
||||||
|
description: &'a str,
|
||||||
|
max_ch: u8,
|
||||||
|
help_msg: &'a str,
|
||||||
|
validations: &'a [fn(&str) -> bool],
|
||||||
|
text_edit_width: f32,
|
||||||
|
text_style: TextStyle,
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
impl<'a> StateTextEdit<'a> {
|
||||||
|
pub fn new(ui: &Ui) -> Self {
|
||||||
|
StateTextEdit {
|
||||||
|
description: "",
|
||||||
|
max_ch: 30,
|
||||||
|
help_msg: "",
|
||||||
|
validations: &[],
|
||||||
|
text_edit_width: ui.text_style_height(&TextStyle::Body) * 18.0,
|
||||||
|
text_style: TextStyle::Body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn build(self, ui: &mut Ui, state_field: &mut String) -> bool {
|
||||||
|
let mut valid = false;
|
||||||
|
ui.horizontal_centered(|ui| {
|
||||||
|
let color;
|
||||||
|
let symbol;
|
||||||
|
let mut input_validated = true;
|
||||||
|
let len;
|
||||||
|
let inside_space;
|
||||||
|
for v in self.validations {
|
||||||
|
if !v(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);
|
||||||
|
valid = true;
|
||||||
|
} else {
|
||||||
|
symbol = "❌";
|
||||||
|
color = Color32::from_rgb(230, 50, 50);
|
||||||
|
}
|
||||||
|
match self.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!(
|
||||||
|
"{}[{}{}/{}{}]{}",
|
||||||
|
self.description, inside_space, len, self.max_ch, inside_space, symbol
|
||||||
|
);
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height_txt_before_button(ui, &self.text_style)],
|
||||||
|
Label::new(RichText::new(text).color(color)),
|
||||||
|
);
|
||||||
|
// allocate the size to leave half of the total width free.
|
||||||
|
ui.spacing_mut().text_edit_width = self.text_edit_width;
|
||||||
|
ui.text_edit_singleline(state_field)
|
||||||
|
.on_hover_text(self.help_msg);
|
||||||
|
state_field.truncate(self.max_ch.into());
|
||||||
|
});
|
||||||
|
valid
|
||||||
|
}
|
||||||
|
pub fn description(mut self, description: &'a str) -> Self {
|
||||||
|
self.description = description;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn max_ch(mut self, max_ch: u8) -> Self {
|
||||||
|
self.max_ch = max_ch;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn help_msg(mut self, help_msg: &'a str) -> Self {
|
||||||
|
self.help_msg = help_msg;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn validations(mut self, validations: &'a [fn(&str) -> bool]) -> Self {
|
||||||
|
self.validations = validations;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn text_style(mut self, text_style: TextStyle) -> Self {
|
||||||
|
self.text_style = text_style;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn text_edit_width(mut self, text_edit_width: f32) -> Self {
|
||||||
|
self.text_edit_width = text_edit_width;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn text_edit_width_half_left(mut self, ui: &Ui) -> Self {
|
||||||
|
self.text_edit_width = ui.available_width() / 2.0;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn text_edit_width_same_as_max_ch(mut self, ui: &Ui) -> Self {
|
||||||
|
self.text_edit_width = ui.text_style_height(&self.text_style) * self.max_ch as f32;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// path to choose
|
||||||
|
pub fn path_db_field(ui: &mut Ui, path: &mut String, file_window: &Arc<Mutex<FileWindow>>) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let symbol;
|
||||||
|
let color;
|
||||||
|
let hover;
|
||||||
|
if path.is_empty() {
|
||||||
|
symbol = "➖";
|
||||||
|
color = LIGHT_GRAY;
|
||||||
|
hover = NODE_DB_PATH_EMPTY;
|
||||||
|
} else if !Gupax::path_is_dir(path) {
|
||||||
|
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(
|
||||||
|
[0.0, height_txt_before_button(ui, &TextStyle::Body)],
|
||||||
|
Label::new(RichText::new(text).color(color)),
|
||||||
|
);
|
||||||
|
let window_busy = file_window.lock().unwrap().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.spacing_mut().text_edit_width = ui.available_width();
|
||||||
|
ui.text_edit_singleline(path).on_hover_text(hover);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pub fn monero_address_field(address: &mut String, ui: &mut Ui, hover: &str) {
|
||||||
|
ui.group(|ui| {
|
||||||
|
let text;
|
||||||
|
let color;
|
||||||
|
let len = format!("{:02}", address.len());
|
||||||
|
if address.is_empty() {
|
||||||
|
text = format!("Monero Address [{}/95] ➖", len);
|
||||||
|
color = Color32::LIGHT_GRAY;
|
||||||
|
} else if Regexes::addr_ok(address) {
|
||||||
|
text = format!("Monero Address [{}/95] ✔", len);
|
||||||
|
color = Color32::from_rgb(100, 230, 100);
|
||||||
|
} else {
|
||||||
|
text = format!("Monero Address [{}/95] ❌", len);
|
||||||
|
color = Color32::from_rgb(230, 50, 50);
|
||||||
|
}
|
||||||
|
ui.style_mut().spacing.text_edit_width = ui.available_width();
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.label(RichText::new(text).color(color));
|
||||||
|
// ui.set_max_width(95.0 * 3.0);
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
ui.add(
|
||||||
|
TextEdit::hint_text(TextEdit::singleline(address), "4...")
|
||||||
|
.horizontal_align(egui::Align::Center),
|
||||||
|
)
|
||||||
|
.on_hover_text(hover);
|
||||||
|
address.truncate(95);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -5,10 +5,13 @@ use crate::components::gupax::*;
|
||||||
use crate::components::update::Update;
|
use crate::components::update::Update;
|
||||||
use crate::components::update::check_binary_path;
|
use crate::components::update::check_binary_path;
|
||||||
use crate::disk::state::*;
|
use crate::disk::state::*;
|
||||||
|
use crate::miscs::height_txt_before_button;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
use strum::EnumCount;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
impl Gupax {
|
impl Gupax {
|
||||||
#[inline(always)] // called once
|
#[inline(always)] // called once
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -20,7 +23,6 @@ impl Gupax {
|
||||||
file_window: &Arc<Mutex<FileWindow>>,
|
file_window: &Arc<Mutex<FileWindow>>,
|
||||||
error_state: &mut ErrorState,
|
error_state: &mut ErrorState,
|
||||||
restart: &Arc<Mutex<Restart>>,
|
restart: &Arc<Mutex<Restart>>,
|
||||||
size: Vec2,
|
|
||||||
_frame: &mut eframe::Frame,
|
_frame: &mut eframe::Frame,
|
||||||
_ctx: &egui::Context,
|
_ctx: &egui::Context,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
|
@ -28,33 +30,30 @@ impl Gupax {
|
||||||
) {
|
) {
|
||||||
// Update button + Progress bar
|
// Update button + Progress bar
|
||||||
debug!("Gupaxx Tab | Rendering [Update] button + progress bar");
|
debug!("Gupaxx Tab | Rendering [Update] button + progress bar");
|
||||||
|
let height_font = ui.text_style_height(&TextStyle::Body);
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
|
ui.style_mut().spacing.item_spacing = [height_font, height_font].into();
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let button = if self.simple {
|
|
||||||
size.y / 5.0
|
|
||||||
} else {
|
|
||||||
size.y / 15.0
|
|
||||||
};
|
|
||||||
let height = if self.simple {
|
|
||||||
size.y / 5.0
|
|
||||||
} else {
|
|
||||||
size.y / 10.0
|
|
||||||
};
|
|
||||||
let width = size.x - SPACE;
|
|
||||||
let updating = *update.lock().unwrap().updating.lock().unwrap();
|
let updating = *update.lock().unwrap().updating.lock().unwrap();
|
||||||
ui.vertical(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(height_font);
|
||||||
|
ui.style_mut().spacing.button_padding = ui.style().spacing.button_padding * 3.0;
|
||||||
// If [Gupax] is being built for a Linux distro,
|
// If [Gupax] is being built for a Linux distro,
|
||||||
// disable built-in updating completely.
|
// disable built-in updating completely.
|
||||||
#[cfg(feature = "distro")]
|
#[cfg(feature = "distro")]
|
||||||
ui.disable();
|
ui.disable();
|
||||||
#[cfg(feature = "distro")]
|
#[cfg(feature = "distro")]
|
||||||
ui.add_sized([width, button], Button::new("Updates are disabled"))
|
// ui.add_sized([width, button], Button::new("Updates are disabled"))
|
||||||
|
// .on_disabled_hover_text(DISTRO_NO_UPDATE);
|
||||||
|
ui.button("Updates are disabled")
|
||||||
.on_disabled_hover_text(DISTRO_NO_UPDATE);
|
.on_disabled_hover_text(DISTRO_NO_UPDATE);
|
||||||
#[cfg(not(feature = "distro"))]
|
#[cfg(not(feature = "distro"))]
|
||||||
ui.add_enabled_ui(!updating && *restart.lock().unwrap() == Restart::No, |ui| {
|
ui.add_enabled_ui(!updating && *restart.lock().unwrap() == Restart::No, |ui| {
|
||||||
#[cfg(not(feature = "distro"))]
|
#[cfg(not(feature = "distro"))]
|
||||||
|
// if ui
|
||||||
|
// .add_sized([width, button], Button::new("Check for updates"))
|
||||||
if ui
|
if ui
|
||||||
.add_sized([width, button], Button::new("Check for updates"))
|
.button("Check for updates")
|
||||||
.on_hover_text(GUPAX_UPDATE)
|
.on_hover_text(GUPAX_UPDATE)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -68,8 +67,6 @@ impl Gupax {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.add_enabled_ui(updating, |ui| {
|
ui.add_enabled_ui(updating, |ui| {
|
||||||
let prog = *update.lock().unwrap().prog.lock().unwrap();
|
let prog = *update.lock().unwrap().prog.lock().unwrap();
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
|
@ -78,249 +75,61 @@ impl Gupax {
|
||||||
prog,
|
prog,
|
||||||
"%"
|
"%"
|
||||||
);
|
);
|
||||||
ui.add_sized([width, height * 1.4], Label::new(RichText::new(msg)));
|
ui.label(msg);
|
||||||
let height = height / 2.0;
|
|
||||||
let size = vec2(width, height);
|
|
||||||
if updating {
|
if updating {
|
||||||
ui.add_sized(size, Spinner::new().size(height));
|
ui.spinner();
|
||||||
} else {
|
} else {
|
||||||
ui.add_sized(size, Label::new("..."));
|
ui.label("...");
|
||||||
}
|
}
|
||||||
ui.add_sized(
|
ui.add(ProgressBar::new(
|
||||||
size,
|
|
||||||
ProgressBar::new(
|
|
||||||
update.lock().unwrap().prog.lock().unwrap().round() / 100.0,
|
update.lock().unwrap().prog.lock().unwrap().round() / 100.0,
|
||||||
),
|
));
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("Gupaxx Tab | Rendering bool buttons");
|
// debug!("Gupaxx Tab | Rendering bool buttons");
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
egui::ScrollArea::horizontal().show(ui, |ui| {
|
ui.vertical_centered(|ui| {
|
||||||
let width = (size.x - SPACE * 17.0) / 8.0;
|
ui.add(Label::new(
|
||||||
let height = if self.simple {
|
RichText::new("Default Behaviour")
|
||||||
size.y / 10.0
|
.underline()
|
||||||
} else {
|
.color(LIGHT_GRAY),
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
|
ui.separator();
|
||||||
|
self.horizontal_flex_auto_start(ui, AutoStart::ALL);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if self.simple {
|
if self.simple {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Gupaxx Tab | Rendering P2Pool/XMRig path selection");
|
debug!("Gupaxx Tab | Rendering Node/P2Pool/XMRig/XMRig-Proxy path selection");
|
||||||
// P2Pool/XMRig binary path selection
|
|
||||||
// need to clone bool so file_window is not locked across a thread
|
// need to clone bool so file_window is not locked across a thread
|
||||||
let window_busy = file_window.lock().unwrap().thread.to_owned();
|
let window_busy = file_window.lock().unwrap().thread.to_owned();
|
||||||
let height = size.y / 28.0;
|
|
||||||
let text_edit = (ui.available_width() / 10.0) - SPACE;
|
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.add_sized(
|
ui.push_id(2, |ui| {
|
||||||
[ui.available_width(), height / 2.0],
|
ui.vertical_centered(|ui| {
|
||||||
Label::new(
|
ui.add(Label::new(
|
||||||
RichText::new("Node/P2Pool/XMRig/XMRig-Proxy PATHs")
|
RichText::new("Node/P2Pool/XMRig/XMRig-Proxy PATHs")
|
||||||
.underline()
|
.underline()
|
||||||
.color(LIGHT_GRAY),
|
.color(LIGHT_GRAY),
|
||||||
),
|
))
|
||||||
)
|
|
||||||
.on_hover_text("Gupaxx is online");
|
.on_hover_text("Gupaxx is online");
|
||||||
|
});
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.horizontal(|ui| {
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
if self.node_path.is_empty() {
|
ui.vertical(|ui| {
|
||||||
ui.add_sized(
|
BundledProcess::iter().for_each(|name| {
|
||||||
[text_edit, height],
|
path_binary(
|
||||||
Label::new(RichText::new("Node Binary Path ➖").color(LIGHT_GRAY)),
|
self.path_binary(&name),
|
||||||
|
name.process_name(),
|
||||||
|
ui,
|
||||||
|
window_busy,
|
||||||
|
file_window,
|
||||||
)
|
)
|
||||||
.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 !check_binary_path(&self.node_path, ProcessName::Node) {
|
|
||||||
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(!window_busy, |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(
|
|
||||||
[text_edit, height],
|
|
||||||
Label::new(RichText::new("P2Pool Binary Path ➖").color(LIGHT_GRAY)),
|
|
||||||
)
|
|
||||||
.on_hover_text(P2POOL_PATH_EMPTY);
|
|
||||||
} else if !Self::path_is_file(&self.p2pool_path) {
|
|
||||||
ui.add_sized(
|
|
||||||
[text_edit, height],
|
|
||||||
Label::new(RichText::new("P2Pool Binary Path ❌").color(RED)),
|
|
||||||
)
|
|
||||||
.on_hover_text(P2POOL_PATH_NOT_FILE);
|
|
||||||
} else if !check_binary_path(&self.p2pool_path, ProcessName::P2pool) {
|
|
||||||
ui.add_sized(
|
|
||||||
[text_edit, height],
|
|
||||||
Label::new(RichText::new("P2Pool Binary Path ❌").color(RED)),
|
|
||||||
)
|
|
||||||
.on_hover_text(P2POOL_PATH_NOT_VALID);
|
|
||||||
} else {
|
|
||||||
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.add_enabled_ui(!window_busy, |ui| {
|
|
||||||
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
|
|
||||||
Self::spawn_file_window_thread(file_window, FileType::P2pool);
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[ui.available_width(), height],
|
|
||||||
TextEdit::singleline(&mut self.p2pool_path),
|
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_PATH_P2POOL);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
if self.xmrig_path.is_empty() {
|
|
||||||
ui.add_sized(
|
|
||||||
[text_edit, height],
|
|
||||||
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)),
|
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_PATH_NOT_FILE);
|
|
||||||
} else if !check_binary_path(&self.xmrig_path, ProcessName::Xmrig) {
|
|
||||||
ui.add_sized(
|
|
||||||
[text_edit, height],
|
|
||||||
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)),
|
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_PATH_OK);
|
|
||||||
}
|
|
||||||
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
|
|
||||||
ui.add_enabled_ui(!window_busy, |ui| {
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
if self.xmrig_proxy_path.is_empty() {
|
|
||||||
ui.add_sized(
|
|
||||||
[text_edit, height],
|
|
||||||
Label::new(
|
|
||||||
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)),
|
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_PROXY_PATH_NOT_FILE);
|
|
||||||
} else if !crate::components::update::check_binary_path(
|
|
||||||
&self.xmrig_proxy_path,
|
|
||||||
ProcessName::XmrigProxy,
|
|
||||||
) {
|
|
||||||
ui.add_sized(
|
|
||||||
[text_edit, height],
|
|
||||||
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)),
|
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_PROXY_PATH_OK);
|
|
||||||
}
|
|
||||||
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
|
|
||||||
ui.add_enabled_ui(!window_busy, |ui| {
|
|
||||||
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
|
|
||||||
Self::spawn_file_window_thread(file_window, FileType::XmrigProxy);
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[ui.available_width(), height],
|
|
||||||
TextEdit::singleline(&mut self.xmrig_proxy_path),
|
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_PATH_XMRIG_PROXY);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
let mut guard = file_window.lock().unwrap();
|
let mut guard = file_window.lock().unwrap();
|
||||||
|
@ -341,101 +150,60 @@ impl Gupax {
|
||||||
guard.picked_node = false;
|
guard.picked_node = false;
|
||||||
}
|
}
|
||||||
drop(guard);
|
drop(guard);
|
||||||
|
});
|
||||||
let height = ui.available_height() / 6.0;
|
|
||||||
|
|
||||||
// Saved [Tab]
|
// Saved [Tab]
|
||||||
debug!("Gupaxx Tab | Rendering [Tab] selector");
|
debug!("Gupaxx Tab | Rendering [Tab] selector");
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let width = (size.x / 7.0) - (SPACE * 1.93);
|
ui.vertical_centered(|ui| {
|
||||||
let size = vec2(width, height);
|
ui.add(Label::new(
|
||||||
ui.add_sized(
|
RichText::new("Default Tab").underline().color(LIGHT_GRAY),
|
||||||
[ui.available_width(), height / 2.0],
|
))
|
||||||
Label::new(RichText::new("Default Tab").underline().color(LIGHT_GRAY)),
|
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_TAB);
|
.on_hover_text(GUPAX_TAB);
|
||||||
|
});
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
ui.push_id(1, |ui| {
|
||||||
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui
|
let width = (ui.available_width() / Tab::COUNT as f32)
|
||||||
.add_sized(size, SelectableLabel::new(self.tab == Tab::About, "About"))
|
- (ui.spacing().button_padding.y * 2.0
|
||||||
.on_hover_text(GUPAX_TAB_ABOUT)
|
+ ui.spacing().item_spacing.x)
|
||||||
.clicked()
|
- SPACE;
|
||||||
{
|
Tab::iter().enumerate().for_each(|(count, tab)| {
|
||||||
self.tab = Tab::About;
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.add_sized(
|
||||||
size,
|
[width, height_txt_before_button(ui, &TextStyle::Button)],
|
||||||
SelectableLabel::new(self.tab == Tab::Status, "Status"),
|
SelectableLabel::new(self.tab == tab, tab.to_string()),
|
||||||
)
|
)
|
||||||
.on_hover_text(GUPAX_TAB_STATUS)
|
.on_hover_text(tab.msg_default_tab())
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.tab = Tab::Status;
|
self.tab = tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if count + 1 != Tab::COUNT {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
|
||||||
.add_sized(size, SelectableLabel::new(self.tab == Tab::Gupax, "Gupaxx"))
|
|
||||||
.on_hover_text(GUPAX_TAB_GUPAX)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
SelectableLabel::new(self.tab == Tab::P2pool, "P2Pool"),
|
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_TAB_P2POOL)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.tab = Tab::P2pool;
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
if ui
|
|
||||||
.add_sized(size, SelectableLabel::new(self.tab == Tab::Xmrig, "XMRig"))
|
|
||||||
.on_hover_text(GUPAX_TAB_XMRIG)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.tab = Tab::Xmrig;
|
|
||||||
}
|
|
||||||
if ui
|
|
||||||
.add_sized(size, SelectableLabel::new(self.tab == Tab::Xvb, "XvB"))
|
|
||||||
.on_hover_text(GUPAX_TAB_XVB)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.tab = Tab::Xvb;
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Gupax App resolution sliders
|
// Gupax App resolution sliders
|
||||||
debug!("Gupaxx Tab | Rendering resolution sliders");
|
debug!("Gupaxx Tab | Rendering resolution sliders");
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.add_sized(
|
ui.vertical_centered(|ui| {
|
||||||
[ui.available_width(), height / 2.0],
|
ui.add(Label::new(
|
||||||
Label::new(
|
RichText::new("Width/Height/Scaling Adjustment")
|
||||||
RichText::new("Width/Height Adjust")
|
|
||||||
.underline()
|
.underline()
|
||||||
.color(LIGHT_GRAY),
|
.color(LIGHT_GRAY),
|
||||||
),
|
))
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_ADJUST);
|
.on_hover_text(GUPAX_ADJUST);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let width = size.x / 10.0;
|
|
||||||
ui.spacing_mut().icon_width = width / 25.0;
|
|
||||||
ui.spacing_mut().slider_width = width * 7.6;
|
|
||||||
match self.ratio {
|
match self.ratio {
|
||||||
Ratio::None => (),
|
Ratio::None => (),
|
||||||
Ratio::Width => {
|
Ratio::Width => {
|
||||||
|
@ -449,54 +217,41 @@ impl Gupax {
|
||||||
self.selected_width = width as u16;
|
self.selected_width = width as u16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let height = height / 3.5;
|
// let height = height / 3.5;
|
||||||
let size = vec2(width, height);
|
// let size = vec2(width, height);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add_enabled_ui(self.ratio != Ratio::Height, |ui| {
|
ui.add_enabled_ui(self.ratio != Ratio::Height, |ui| {
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
" Width [{}-{}]:",
|
" Width [{}-{}]:",
|
||||||
APP_MIN_WIDTH as u16, APP_MAX_WIDTH as u16
|
APP_MIN_WIDTH as u16, APP_MAX_WIDTH as u16
|
||||||
)),
|
));
|
||||||
);
|
ui.add(Slider::new(
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Slider::new(
|
|
||||||
&mut self.selected_width,
|
&mut self.selected_width,
|
||||||
APP_MIN_WIDTH as u16..=APP_MAX_WIDTH as u16,
|
APP_MIN_WIDTH as u16..=APP_MAX_WIDTH as u16,
|
||||||
),
|
))
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_WIDTH);
|
.on_hover_text(GUPAX_WIDTH);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add_enabled_ui(self.ratio != Ratio::Width, |ui| {
|
ui.add_enabled_ui(self.ratio != Ratio::Width, |ui| {
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
" Height [{}-{}]:",
|
||||||
Label::new(format!(
|
|
||||||
"Height [{}-{}]:",
|
|
||||||
APP_MIN_HEIGHT as u16, APP_MAX_HEIGHT as u16
|
APP_MIN_HEIGHT as u16, APP_MAX_HEIGHT as u16
|
||||||
)),
|
));
|
||||||
);
|
ui.add(Slider::new(
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Slider::new(
|
|
||||||
&mut self.selected_height,
|
&mut self.selected_height,
|
||||||
APP_MIN_HEIGHT as u16..=APP_MAX_HEIGHT as u16,
|
APP_MIN_HEIGHT as u16..=APP_MAX_HEIGHT as u16,
|
||||||
),
|
))
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_HEIGHT);
|
.on_hover_text(GUPAX_HEIGHT);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add_sized(
|
ui.label(format!(" Scaling [{APP_MIN_SCALE}..{APP_MAX_SCALE}]:"));
|
||||||
size,
|
ui.add(
|
||||||
Label::new(format!("Scaling [{APP_MIN_SCALE}..{APP_MAX_SCALE}]:")),
|
Slider::new(
|
||||||
);
|
&mut self.selected_scale,
|
||||||
ui.add_sized(
|
APP_MIN_SCALE..=APP_MAX_SCALE,
|
||||||
size,
|
)
|
||||||
Slider::new(&mut self.selected_scale, APP_MIN_SCALE..=APP_MAX_SCALE)
|
|
||||||
.step_by(0.1),
|
.step_by(0.1),
|
||||||
)
|
)
|
||||||
.on_hover_text(GUPAX_SCALE);
|
.on_hover_text(GUPAX_SCALE);
|
||||||
|
@ -505,15 +260,11 @@ impl Gupax {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Button);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Button);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
// Width/Height locks
|
// Width/Height locks
|
||||||
ui.horizontal(|ui| {
|
ui.vertical(|ui| {
|
||||||
use Ratio::*;
|
use Ratio::*;
|
||||||
let width = (size.x / 4.0) - (SPACE * 1.5);
|
ui.horizontal(|ui| {
|
||||||
let size = vec2(width, height);
|
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.selectable_label(self.ratio == Width, "Lock to width")
|
||||||
size,
|
|
||||||
SelectableLabel::new(self.ratio == Width, "Lock to width"),
|
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_LOCK_WIDTH)
|
.on_hover_text(GUPAX_LOCK_WIDTH)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -521,10 +272,7 @@ impl Gupax {
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.selectable_label(self.ratio == Height, "Lock to height")
|
||||||
size,
|
|
||||||
SelectableLabel::new(self.ratio == Height, "Lock to height"),
|
|
||||||
)
|
|
||||||
.on_hover_text(GUPAX_LOCK_HEIGHT)
|
.on_hover_text(GUPAX_LOCK_HEIGHT)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -532,25 +280,141 @@ impl Gupax {
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
if ui
|
||||||
.add_sized(size, SelectableLabel::new(self.ratio == None, "No lock"))
|
.selectable_label(self.ratio == None, "No lock")
|
||||||
.on_hover_text(GUPAX_NO_LOCK)
|
.on_hover_text(GUPAX_NO_LOCK)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.ratio = None;
|
self.ratio = None;
|
||||||
}
|
}
|
||||||
if ui
|
ui.separator();
|
||||||
.add_sized(size, Button::new("Set"))
|
if ui.button("Set").on_hover_text(GUPAX_SET).clicked() {
|
||||||
.on_hover_text(GUPAX_SET)
|
let size = Vec2::new(
|
||||||
.clicked()
|
self.selected_width as f32,
|
||||||
{
|
self.selected_height as f32,
|
||||||
let size =
|
);
|
||||||
Vec2::new(self.selected_width as f32, self.selected_height as f32);
|
ui.ctx().send_viewport_cmd(
|
||||||
ui.ctx()
|
egui::viewport::ViewportCommand::InnerSize(size),
|
||||||
.send_viewport_cmd(egui::viewport::ViewportCommand::InnerSize(size));
|
);
|
||||||
*must_resize = true;
|
*must_resize = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/// widget: AutoStart variant and selectable label (true) or checkbox (false)
|
||||||
|
pub fn horizontal_flex_auto_start(&mut self, ui: &mut Ui, auto_starts: &[AutoStart]) {
|
||||||
|
let text_style = TextStyle::Button;
|
||||||
|
// let height = ui.style().text_styles.get(&text_style).unwrap().size;
|
||||||
|
ui.style_mut().override_text_style = Some(text_style);
|
||||||
|
// width = (width - / number of tab) - (space between widget * 2.0 + space of separator / 2.0)
|
||||||
|
// ui.style_mut().spacing.item_spacing.x = 4.0;
|
||||||
|
let spacing = 2.0;
|
||||||
|
// ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| {
|
||||||
|
// ui.horizontal(|ui| {
|
||||||
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
|
ui.with_layout(egui::Layout::left_to_right(egui::Align::Min), |ui| {
|
||||||
|
let width = (((ui.available_width()) / auto_starts.len() as f32)
|
||||||
|
- ((ui.style().spacing.item_spacing.x * 2.0) + (spacing / 2.0)))
|
||||||
|
.max(0.0);
|
||||||
|
// TODO: calculate minimum width needed, if ui.available width is less, show items on two lines, then on 3 etc..
|
||||||
|
// checkbox padding + item spacing + text + separator
|
||||||
|
let size = [width, 0.0];
|
||||||
|
let len = auto_starts.iter().len();
|
||||||
|
for (count, auto) in auto_starts.iter().enumerate() {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let mut is_checked = self.auto.is_enabled(auto);
|
||||||
|
let widget = Checkbox::new(&mut is_checked, auto.to_string());
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add_sized(size, widget)
|
||||||
|
.on_hover_text(auto.help_msg())
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.auto.enable(auto, is_checked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// add a space to prevent selectable button to be at the same line as the end of the top bar. Make it the same spacing as separators.
|
||||||
|
ui.add_space(spacing * 4.0);
|
||||||
|
});
|
||||||
|
if count + 1 != len {
|
||||||
|
ui.add(Separator::default().spacing(spacing).vertical());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn path_binary(
|
||||||
|
path: &mut String,
|
||||||
|
name: ProcessName,
|
||||||
|
ui: &mut Ui,
|
||||||
|
window_busy: bool,
|
||||||
|
file_window: &Arc<Mutex<FileWindow>>,
|
||||||
|
) {
|
||||||
|
// align correctly even with different length of name by adapting the space just after.
|
||||||
|
let flex_space = " ".repeat(
|
||||||
|
ProcessName::iter()
|
||||||
|
.enumerate()
|
||||||
|
.max_by(|(_, a), (_, b)| {
|
||||||
|
a.to_string()
|
||||||
|
.len()
|
||||||
|
.partial_cmp(&b.to_string().len())
|
||||||
|
.expect("ProcessName should have values")
|
||||||
|
})
|
||||||
|
.expect("Iterator cant' be empty")
|
||||||
|
.1
|
||||||
|
.to_string()
|
||||||
|
.len()
|
||||||
|
- name.to_string().len()
|
||||||
|
+ 1,
|
||||||
|
);
|
||||||
|
let msg = format!(" {name}{flex_space}Binary Path");
|
||||||
|
// need to precise the height of text or there will be an misalignment with the button if it's bigger than the text.
|
||||||
|
let height =
|
||||||
|
(ui.style().spacing.button_padding.y * 2.0) + ui.text_style_height(&TextStyle::Body);
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if path.is_empty() {
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height],
|
||||||
|
Label::new(RichText::new(msg + " ➖").color(LIGHT_GRAY)),
|
||||||
|
)
|
||||||
|
.on_hover_text(name.msg_binary_path_empty());
|
||||||
|
} else if !Gupax::path_is_file(path) {
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height],
|
||||||
|
Label::new(RichText::new(msg + " ❌").color(RED)),
|
||||||
|
)
|
||||||
|
.on_hover_text(name.msg_binary_path_not_file());
|
||||||
|
} else if !check_binary_path(path, name) {
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height],
|
||||||
|
Label::new(RichText::new(msg + " ❌").color(RED)),
|
||||||
|
)
|
||||||
|
.on_hover_text(name.msg_binary_path_invalid());
|
||||||
|
} else {
|
||||||
|
ui.add_sized(
|
||||||
|
[0.0, height],
|
||||||
|
Label::new(RichText::new(msg + " ✔").color(GREEN)),
|
||||||
|
)
|
||||||
|
.on_hover_text(name.msg_binary_path_ok());
|
||||||
|
}
|
||||||
|
ui.spacing_mut().text_edit_width = (ui.available_width() - SPACE).max(0.0);
|
||||||
|
ui.add_enabled_ui(!window_busy, |ui| {
|
||||||
|
if ui.button("Open").on_hover_text(GUPAX_SELECT).clicked() {
|
||||||
|
Gupax::spawn_file_window_thread(
|
||||||
|
file_window,
|
||||||
|
name.file_type()
|
||||||
|
.expect("XvB process should not be called in a function related to path"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ui.text_edit_singleline(path)
|
||||||
|
.on_hover_text(name.msg_path_edit());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use crate::app::Tab;
|
use crate::app::Tab;
|
||||||
use crate::app::eframe_impl::ProcessStatesGui;
|
use crate::app::eframe_impl::ProcessStatesGui;
|
||||||
use crate::app::keys::KeyPressed;
|
use crate::app::keys::KeyPressed;
|
||||||
|
use crate::components::gupax::FileWindow;
|
||||||
use crate::helper::ProcessName;
|
use crate::helper::ProcessName;
|
||||||
|
use crate::regex::REGEXES;
|
||||||
use crate::utils::constants::*;
|
use crate::utils::constants::*;
|
||||||
|
use common::state_edit_field::StateTextEdit;
|
||||||
use egui::*;
|
use egui::*;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
mod about;
|
mod about;
|
||||||
|
pub mod common;
|
||||||
mod gupax;
|
mod gupax;
|
||||||
mod node;
|
mod node;
|
||||||
mod p2pool;
|
mod p2pool;
|
||||||
|
@ -47,7 +51,6 @@ impl crate::app::App {
|
||||||
self.max_threads,
|
self.max_threads,
|
||||||
&self.gupax_p2pool_api,
|
&self.gupax_p2pool_api,
|
||||||
&self.benchmarks,
|
&self.benchmarks,
|
||||||
self.size,
|
|
||||||
ctx,
|
ctx,
|
||||||
ui,
|
ui,
|
||||||
);
|
);
|
||||||
|
@ -62,7 +65,6 @@ impl crate::app::App {
|
||||||
&self.file_window,
|
&self.file_window,
|
||||||
&mut self.error_state,
|
&mut self.error_state,
|
||||||
&self.restart,
|
&self.restart,
|
||||||
self.size,
|
|
||||||
frame,
|
frame,
|
||||||
ctx,
|
ctx,
|
||||||
ui,
|
ui,
|
||||||
|
@ -76,7 +78,6 @@ impl crate::app::App {
|
||||||
&self.node,
|
&self.node,
|
||||||
&self.node_api,
|
&self.node_api,
|
||||||
&mut self.node_stdin,
|
&mut self.node_stdin,
|
||||||
self.size,
|
|
||||||
&self.file_window,
|
&self.file_window,
|
||||||
ui,
|
ui,
|
||||||
);
|
);
|
||||||
|
@ -91,7 +92,6 @@ impl crate::app::App {
|
||||||
&self.p2pool,
|
&self.p2pool,
|
||||||
&self.p2pool_api,
|
&self.p2pool_api,
|
||||||
&mut self.p2pool_stdin,
|
&mut self.p2pool_stdin,
|
||||||
self.size,
|
|
||||||
ctx,
|
ctx,
|
||||||
ui,
|
ui,
|
||||||
);
|
);
|
||||||
|
@ -104,7 +104,6 @@ impl crate::app::App {
|
||||||
&self.xmrig,
|
&self.xmrig,
|
||||||
&self.xmrig_api,
|
&self.xmrig_api,
|
||||||
&mut self.xmrig_stdin,
|
&mut self.xmrig_stdin,
|
||||||
self.size,
|
|
||||||
ctx,
|
ctx,
|
||||||
ui,
|
ui,
|
||||||
);
|
);
|
||||||
|
@ -117,7 +116,6 @@ impl crate::app::App {
|
||||||
&mut self.pool_vec,
|
&mut self.pool_vec,
|
||||||
&self.xmrig_proxy_api,
|
&self.xmrig_proxy_api,
|
||||||
&mut self.xmrig_proxy_stdin,
|
&mut self.xmrig_proxy_stdin,
|
||||||
self.size,
|
|
||||||
ui,
|
ui,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +123,6 @@ impl crate::app::App {
|
||||||
debug!("App | Entering [XvB] Tab");
|
debug!("App | Entering [XvB] Tab");
|
||||||
crate::disk::state::Xvb::show(
|
crate::disk::state::Xvb::show(
|
||||||
&mut self.state.xvb,
|
&mut self.state.xvb,
|
||||||
self.size,
|
|
||||||
&self.state.p2pool.address,
|
&self.state.p2pool.address,
|
||||||
ctx,
|
ctx,
|
||||||
ui,
|
ui,
|
||||||
|
@ -139,3 +136,49 @@ impl crate::app::App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common widgets that will appears on multiple panels.
|
||||||
|
|
||||||
|
// header
|
||||||
|
|
||||||
|
// console
|
||||||
|
|
||||||
|
// sliders in/out peers/log
|
||||||
|
|
||||||
|
// menu node
|
||||||
|
|
||||||
|
// premade state edit field
|
||||||
|
// return boolean to know if the field input is validated.
|
||||||
|
fn rpc_port_field(field: &mut String, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" RPC PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(NODE_API_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, field)
|
||||||
|
}
|
||||||
|
fn zmq_port_field(field: &mut String, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" ZMQ PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(NODE_ZMQ_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, field)
|
||||||
|
}
|
||||||
|
fn rpc_bind_field(field: &mut String, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description("RPC BIND IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(NODE_API_BIND)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x), |x| REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zmq_bind_field(field: &mut String, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description("API BIND IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(NODE_ZMQ_BIND)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x), |x| REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, field)
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
|
use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
|
||||||
|
use crate::app::panels::middle::common::state_edit_field::{path_db_field, slider_state_field};
|
||||||
|
use crate::app::panels::middle::{rpc_bind_field, rpc_port_field, zmq_bind_field, zmq_port_field};
|
||||||
use crate::{
|
use crate::{
|
||||||
GUPAX_SELECT, NODE_API_BIND, NODE_API_PORT, NODE_ARGUMENTS, NODE_DB_DIR, NODE_DB_PATH_EMPTY,
|
NODE_ARGUMENTS, NODE_DNS_BLOCKLIST, NODE_DNS_CHECKPOINT, NODE_INPUT, NODE_PRUNNING, NODE_URL,
|
||||||
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, TextStyle, Ui, Vec2};
|
use egui::{Label, TextStyle};
|
||||||
use regex::Regex;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::components::gupax::{FileType, FileWindow};
|
use crate::components::gupax::FileWindow;
|
||||||
use crate::disk::state::{Gupax, Node};
|
use crate::disk::state::Node;
|
||||||
use crate::helper::Process;
|
use crate::helper::Process;
|
||||||
use crate::helper::node::PubNodeApi;
|
use crate::helper::node::PubNodeApi;
|
||||||
use crate::regex::{REGEXES, num_lines};
|
use crate::{P2POOL_IN, P2POOL_LOG, P2POOL_OUT, SPACE};
|
||||||
use crate::utils::constants::DARK_GRAY;
|
|
||||||
use crate::{GREEN, LIGHT_GRAY, P2POOL_IN, P2POOL_LOG, P2POOL_OUT, RED, SPACE};
|
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
#[inline(always)] // called once
|
#[inline(always)] // called once
|
||||||
|
@ -24,102 +22,47 @@ impl Node {
|
||||||
process: &Arc<Mutex<Process>>,
|
process: &Arc<Mutex<Process>>,
|
||||||
api: &Arc<Mutex<PubNodeApi>>,
|
api: &Arc<Mutex<PubNodeApi>>,
|
||||||
buffer: &mut String,
|
buffer: &mut String,
|
||||||
size: Vec2,
|
|
||||||
file_window: &Arc<Mutex<FileWindow>>,
|
file_window: &Arc<Mutex<FileWindow>>,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
) {
|
) {
|
||||||
let width = size.x;
|
ui.style_mut().override_text_style = Some(TextStyle::Body);
|
||||||
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.vertical_centered(|ui| {
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
||||||
ui.hyperlink_to("Monerod", NODE_URL);
|
ui.hyperlink_to("Monerod", NODE_URL);
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Body);
|
ui.style_mut().override_text_style = None;
|
||||||
ui.add(Label::new("C++ Monero Node"));
|
ui.add(Label::new("C++ Monero Node"));
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
});
|
});
|
||||||
// console output for log
|
// console output for log
|
||||||
debug!("Node Tab | Rendering [Console]");
|
debug!("Node Tab | Rendering [Console]");
|
||||||
ui.group(|ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
let text = &api.lock().unwrap().output;
|
let text = &api.lock().unwrap().output;
|
||||||
let nb_lines = num_lines(text);
|
ui.group(|ui| {
|
||||||
let height = size.y / 2.8;
|
console(ui, text);
|
||||||
let width = (size.x - (space_h / 2.0)).max(0.0);
|
if !self.simple {
|
||||||
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
ui.separator();
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
input_args_field(
|
||||||
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,
|
||||||
ui.text_style_height(&TextStyle::Small),
|
buffer,
|
||||||
nb_lines,
|
process,
|
||||||
|ui, row_range| {
|
r#"Commands: help, status, set_log <level>, diff"#,
|
||||||
for i in row_range {
|
NODE_INPUT,
|
||||||
if let Some(line) = text.lines().nth(i) {
|
|
||||||
ui.label(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
//---------------------------------------------------------------------------------------------------- [Advanced] Console
|
//---------------------------------------------------------------------------------------------------- [Advanced] Console
|
||||||
if !self.simple {
|
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 = process.lock().unwrap(); // Lock
|
|
||||||
if process.is_alive() {
|
|
||||||
process.input.push(buffer);
|
|
||||||
} // Push only if alive
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Arguments
|
//---------------------------------------------------------------------------------------------------- Arguments
|
||||||
debug!("Node Tab | Rendering [Arguments]");
|
debug!("Node Tab | Rendering [Arguments]");
|
||||||
ui.group(|ui| {
|
start_options_field(
|
||||||
ui.horizontal(|ui| {
|
ui,
|
||||||
ui.add_sized(
|
&mut self.arguments,
|
||||||
[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"#,
|
r#"--zmq-pub tcp://127.0.0.1:18081"#,
|
||||||
),
|
NODE_ARGUMENTS,
|
||||||
)
|
);
|
||||||
.on_hover_text(NODE_ARGUMENTS);
|
|
||||||
self.arguments.truncate(1024);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
if !self.arguments.is_empty() {
|
|
||||||
ui.disable();
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------------------------------- Prunned checkbox
|
//---------------------------------------------------------------------------------------------------- Prunned checkbox
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
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;
|
|
||||||
debug!("Node Tab | Rendering DNS and Prunning buttons");
|
debug!("Node Tab | Rendering DNS and Prunning buttons");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
|
@ -134,24 +77,21 @@ impl Node {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
// idea
|
// // idea
|
||||||
// need to warn the user if local firewall is blocking port
|
// // need to warn the user if local firewall is blocking port
|
||||||
// need to warn the user if NAT is blocking port
|
// // need to warn the user if NAT is blocking port
|
||||||
// need to show local ip address
|
// // need to show local ip address
|
||||||
// need to show public ip
|
// // 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.horizontal(|ui| {
|
||||||
|
egui::ScrollArea::horizontal().show(ui, |ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
rpc_bind_field(self, ui, txt_description_width, text_height, width);
|
rpc_bind_field(&mut self.api_ip, ui);
|
||||||
rpc_port_field(self, ui, txt_description_width, text_height, width);
|
rpc_port_field(&mut self.api_port, ui);
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
zmq_bind_field(self, ui, txt_description_width, text_height, width);
|
zmq_bind_field(&mut self.zmq_ip, ui);
|
||||||
zmq_port_field(self, ui, txt_description_width, text_height, width);
|
zmq_port_field(&mut self.zmq_port, ui);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -159,251 +99,47 @@ impl Node {
|
||||||
debug!("Node Tab | Rendering sliders elements");
|
debug!("Node Tab | Rendering sliders elements");
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
ui.add_space(SPACE);
|
||||||
ui.horizontal(|ui| {
|
slider_state_field(
|
||||||
// ui.label("Out peers [10-450]:");
|
ui,
|
||||||
ui.add_sized(
|
"Out peers [2-450]:",
|
||||||
[txt_description_width, text_height],
|
P2POOL_OUT,
|
||||||
Label::new("Out peers [2-450]:"),
|
&mut self.out_peers,
|
||||||
|
2..=450,
|
||||||
);
|
);
|
||||||
// not sure what's the right calculation to make
|
ui.add_space(SPACE);
|
||||||
ui.style_mut().spacing.slider_width = (ui.available_width()
|
slider_state_field(
|
||||||
- ui.spacing().item_spacing.x * 4.0
|
ui,
|
||||||
- ui.spacing().scroll.bar_width
|
"In peers [2-450]:",
|
||||||
- (SPACE * 2.0))
|
P2POOL_IN,
|
||||||
.max(0.0);
|
&mut self.in_peers,
|
||||||
ui.add(Slider::new(&mut self.out_peers, 2..=450))
|
2..=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 [2-450]:"),
|
|
||||||
);
|
);
|
||||||
ui.style_mut().spacing.slider_width = (ui.available_width()
|
ui.add_space(SPACE);
|
||||||
- ui.spacing().item_spacing.x * 4.0
|
slider_state_field(
|
||||||
- ui.spacing().scroll.bar_width
|
ui,
|
||||||
- (SPACE * 2.0))
|
"Log level [ 0-4 ]:",
|
||||||
.max(0.0);
|
P2POOL_LOG,
|
||||||
ui.add(Slider::new(&mut self.in_peers, 2..=450))
|
&mut self.log_level,
|
||||||
.on_hover_text(P2POOL_IN);
|
0..=6,
|
||||||
});
|
|
||||||
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.add_space(SPACE);
|
||||||
- ui.spacing().item_spacing.x * 4.0
|
|
||||||
- ui.spacing().scroll.bar_width
|
|
||||||
- (SPACE * 2.0))
|
|
||||||
.max(0.0);
|
|
||||||
ui.add(Slider::new(&mut self.log_level, 0..=4))
|
|
||||||
.on_hover_text(P2POOL_LOG);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
//---------------------------------------------------------------------------------------------------- DB path
|
//---------------------------------------------------------------------------------------------------- DB path
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
path_db_field(self, ui, txt_description_width, text_height, file_window);
|
path_db_field(ui, &mut self.path_db, file_window);
|
||||||
});
|
|
||||||
ui.add_space(space_h);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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![®EXES.ipv4, ®EXES.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![®EXES.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![®EXES.ipv4, ®EXES.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![®EXES.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).max(0.0);
|
|
||||||
let window_busy = file_window.lock().unwrap().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 = file_window.lock().unwrap();
|
let mut guard = file_window.lock().unwrap();
|
||||||
if guard.picked_nodedb {
|
if guard.picked_nodedb {
|
||||||
state.path_db.clone_from(&guard.nodedb_path);
|
self.path_db.clone_from(&guard.nodedb_path);
|
||||||
guard.picked_nodedb = false;
|
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)
|
|
||||||
.max(0.0);
|
|
||||||
ui.text_edit_singleline(state_field).on_hover_text(help_msg);
|
|
||||||
state_field.truncate(max_ch.into());
|
|
||||||
});
|
});
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,238 +1,43 @@
|
||||||
use crate::disk::node::Node;
|
use crate::app::panels::middle::common::list_poolnode::{PoolNode, list_poolnode};
|
||||||
|
use crate::app::panels::middle::common::state_edit_field::{StateTextEdit, slider_state_field};
|
||||||
|
use crate::miscs::height_txt_before_button;
|
||||||
use crate::{disk::state::P2pool, utils::regex::REGEXES};
|
use crate::{disk::state::P2pool, utils::regex::REGEXES};
|
||||||
use egui::Checkbox;
|
|
||||||
use egui::Slider;
|
|
||||||
use egui::{Button, Vec2};
|
|
||||||
|
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use egui::{Color32, ComboBox, Label, RichText, SelectableLabel, Ui};
|
use egui::{Checkbox, SelectableLabel, Ui};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
impl P2pool {
|
impl P2pool {
|
||||||
pub(super) fn advanced(
|
pub(super) fn advanced(&mut self, ui: &mut Ui, node_vec: &mut Vec<(String, PoolNode)>) {
|
||||||
&mut self,
|
// let height = size.y / 16.0;
|
||||||
ui: &mut Ui,
|
// let space_h = size.y / 128.0;
|
||||||
size: Vec2,
|
|
||||||
text_edit: f32,
|
|
||||||
node_vec: &mut Vec<(String, Node)>,
|
|
||||||
) {
|
|
||||||
let height = size.y / 16.0;
|
|
||||||
let space_h = size.y / 128.0;
|
|
||||||
debug!("P2Pool Tab | Rendering [Node List] elements");
|
debug!("P2Pool Tab | Rendering [Node List] elements");
|
||||||
let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
|
let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
|
||||||
// [Monero node IP/RPC/ZMQ]
|
// [Monero node IP/RPC/ZMQ]
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let width = size.x/10.0;
|
// let width = size.x/10.0;
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.spacing_mut().text_edit_width = width*3.32;
|
if !self.name_field(ui) {
|
||||||
ui.horizontal(|ui| {
|
incorrect_input = false;
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.name.len());
|
|
||||||
if self.name.is_empty() {
|
|
||||||
text = format!("Name [ {}/30 ]➖", len);
|
|
||||||
color = Color32::LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.name.is_match(&self.name) {
|
|
||||||
text = format!("Name [ {}/30 ]✔", len);
|
|
||||||
color = Color32::from_rgb(100, 230, 100);
|
|
||||||
} else {
|
|
||||||
text = format!("Name [ {}/30 ]❌", len);
|
|
||||||
color = Color32::from_rgb(230, 50, 50);
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.ip_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.name).on_hover_text(P2POOL_NAME);
|
incorrect_input = false;
|
||||||
self.name.truncate(30);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:03}", self.ip.len());
|
|
||||||
if self.ip.is_empty() {
|
|
||||||
text = format!(" IP [{}/255]➖", len);
|
|
||||||
color = Color32::LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if self.ip == "localhost" || REGEXES.ipv4.is_match(&self.ip) || REGEXES.domain.is_match(&self.ip) {
|
|
||||||
text = format!(" IP [{}/255]✔", len);
|
|
||||||
color = Color32::from_rgb(100, 230, 100);
|
|
||||||
} else {
|
|
||||||
text = format!(" IP [{}/255]❌", len);
|
|
||||||
color = Color32::from_rgb(230, 50, 50);
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.rpc_port_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.ip).on_hover_text(P2POOL_NODE_IP);
|
incorrect_input = false;
|
||||||
self.ip.truncate(255);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = self.rpc.len();
|
|
||||||
if self.rpc.is_empty() {
|
|
||||||
text = format!(" RPC [ {}/5 ]➖", len);
|
|
||||||
color = Color32::LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.port.is_match(&self.rpc) {
|
|
||||||
text = format!(" RPC [ {}/5 ]✔", len);
|
|
||||||
color = Color32::from_rgb(100, 230, 100);
|
|
||||||
} else {
|
|
||||||
text = format!(" RPC [ {}/5 ]❌", len);
|
|
||||||
color = Color32::from_rgb(230, 50, 50);
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
|
||||||
ui.text_edit_singleline(&mut self.rpc).on_hover_text(P2POOL_RPC_PORT);
|
|
||||||
self.rpc.truncate(5);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = self.zmq.len();
|
|
||||||
if self.zmq.is_empty() {
|
|
||||||
text = format!(" ZMQ [ {}/5 ]➖", len);
|
|
||||||
color = Color32::LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.port.is_match(&self.zmq) {
|
|
||||||
text = format!(" ZMQ [ {}/5 ]✔", len);
|
|
||||||
color = Color32::from_rgb(100, 230, 100);
|
|
||||||
} else {
|
|
||||||
text = format!(" ZMQ [ {}/5 ]❌", len);
|
|
||||||
color = Color32::from_rgb(230, 50, 50);
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
|
||||||
ui.text_edit_singleline(&mut self.zmq).on_hover_text(P2POOL_ZMQ_PORT);
|
|
||||||
self.zmq.truncate(5);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
let width = ui.available_width();
|
|
||||||
ui.add_space(1.0);
|
|
||||||
// [Manual node selection]
|
|
||||||
ui.spacing_mut().slider_width = width - 8.0;
|
|
||||||
ui.spacing_mut().icon_width = width / 25.0;
|
|
||||||
// [Ping List]
|
|
||||||
debug!("P2Pool Tab | Rendering [Node List]");
|
|
||||||
let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
|
|
||||||
ComboBox::from_id_salt("manual_nodes").selected_text(text).width(width).show_ui(ui, |ui| {
|
|
||||||
for (n, (name, node)) in node_vec.iter().enumerate() {
|
|
||||||
let text = RichText::new(format!("{}. {}\n IP: {}\n RPC: {}\n ZMQ: {}", n+1, name, node.ip, node.rpc, node.zmq));
|
|
||||||
if ui.add(SelectableLabel::new(self.selected_name == *name, text)).clicked() {
|
|
||||||
self.selected_index = n;
|
|
||||||
let node = node.clone();
|
|
||||||
self.selected_name.clone_from(name);
|
|
||||||
self.selected_ip.clone_from(&node.ip);
|
|
||||||
self.selected_rpc.clone_from(&node.rpc);
|
|
||||||
self.selected_zmq.clone_from(&node.zmq);
|
|
||||||
self.name.clone_from(name);
|
|
||||||
self.ip = node.ip;
|
|
||||||
self.rpc = node.rpc;
|
|
||||||
self.zmq = node.zmq;
|
|
||||||
}
|
}
|
||||||
|
if !self.zmq_port_field(ui) {
|
||||||
|
incorrect_input = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// [Add/Save]
|
list_poolnode(
|
||||||
let node_vec_len = node_vec.len();
|
ui,
|
||||||
let mut exists = false;
|
&mut (&mut self.name, &mut self.ip, &mut self.rpc, &mut self.zmq),
|
||||||
let mut save_diff = true;
|
&mut self.selected_node,
|
||||||
let mut existing_index = 0;
|
node_vec,
|
||||||
for (name, node) in node_vec.iter() {
|
incorrect_input,
|
||||||
if *name == self.name {
|
);
|
||||||
exists = true;
|
|
||||||
if self.ip == node.ip && self.rpc == node.rpc && self.zmq == node.zmq {
|
|
||||||
save_diff = false;
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
existing_index += 1;
|
|
||||||
}
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text = if exists { LIST_SAVE } else { LIST_ADD };
|
|
||||||
let text = format!("{}\n Currently selected node: {}. {}\n Current amount of nodes: {}/1000", text, self.selected_index+1, self.selected_name, node_vec_len);
|
|
||||||
// If the node already exists, show [Save] and mutate the already existing node
|
|
||||||
if exists {
|
|
||||||
ui.add_enabled_ui(!incorrect_input && save_diff, |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
|
|
||||||
let node = Node {
|
|
||||||
ip: self.ip.clone(),
|
|
||||||
rpc: self.rpc.clone(),
|
|
||||||
zmq: self.zmq.clone(),
|
|
||||||
};
|
|
||||||
node_vec[existing_index].1 = node;
|
|
||||||
self.selected_index = existing_index;
|
|
||||||
self.selected_ip.clone_from(&self.ip);
|
|
||||||
self.selected_rpc.clone_from(&self.rpc);
|
|
||||||
self.selected_zmq.clone_from(&self.zmq);
|
|
||||||
info!("Node | S | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", existing_index+1, self.name, self.ip, self.rpc, self.zmq);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Else, add to the list
|
|
||||||
} else {
|
|
||||||
ui.add_enabled_ui(!incorrect_input && node_vec_len < 1000, |ui| {
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Add")).on_hover_text(text).clicked() {
|
|
||||||
let node = Node {
|
|
||||||
ip: self.ip.clone(),
|
|
||||||
rpc: self.rpc.clone(),
|
|
||||||
zmq: self.zmq.clone(),
|
|
||||||
};
|
|
||||||
node_vec.push((self.name.clone(), node));
|
|
||||||
self.selected_index = node_vec_len;
|
|
||||||
self.selected_name.clone_from(&self.name);
|
|
||||||
self.selected_ip.clone_from(&self.ip);
|
|
||||||
self.selected_rpc.clone_from(&self.rpc);
|
|
||||||
self.selected_zmq.clone_from(&self.zmq);
|
|
||||||
info!("Node | A | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", node_vec_len, self.name, self.ip, self.rpc, self.zmq);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// [Delete]
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(node_vec_len > 1, |ui|{
|
|
||||||
let text = format!("{}\n Currently selected node: {}. {}\n Current amount of nodes: {}/1000", LIST_DELETE, self.selected_index+1, self.selected_name, node_vec_len);
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Delete")).on_hover_text(text).clicked() {
|
|
||||||
let new_name;
|
|
||||||
let new_node;
|
|
||||||
match self.selected_index {
|
|
||||||
0 => {
|
|
||||||
new_name = node_vec[1].0.clone();
|
|
||||||
new_node = node_vec[1].1.clone();
|
|
||||||
node_vec.remove(0);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
node_vec.remove(self.selected_index);
|
|
||||||
self.selected_index -= 1;
|
|
||||||
new_name = node_vec[self.selected_index].0.clone();
|
|
||||||
new_node = node_vec[self.selected_index].1.clone();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.selected_name.clone_from(&new_name);
|
|
||||||
self.selected_ip.clone_from(&new_node.ip);
|
|
||||||
self.selected_rpc.clone_from(&new_node.rpc);
|
|
||||||
self.selected_zmq.clone_from(&new_node.zmq);
|
|
||||||
self.name = new_name;
|
|
||||||
self.ip = new_node.ip;
|
|
||||||
self.rpc = new_node.rpc;
|
|
||||||
self.zmq = new_node.zmq;
|
|
||||||
info!("Node | D | [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", self.selected_index, self.selected_name, self.selected_ip, self.selected_rpc, self.selected_zmq);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(!self.name.is_empty() || !self.ip.is_empty() || !self.rpc.is_empty() || !self.zmq.is_empty(), |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Clear")).on_hover_text(LIST_CLEAR).clicked() {
|
|
||||||
self.name.clear();
|
|
||||||
self.ip.clear();
|
|
||||||
self.rpc.clear();
|
|
||||||
self.zmq.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// ui.add_space(space_h);
|
// ui.add_space(space_h);
|
||||||
|
@ -240,12 +45,15 @@ impl P2pool {
|
||||||
debug!("P2Pool Tab | Rendering [Main/Mini/Peers/Log] elements");
|
debug!("P2Pool Tab | Rendering [Main/Mini/Peers/Log] elements");
|
||||||
// [Main/Mini]
|
// [Main/Mini]
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let height = height / 4.0;
|
// let height = height / 4.0;
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
let height = height_txt_before_button(ui, &egui::TextStyle::Button) * 1.9;
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (size.x / 4.0) - SPACE;
|
let width = (ui.available_width() / 4.0) - SPACE;
|
||||||
let height = height + space_h;
|
|
||||||
if ui
|
if ui
|
||||||
|
// if ui.add_sized(, )
|
||||||
|
// .selectable_label(!self.mini, "P2Pool Main")
|
||||||
.add_sized(
|
.add_sized(
|
||||||
[width, height],
|
[width, height],
|
||||||
SelectableLabel::new(!self.mini, "P2Pool Main"),
|
SelectableLabel::new(!self.mini, "P2Pool Main"),
|
||||||
|
@ -256,6 +64,8 @@ impl P2pool {
|
||||||
self.mini = false;
|
self.mini = false;
|
||||||
}
|
}
|
||||||
if ui
|
if ui
|
||||||
|
// .selectable_label(!self.mini, "P2Pool Mini")
|
||||||
|
// if ui
|
||||||
.add_sized(
|
.add_sized(
|
||||||
[width, height],
|
[width, height],
|
||||||
SelectableLabel::new(self.mini, "P2Pool Mini"),
|
SelectableLabel::new(self.mini, "P2Pool Mini"),
|
||||||
|
@ -265,49 +75,80 @@ impl P2pool {
|
||||||
{
|
{
|
||||||
self.mini = true;
|
self.mini = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
debug!("P2Pool Tab | Rendering Backup host button");
|
||||||
|
ui.group(|ui| {
|
||||||
|
// [Backup host]
|
||||||
|
ui.add_sized(
|
||||||
|
[(ui.available_width() / 2.0) - (SPACE * 2.0), height],
|
||||||
|
Checkbox::new(&mut self.backup_host, "Backup host"),
|
||||||
|
)
|
||||||
|
// ui.checkbox(&mut self.backup_host, "Backup host")
|
||||||
|
.on_hover_text(P2POOL_BACKUP_HOST_ADVANCED);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
// [Out/In Peers] + [Log Level]
|
// [Out/In Peers] + [Log Level]
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let text = (ui.available_width() / 10.0) - SPACE;
|
ui.add_space(SPACE);
|
||||||
let width = (text * 8.0) - SPACE;
|
slider_state_field(
|
||||||
let height = height / 3.0;
|
ui,
|
||||||
ui.style_mut().spacing.slider_width = width / 1.1;
|
"Out peers [2-450]:",
|
||||||
ui.style_mut().spacing.interact_size.y = height;
|
P2POOL_OUT,
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
|
&mut self.out_peers,
|
||||||
ui.horizontal(|ui| {
|
2..=450,
|
||||||
ui.add_sized([text, height], Label::new("Out peers [10-450]:"));
|
);
|
||||||
ui.add_sized([width, height], Slider::new(&mut self.out_peers, 10..=450))
|
ui.add_space(SPACE);
|
||||||
.on_hover_text(P2POOL_OUT);
|
slider_state_field(
|
||||||
ui.add_space(ui.available_width() - 4.0);
|
ui,
|
||||||
});
|
"In peers [2-450]:",
|
||||||
ui.horizontal(|ui| {
|
P2POOL_IN,
|
||||||
ui.add_sized([text, height], Label::new(" In peers [10-450]:"));
|
&mut self.in_peers,
|
||||||
ui.add_sized([width, height], Slider::new(&mut self.in_peers, 10..=450))
|
2..=450,
|
||||||
.on_hover_text(P2POOL_IN);
|
);
|
||||||
});
|
ui.add_space(SPACE);
|
||||||
ui.horizontal(|ui| {
|
slider_state_field(
|
||||||
ui.add_sized([text, height], Label::new(" Log level [0-6]:"));
|
ui,
|
||||||
ui.add_sized([width, height], Slider::new(&mut self.log_level, 0..=6))
|
"Log level [ 0-6 ]:",
|
||||||
.on_hover_text(P2POOL_LOG);
|
P2POOL_LOG,
|
||||||
});
|
&mut self.log_level,
|
||||||
|
0..=6,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
debug!("P2Pool Tab | Rendering Backup host button");
|
fn name_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
ui.group(|ui| {
|
StateTextEdit::new(ui)
|
||||||
let width = size.x - SPACE;
|
.description(" Name ")
|
||||||
let height = ui.available_height();
|
.max_ch(30)
|
||||||
ui.style_mut().spacing.icon_width = height;
|
.help_msg(P2POOL_NAME)
|
||||||
ui.style_mut().spacing.icon_width_inner = height * 0.9;
|
.validations(&[|x| REGEXES.name.is_match(x)])
|
||||||
// [Backup host]
|
.build(ui, &mut self.name)
|
||||||
ui.add_sized(
|
}
|
||||||
[width, height],
|
fn rpc_port_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
Checkbox::new(&mut self.backup_host, "Backup host"),
|
StateTextEdit::new(ui)
|
||||||
)
|
.description(" RPC PORT ")
|
||||||
.on_hover_text(P2POOL_BACKUP_HOST_ADVANCED);
|
.max_ch(5)
|
||||||
});
|
.help_msg(P2POOL_RPC_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, &mut self.rpc)
|
||||||
|
}
|
||||||
|
fn zmq_port_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" ZMQ PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(P2POOL_ZMQ_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, &mut self.zmq)
|
||||||
|
}
|
||||||
|
fn ip_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(P2POOL_NODE_IP)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x), |x| REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, &mut self.ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::disk::node::Node;
|
use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
|
||||||
use crate::disk::state::{P2pool, State};
|
use crate::disk::state::{P2pool, State};
|
||||||
use crate::helper::p2pool::PubP2poolApi;
|
use crate::helper::p2pool::PubP2poolApi;
|
||||||
use crate::regex::num_lines;
|
|
||||||
// Gupax - GUI Uniting P2Pool And XMRig
|
// Gupax - GUI Uniting P2Pool And XMRig
|
||||||
//
|
//
|
||||||
// Copyright (c) 2022-2023 hinto-janai
|
// Copyright (c) 2022-2023 hinto-janai
|
||||||
|
@ -18,12 +17,13 @@ use crate::regex::num_lines;
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
use crate::{components::node::*, constants::*, helper::*, utils::regex::Regexes};
|
use crate::{components::node::*, constants::*, helper::*};
|
||||||
use egui::{Color32, Label, RichText, TextEdit, TextStyle, Vec2, vec2};
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use super::common::list_poolnode::PoolNode;
|
||||||
|
|
||||||
mod advanced;
|
mod advanced;
|
||||||
mod simple;
|
mod simple;
|
||||||
|
|
||||||
|
@ -32,143 +32,51 @@ impl P2pool {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn show(
|
pub fn show(
|
||||||
&mut self,
|
&mut self,
|
||||||
node_vec: &mut Vec<(String, Node)>,
|
node_vec: &mut Vec<(String, PoolNode)>,
|
||||||
_og: &Arc<Mutex<State>>,
|
_og: &Arc<Mutex<State>>,
|
||||||
ping: &Arc<Mutex<Ping>>,
|
ping: &Arc<Mutex<Ping>>,
|
||||||
process: &Arc<Mutex<Process>>,
|
process: &Arc<Mutex<Process>>,
|
||||||
api: &Arc<Mutex<PubP2poolApi>>,
|
api: &Arc<Mutex<PubP2poolApi>>,
|
||||||
buffer: &mut String,
|
buffer: &mut String,
|
||||||
size: Vec2,
|
|
||||||
_ctx: &egui::Context,
|
_ctx: &egui::Context,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
) {
|
) {
|
||||||
let height = size.y;
|
|
||||||
let width = size.x;
|
|
||||||
let text_edit = size.y / 25.0;
|
|
||||||
//---------------------------------------------------------------------------------------------------- [Simple] Console
|
//---------------------------------------------------------------------------------------------------- [Simple] Console
|
||||||
// debug!("P2Pool Tab | Rendering [Console]");
|
// debug!("P2Pool Tab | Rendering [Console]");
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.group(|ui| {
|
|
||||||
let text = &api.lock().unwrap().output;
|
let text = &api.lock().unwrap().output;
|
||||||
let nb_lines = num_lines(text);
|
ui.group(|ui| {
|
||||||
let (height, width) = if self.simple {
|
console(ui, text);
|
||||||
((size.y * 0.38) - SPACE, size.x - SPACE)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
if size.y < 600.0 {
|
|
||||||
size.y * 0.22 - SPACE
|
|
||||||
} else {
|
|
||||||
size.y * 0.36 - SPACE
|
|
||||||
},
|
|
||||||
width - SPACE,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
|
|
||||||
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::Small),
|
|
||||||
nb_lines,
|
|
||||||
|ui, row_range| {
|
|
||||||
for i in row_range {
|
|
||||||
if let Some(line) = text.lines().nth(i) {
|
|
||||||
ui.label(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if !self.simple {
|
if !self.simple {
|
||||||
//---------------------------------------------------------------------------------------------------- [Advanced] Console
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
let response = ui
|
input_args_field(
|
||||||
.add_sized(
|
ui,
|
||||||
[width, text_edit],
|
buffer,
|
||||||
TextEdit::hint_text(
|
process,
|
||||||
TextEdit::singleline(buffer),
|
|
||||||
r#"Type a command (e.g "help" or "status") and press Enter"#,
|
r#"Type a command (e.g "help" or "status") and press Enter"#,
|
||||||
),
|
P2POOL_INPUT,
|
||||||
)
|
|
||||||
.on_hover_text(P2POOL_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 = process.lock().unwrap(); // Lock
|
|
||||||
if process.is_alive() {
|
|
||||||
process.input.push(buffer);
|
|
||||||
} // Push only if alive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Args
|
|
||||||
if !self.simple {
|
|
||||||
debug!("P2Pool Tab | Rendering [Arguments]");
|
|
||||||
ui.group(|ui| {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let width = (width / 10.0) - SPACE;
|
|
||||||
ui.add_sized([width, text_edit], Label::new("Command arguments:"));
|
|
||||||
ui.add_sized(
|
|
||||||
[ui.available_width(), text_edit],
|
|
||||||
TextEdit::hint_text(
|
|
||||||
TextEdit::singleline(&mut self.arguments),
|
|
||||||
r#"--wallet <...> --host <...>"#,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.on_hover_text(P2POOL_ARGUMENTS);
|
|
||||||
self.arguments.truncate(1024);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
if !self.arguments.is_empty() {
|
|
||||||
ui.disable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Address
|
|
||||||
debug!("P2Pool Tab | Rendering [Address]");
|
|
||||||
ui.group(|ui| {
|
|
||||||
let width = width - SPACE;
|
|
||||||
ui.spacing_mut().text_edit_width = (width) - (SPACE * 3.0);
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.address.len());
|
|
||||||
if self.address.is_empty() {
|
|
||||||
text = format!("Monero Address [{}/95] ➖", len);
|
|
||||||
color = Color32::LIGHT_GRAY;
|
|
||||||
} else if Regexes::addr_ok(&self.address) {
|
|
||||||
text = format!("Monero Address [{}/95] ✔", len);
|
|
||||||
color = Color32::from_rgb(100, 230, 100);
|
|
||||||
} else {
|
|
||||||
text = format!("Monero Address [{}/95] ❌", len);
|
|
||||||
color = Color32::from_rgb(230, 50, 50);
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Label::new(RichText::new(text).color(color)),
|
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
}
|
||||||
[width, text_edit],
|
|
||||||
TextEdit::hint_text(TextEdit::singleline(&mut self.address), "4..."),
|
|
||||||
)
|
|
||||||
.on_hover_text(P2POOL_ADDRESS);
|
|
||||||
self.address.truncate(95);
|
|
||||||
});
|
});
|
||||||
|
if !self.simple {
|
||||||
|
start_options_field(
|
||||||
|
ui,
|
||||||
|
&mut self.arguments,
|
||||||
|
r#"--wallet <...> --host <...>"#,
|
||||||
|
P2POOL_ARGUMENTS,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
debug!("P2Pool Tab | Rendering [Address]");
|
||||||
|
crate::app::panels::middle::common::state_edit_field::monero_address_field(
|
||||||
|
&mut self.address,
|
||||||
|
ui,
|
||||||
|
P2POOL_ADDRESS,
|
||||||
|
);
|
||||||
|
|
||||||
// let height = ui.available_height();
|
|
||||||
let size = vec2(width, height);
|
|
||||||
if self.simple {
|
if self.simple {
|
||||||
//---------------------------------------------------------------------------------------------------- Simple
|
self.simple(ui, ping);
|
||||||
self.simple(ui, size, ping);
|
|
||||||
//---------------------------------------------------------------------------------------------------- Advanced
|
|
||||||
} else {
|
} else {
|
||||||
self.advanced(ui, size, text_edit, node_vec);
|
self.advanced(ui, node_vec);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,32 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use crate::app::panels::middle::Hyperlink;
|
|
||||||
use crate::app::panels::middle::ProgressBar;
|
use crate::app::panels::middle::ProgressBar;
|
||||||
use crate::app::panels::middle::Spinner;
|
|
||||||
use crate::components::node::Ping;
|
use crate::components::node::Ping;
|
||||||
use crate::components::node::RemoteNode;
|
use crate::components::node::RemoteNode;
|
||||||
use crate::components::node::format_ip_location;
|
use crate::components::node::format_ip_location;
|
||||||
use crate::components::node::format_ms;
|
use crate::components::node::format_ms;
|
||||||
use crate::disk::state::P2pool;
|
use crate::disk::state::P2pool;
|
||||||
|
use crate::miscs::height_txt_before_button;
|
||||||
use egui::Button;
|
use egui::Button;
|
||||||
use egui::Checkbox;
|
use egui::Checkbox;
|
||||||
use egui::Vec2;
|
use egui::ScrollArea;
|
||||||
|
use egui::TextStyle;
|
||||||
|
use egui::TextWrapMode;
|
||||||
use egui::vec2;
|
use egui::vec2;
|
||||||
|
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use egui::{Color32, ComboBox, Label, RichText, Ui};
|
use egui::{Color32, ComboBox, RichText, Ui};
|
||||||
use log::*;
|
use log::*;
|
||||||
impl P2pool {
|
impl P2pool {
|
||||||
pub(super) fn simple(&mut self, ui: &mut Ui, size: Vec2, ping: &Arc<Mutex<Ping>>) {
|
pub(super) fn simple(&mut self, ui: &mut Ui, ping: &Arc<Mutex<Ping>>) {
|
||||||
// [Node]
|
|
||||||
let height = size.y / 13.0;
|
|
||||||
let space_h = size.y / 96.0;
|
|
||||||
ui.spacing_mut().slider_width = (size.x - 16.0).max(0.0);
|
|
||||||
ui.spacing_mut().icon_width = size.x / 25.0;
|
|
||||||
|
|
||||||
// [Auto-select] if we haven't already.
|
|
||||||
// Using [Arc<Mutex<Ping>>] as an intermediary here
|
|
||||||
// saves me the hassle of wrapping [state: State] completely
|
|
||||||
// and [.lock().unwrap()]ing it everywhere.
|
|
||||||
// Two atomic bools = enough to represent this data
|
|
||||||
|
|
||||||
// local or remote
|
|
||||||
// button bool
|
|
||||||
ui.vertical_centered(|ui|{
|
ui.vertical_centered(|ui|{
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
ui.checkbox(&mut self.local_node, "Use a local node").on_hover_text("If checked (recommended), p2pool will automatically use the local node.\nCheck the Node tab to start a local node.\nIf unchecked, p2pool will attempt to use a remote node.");
|
ui.checkbox(&mut self.local_node, "Use a local node").on_hover_text("If checked (recommended), p2pool will automatically use the local node.\nCheck the Node tab to start a local node.\nIf unchecked, p2pool will attempt to use a remote node.");
|
||||||
});
|
});
|
||||||
ui.add_space(space_h * 2.0);
|
ui.add_space(SPACE * 2.0);
|
||||||
|
|
||||||
// if checked, use only local node
|
// if checked, use only local node
|
||||||
// if unchecked, show remote nodes.
|
// if unchecked, show remote nodes.
|
||||||
|
|
||||||
// disable remote if local is checked.
|
// disable remote if local is checked.
|
||||||
let visible = !self.local_node;
|
let visible = !self.local_node;
|
||||||
debug!("P2Pool Tab | Running [auto-select] check");
|
debug!("P2Pool Tab | Running [auto-select] check");
|
||||||
|
@ -54,7 +39,6 @@ impl P2pool {
|
||||||
}
|
}
|
||||||
drop(ping);
|
drop(ping);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_enabled_ui(visible, |ui| {
|
ui.add_enabled_ui(visible, |ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
@ -74,9 +58,11 @@ impl P2pool {
|
||||||
debug!("P2Pool Tab | Rendering [ComboBox] of Remote Nodes");
|
debug!("P2Pool Tab | Rendering [ComboBox] of Remote Nodes");
|
||||||
let ip_location = format_ip_location(&self.node, false);
|
let ip_location = format_ip_location(&self.node, false);
|
||||||
let text = RichText::new(format!(" ⏺ {}ms | {}", ms, ip_location)).color(color);
|
let text = RichText::new(format!(" ⏺ {}ms | {}", ms, ip_location)).color(color);
|
||||||
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Small);
|
||||||
|
ui.spacing_mut().item_spacing.y = 0.0;
|
||||||
ComboBox::from_id_salt("remote_nodes")
|
ComboBox::from_id_salt("remote_nodes")
|
||||||
.selected_text(text)
|
.selected_text(text)
|
||||||
.width(size.x)
|
.width(ui.available_width())
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
for data in ping.lock().unwrap().nodes.iter() {
|
for data in ping.lock().unwrap().nodes.iter() {
|
||||||
let ms = format_ms(data.ms);
|
let ms = format_ms(data.ms);
|
||||||
|
@ -87,16 +73,24 @@ impl P2pool {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
ui.add_space(SPACE);
|
||||||
ui.add_space(space_h);
|
|
||||||
|
|
||||||
debug!("P2Pool Tab | Rendering [Select fastest ... Ping] buttons");
|
debug!("P2Pool Tab | Rendering [Select fastest ... Ping] buttons");
|
||||||
|
ScrollArea::horizontal()
|
||||||
|
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
|
||||||
|
.id_salt("horizontal")
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Button);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = ((size.x / 5.0) - 6.0).max(0.0);
|
ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
|
||||||
let size = vec2(width, height);
|
// ui.columns_const(|[col1, col2, col3, col4, col5]| {
|
||||||
|
let width = ((ui.available_width() / 5.0)
|
||||||
|
- (ui.spacing().item_spacing.x * (4.0 / 5.0)))
|
||||||
|
.max(20.0);
|
||||||
|
let height = height_txt_before_button(ui, &TextStyle::Button) * 2.0;
|
||||||
// [Select random node]
|
// [Select random node]
|
||||||
|
ui.style_mut().override_text_valign = Some(egui::Align::Center);
|
||||||
if ui
|
if ui
|
||||||
.add_sized(size, Button::new("Select random node"))
|
.add_sized([width, height], Button::new("Select random node"))
|
||||||
.on_hover_text(P2POOL_SELECT_RANDOM)
|
.on_hover_text(P2POOL_SELECT_RANDOM)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -104,7 +98,7 @@ impl P2pool {
|
||||||
}
|
}
|
||||||
// [Select fastest node]
|
// [Select fastest node]
|
||||||
if ui
|
if ui
|
||||||
.add_sized(size, Button::new("Select fastest node"))
|
.add_sized([width, height], Button::new("Select fastest node"))
|
||||||
.on_hover_text(P2POOL_SELECT_FASTEST)
|
.on_hover_text(P2POOL_SELECT_FASTEST)
|
||||||
.clicked()
|
.clicked()
|
||||||
&& ping.lock().unwrap().pinged
|
&& ping.lock().unwrap().pinged
|
||||||
|
@ -114,7 +108,7 @@ impl P2pool {
|
||||||
// [Ping Button]
|
// [Ping Button]
|
||||||
ui.add_enabled_ui(!ping.lock().unwrap().pinging, |ui| {
|
ui.add_enabled_ui(!ping.lock().unwrap().pinging, |ui| {
|
||||||
if ui
|
if ui
|
||||||
.add_sized(size, Button::new("Ping remote nodes"))
|
.add_sized([width, height], Button::new("Ping remote nodes"))
|
||||||
.on_hover_text(P2POOL_PING)
|
.on_hover_text(P2POOL_PING)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -123,14 +117,15 @@ impl P2pool {
|
||||||
});
|
});
|
||||||
// [Last <-]
|
// [Last <-]
|
||||||
if ui
|
if ui
|
||||||
.add_sized(size, Button::new("⬅ Last"))
|
.add_sized([width, height], Button::new("⬅ Last"))
|
||||||
.on_hover_text(P2POOL_SELECT_LAST)
|
.on_hover_text(P2POOL_SELECT_LAST)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let ping = ping.lock().unwrap();
|
let ping = ping.lock().unwrap();
|
||||||
match ping.pinged {
|
match ping.pinged {
|
||||||
true => {
|
true => {
|
||||||
self.node = RemoteNode::get_last_from_ping(&self.node, &ping.nodes)
|
self.node =
|
||||||
|
RemoteNode::get_last_from_ping(&self.node, &ping.nodes)
|
||||||
}
|
}
|
||||||
false => self.node = RemoteNode::get_last(&self.node),
|
false => self.node = RemoteNode::get_last(&self.node),
|
||||||
}
|
}
|
||||||
|
@ -138,14 +133,15 @@ impl P2pool {
|
||||||
}
|
}
|
||||||
// [Next ->]
|
// [Next ->]
|
||||||
if ui
|
if ui
|
||||||
.add_sized(size, Button::new("Next ➡"))
|
.add_sized([width, height], Button::new("Next ➡"))
|
||||||
.on_hover_text(P2POOL_SELECT_NEXT)
|
.on_hover_text(P2POOL_SELECT_NEXT)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let ping = ping.lock().unwrap();
|
let ping = ping.lock().unwrap();
|
||||||
match ping.pinged {
|
match ping.pinged {
|
||||||
true => {
|
true => {
|
||||||
self.node = RemoteNode::get_next_from_ping(&self.node, &ping.nodes)
|
self.node =
|
||||||
|
RemoteNode::get_next_from_ping(&self.node, &ping.nodes)
|
||||||
}
|
}
|
||||||
false => self.node = RemoteNode::get_next(&self.node),
|
false => self.node = RemoteNode::get_next(&self.node),
|
||||||
}
|
}
|
||||||
|
@ -153,57 +149,75 @@ impl P2pool {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
let height = height / 2.0;
|
// let height = height / 2.0;
|
||||||
let pinging = ping.lock().unwrap().pinging;
|
let pinging = ping.lock().unwrap().pinging;
|
||||||
ui.add_enabled_ui(pinging, |ui| {
|
ui.add_enabled_ui(pinging, |ui| {
|
||||||
let prog = ping.lock().unwrap().prog.round();
|
let prog = ping.lock().unwrap().prog.round();
|
||||||
let msg =
|
let msg = RichText::new(format!(
|
||||||
RichText::new(format!("{} ... {}%", ping.lock().unwrap().msg, prog));
|
"{} ... {}%",
|
||||||
let height = height / 1.25;
|
ping.lock().unwrap().msg,
|
||||||
let size = vec2(size.x, height);
|
prog
|
||||||
ui.add_space(space_h);
|
));
|
||||||
ui.add_sized(size, Label::new(msg));
|
// let height = height / 1.25;
|
||||||
ui.add_space(space_h);
|
// let size = vec2(size.x, height);
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
ui.label(msg);
|
||||||
|
ui.add_space(SPACE);
|
||||||
if pinging {
|
if pinging {
|
||||||
ui.add_sized(size, Spinner::new().size(height));
|
ui.spinner();
|
||||||
} else {
|
} else {
|
||||||
ui.add_sized(size, Label::new("..."));
|
ui.label("...");
|
||||||
}
|
}
|
||||||
ui.add_sized(size, ProgressBar::new(prog.round() / 100.0));
|
ui.add(ProgressBar::new(prog.round() / 100.0));
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("P2Pool Tab | Rendering [Auto-*] buttons");
|
debug!("P2Pool Tab | Rendering [Auto-*] buttons");
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = ((size.x / 3.0) - (SPACE * 1.75)).max(0.0);
|
let width =
|
||||||
let size = vec2(width, height);
|
(((ui.available_width() - ui.spacing().item_spacing.x) / 3.0)
|
||||||
|
- SPACE * 1.5)
|
||||||
|
.max(ui.text_style_height(&TextStyle::Button) * 7.0);
|
||||||
|
let size = vec2(
|
||||||
|
width,
|
||||||
|
height_txt_before_button(ui, &TextStyle::Button) * 2.0,
|
||||||
|
);
|
||||||
// [Auto-node]
|
// [Auto-node]
|
||||||
ui.add_sized(size, Checkbox::new(&mut self.auto_select, "Auto-select"))
|
ui.add_sized(
|
||||||
|
size,
|
||||||
|
Checkbox::new(&mut self.auto_select, "Auto-select"),
|
||||||
|
)
|
||||||
|
// ui.checkbox(&mut self.auto_select, "Auto-select")
|
||||||
.on_hover_text(P2POOL_AUTO_SELECT);
|
.on_hover_text(P2POOL_AUTO_SELECT);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
// [Auto-node]
|
// [Auto-node]
|
||||||
ui.add_sized(size, Checkbox::new(&mut self.auto_ping, "Auto-ping"))
|
ui.add_sized(size, Checkbox::new(&mut self.auto_ping, "Auto-ping"))
|
||||||
|
// ui.checkbox(&mut self.auto_ping, "Auto-ping")
|
||||||
.on_hover_text(P2POOL_AUTO_NODE);
|
.on_hover_text(P2POOL_AUTO_NODE);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
// [Backup host]
|
// [Backup host]
|
||||||
ui.add_sized(size, Checkbox::new(&mut self.backup_host, "Backup host"))
|
ui.add_sized(
|
||||||
|
size,
|
||||||
|
Checkbox::new(&mut self.backup_host, "Backup host"),
|
||||||
|
)
|
||||||
|
// ui.checkbox(&mut self.backup_host, "Backup host")
|
||||||
.on_hover_text(P2POOL_BACKUP_HOST_SIMPLE);
|
.on_hover_text(P2POOL_BACKUP_HOST_SIMPLE);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
debug!("P2Pool Tab | Rendering warning text");
|
debug!("P2Pool Tab | Rendering warning text");
|
||||||
ui.add_sized(
|
ui.add_space(SPACE);
|
||||||
[size.x, height / 2.0],
|
ui.vertical_centered(|ui| {
|
||||||
Hyperlink::from_label_and_url(
|
ui.hyperlink_to(
|
||||||
"WARNING: It is recommended to run/use your own Monero Node (hover for details)",
|
"WARNING: It is recommended to run/use your own Monero Node (hover for details)",
|
||||||
"https://github.com/Cyrix126/gupaxx#running-a-local-monero-node",
|
"https://github.com/Cyrix126/gupaxx#running-a-local-monero-node",
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(P2POOL_COMMUNITY_NODE_WARNING);
|
.on_hover_text(P2POOL_COMMUNITY_NODE_WARNING);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::{app::Benchmark, disk::state::Status, helper::xrig::xmrig::PubXmrigApi};
|
use crate::{app::Benchmark, disk::state::Status, helper::xrig::xmrig::PubXmrigApi};
|
||||||
use egui::{Hyperlink, ProgressBar, ScrollArea, Spinner, Vec2};
|
use egui::{ProgressBar, ScrollArea, TextWrapMode};
|
||||||
use egui_extras::{Column, TableBuilder};
|
use egui_extras::{Column, TableBuilder};
|
||||||
use readable::num::{Float, Percent, Unsigned};
|
use readable::num::{Float, Percent, Unsigned};
|
||||||
|
|
||||||
|
@ -11,85 +11,56 @@ use log::*;
|
||||||
impl Status {
|
impl Status {
|
||||||
pub(super) fn benchmarks(
|
pub(super) fn benchmarks(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Vec2,
|
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
benchmarks: &[Benchmark],
|
benchmarks: &[Benchmark],
|
||||||
xmrig_alive: bool,
|
xmrig_alive: bool,
|
||||||
xmrig_api: &Arc<Mutex<PubXmrigApi>>,
|
xmrig_api: &Arc<Mutex<PubXmrigApi>>,
|
||||||
) {
|
) {
|
||||||
debug!("Status Tab | Rendering [Benchmarks]");
|
debug!("Status Tab | Rendering [Benchmarks]");
|
||||||
let text = size.y / 20.0;
|
let text = ui.text_style_height(&egui::TextStyle::Body);
|
||||||
let double = text * 2.0;
|
let double = text * 2.0;
|
||||||
let log = size.y / 3.0;
|
|
||||||
|
|
||||||
let width = size.x;
|
let width = ui.available_width();
|
||||||
// [0], The user's CPU (most likely).
|
// [0], The user's CPU (most likely).
|
||||||
let cpu = &benchmarks[0];
|
let cpu = &benchmarks[0];
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (width / 2.0) - (SPACE * 1.666);
|
|
||||||
let min_height = log;
|
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.set_max_width(ui.available_width() / 2.0);
|
||||||
ui.set_min_height(min_height);
|
ui.vertical_centered(|ui| {
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Your CPU").underline().color(BONE))
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("Your CPU").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_CPU);
|
.on_hover_text(STATUS_SUBMENU_YOUR_CPU);
|
||||||
ui.add_sized([width, text], Label::new(cpu.cpu.as_str()));
|
ui.label(cpu.cpu.as_str());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Total Banchmarks").underline().color(BONE))
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("Total Benchmarks").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_BENCHMARKS);
|
.on_hover_text(STATUS_SUBMENU_YOUR_BENCHMARKS);
|
||||||
ui.add_sized([width, text], Label::new(format!("{}", cpu.benchmarks)));
|
ui.label(format!("{}", cpu.benchmarks));
|
||||||
ui.add_sized(
|
// ui.add_sized([width, text], Label::new(format!("{}", cpu.benchmarks)));
|
||||||
[width, text],
|
ui.label(RichText::new("Rank").underline().color(BONE))
|
||||||
Label::new(RichText::new("Rank").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_RANK);
|
.on_hover_text(STATUS_SUBMENU_YOUR_RANK);
|
||||||
ui.add_sized(
|
ui.label(format!("{}/{}", cpu.rank, &benchmarks.len()));
|
||||||
[width, text],
|
|
||||||
Label::new(format!("{}/{}", cpu.rank, &benchmarks.len())),
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.set_min_height(min_height);
|
ui.label(RichText::new("High Hashrate").underline().color(BONE))
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("High Hashrate").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_HIGH);
|
.on_hover_text(STATUS_SUBMENU_YOUR_HIGH);
|
||||||
ui.add_sized(
|
ui.label(format!("{} H/s", Float::from_0(cpu.high.into())));
|
||||||
[width, text],
|
ui.label(RichText::new("Average Hashrate").underline().color(BONE))
|
||||||
Label::new(format!("{} H/s", Float::from_0(cpu.high.into()))),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("Average Hashrate").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_AVERAGE);
|
.on_hover_text(STATUS_SUBMENU_YOUR_AVERAGE);
|
||||||
ui.add_sized(
|
ui.label(format!("{} H/s", Float::from_0(cpu.average.into())));
|
||||||
[width, text],
|
ui.label(RichText::new("Low Hashrate").underline().color(BONE))
|
||||||
Label::new(format!("{} H/s", Float::from_0(cpu.average.into()))),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("Low Hashrate").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_LOW);
|
.on_hover_text(STATUS_SUBMENU_YOUR_LOW);
|
||||||
ui.add_sized(
|
ui.label(RichText::new(format!(
|
||||||
[width, text],
|
"{} H/s",
|
||||||
Label::new(format!("{} H/s", Float::from_0(cpu.low.into()))),
|
Float::from_0(cpu.low.into())
|
||||||
);
|
)));
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// User's CPU hashrate comparison (if XMRig is alive).
|
// User's CPU hashrate comparison (if XMRig is alive).
|
||||||
ui.scope(|ui| {
|
// User's CPU hashrate comparison (if XMRig is alive).
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(SPACE);
|
||||||
if xmrig_alive {
|
if xmrig_alive {
|
||||||
let api = xmrig_api.lock().unwrap();
|
let api = xmrig_api.lock().unwrap();
|
||||||
let percent = (api.hashrate_raw / cpu.high) * 100.0;
|
let percent = (api.hashrate_raw / cpu.high) * 100.0;
|
||||||
|
@ -102,11 +73,11 @@ impl Status {
|
||||||
human, api.hashrate
|
human, api.hashrate
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
ui.add_sized([width, text], ProgressBar::new(1.0));
|
ui.add(ProgressBar::new(1.0));
|
||||||
} else if api.hashrate_raw == 0.0 {
|
} else if api.hashrate_raw == 0.0 {
|
||||||
ui.add_sized([width, text], Label::new("Measuring hashrate..."));
|
ui.label("Measuring hashrate...");
|
||||||
ui.add_sized([width, text], Spinner::new().size(text));
|
ui.spinner();
|
||||||
ui.add_sized([width, text], ProgressBar::new(0.0));
|
ui.add(ProgressBar::new(0.0));
|
||||||
} else {
|
} else {
|
||||||
ui.add_sized(
|
ui.add_sized(
|
||||||
[width, double],
|
[width, double],
|
||||||
|
@ -115,7 +86,7 @@ impl Status {
|
||||||
human, api.hashrate
|
human, api.hashrate
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
ui.add_sized([width, text], ProgressBar::new(percent / 100.0));
|
ui.add(ProgressBar::new(percent / 100.0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ui.add_enabled_ui(xmrig_alive, |ui| {
|
ui.add_enabled_ui(xmrig_alive, |ui| {
|
||||||
|
@ -123,22 +94,21 @@ impl Status {
|
||||||
[width, double],
|
[width, double],
|
||||||
Label::new("XMRig is offline. Hashrate cannot be determined."),
|
Label::new("XMRig is offline. Hashrate cannot be determined."),
|
||||||
);
|
);
|
||||||
ui.add_sized([width, text], ProgressBar::new(0.0));
|
ui.add(ProgressBar::new(0.0));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
// Comparison
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.hyperlink_to("Other CPUs", "https://xmrig.com/benchmark")
|
||||||
|
.on_hover_text(STATUS_SUBMENU_OTHER_CPUS);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Comparison
|
// Comparison
|
||||||
ui.group(|ui| {
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Hyperlink::from_label_and_url("Other CPUs", "https://xmrig.com/benchmark"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_OTHER_CPUS);
|
|
||||||
});
|
|
||||||
let width_column = width / 20.0;
|
let width_column = width / 20.0;
|
||||||
let (cpu, bar, high, average, low, rank, bench) = (
|
let (cpu, bar, high, average, low, rank, bench) = (
|
||||||
width_column * 10.0,
|
width_column * 6.0,
|
||||||
width_column * 3.0,
|
width_column * 3.0,
|
||||||
width_column * 2.0,
|
width_column * 2.0,
|
||||||
width_column * 2.0,
|
width_column * 2.0,
|
||||||
|
@ -146,6 +116,7 @@ impl Status {
|
||||||
width_column,
|
width_column,
|
||||||
width_column * 2.0,
|
width_column * 2.0,
|
||||||
);
|
);
|
||||||
|
ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
|
||||||
ScrollArea::horizontal().show(ui, |ui| {
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.columns(Column::auto(), 7)
|
.columns(Column::auto(), 7)
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use egui::Vec2;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{Benchmark, eframe_impl::ProcessStatesGui},
|
app::{Benchmark, eframe_impl::ProcessStatesGui},
|
||||||
disk::{gupax_p2pool_api::GupaxP2poolApi, state::Status, status::*},
|
disk::{gupax_p2pool_api::GupaxP2poolApi, state::Status, status::*},
|
||||||
|
@ -51,10 +49,9 @@ impl Status {
|
||||||
p2pool_img: &Arc<Mutex<ImgP2pool>>,
|
p2pool_img: &Arc<Mutex<ImgP2pool>>,
|
||||||
xmrig_img: &Arc<Mutex<ImgXmrig>>,
|
xmrig_img: &Arc<Mutex<ImgXmrig>>,
|
||||||
states: &ProcessStatesGui,
|
states: &ProcessStatesGui,
|
||||||
max_threads: usize,
|
max_threads: u16,
|
||||||
gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>,
|
gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>,
|
||||||
benchmarks: &[Benchmark],
|
benchmarks: &[Benchmark],
|
||||||
size: Vec2,
|
|
||||||
_ctx: &egui::Context,
|
_ctx: &egui::Context,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
) {
|
) {
|
||||||
|
@ -62,7 +59,6 @@ impl Status {
|
||||||
if self.submenu == Submenu::Processes {
|
if self.submenu == Submenu::Processes {
|
||||||
self.processes(
|
self.processes(
|
||||||
sys,
|
sys,
|
||||||
size,
|
|
||||||
ui,
|
ui,
|
||||||
node_api,
|
node_api,
|
||||||
p2pool_api,
|
p2pool_api,
|
||||||
|
@ -77,7 +73,6 @@ impl Status {
|
||||||
//---------------------------------------------------------------------------------------------------- [P2Pool]
|
//---------------------------------------------------------------------------------------------------- [P2Pool]
|
||||||
} else if self.submenu == Submenu::P2pool {
|
} else if self.submenu == Submenu::P2pool {
|
||||||
self.p2pool(
|
self.p2pool(
|
||||||
size,
|
|
||||||
ui,
|
ui,
|
||||||
gupax_p2pool_api,
|
gupax_p2pool_api,
|
||||||
states.is_alive(ProcessName::P2pool),
|
states.is_alive(ProcessName::P2pool),
|
||||||
|
@ -86,7 +81,6 @@ impl Status {
|
||||||
//---------------------------------------------------------------------------------------------------- [Benchmarks]
|
//---------------------------------------------------------------------------------------------------- [Benchmarks]
|
||||||
} else if self.submenu == Submenu::Benchmarks {
|
} else if self.submenu == Submenu::Benchmarks {
|
||||||
self.benchmarks(
|
self.benchmarks(
|
||||||
size,
|
|
||||||
ui,
|
ui,
|
||||||
benchmarks,
|
benchmarks,
|
||||||
states.is_alive(ProcessName::Xmrig),
|
states.is_alive(ProcessName::Xmrig),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use egui::{Label, RichText, SelectableLabel, Slider, TextEdit, Vec2};
|
use egui::{Label, RichText, ScrollArea, SelectableLabel, Separator, Slider, TextStyle};
|
||||||
use readable::num::Unsigned;
|
use readable::num::Unsigned;
|
||||||
|
use strum::{EnumCount, IntoEnumIterator};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
disk::{
|
disk::{
|
||||||
|
@ -16,23 +17,31 @@ use crate::{
|
||||||
impl Status {
|
impl Status {
|
||||||
pub fn p2pool(
|
pub fn p2pool(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Vec2,
|
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>,
|
gupax_p2pool_api: &Arc<Mutex<GupaxP2poolApi>>,
|
||||||
p2pool_alive: bool,
|
p2pool_alive: bool,
|
||||||
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
|
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
|
||||||
) {
|
) {
|
||||||
let api = gupax_p2pool_api.lock().unwrap();
|
let api = gupax_p2pool_api.lock().unwrap();
|
||||||
let height = size.y;
|
// let height = size.y;
|
||||||
let width = size.x;
|
// let width = size.x;
|
||||||
let text = height / 25.0;
|
// let text = height / 25.0;
|
||||||
let log = height / 2.8;
|
// let log = height / 2.8;
|
||||||
// Payout Text + PayoutView buttons
|
// Payout Text + PayoutView buttons
|
||||||
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
|
ui.style_mut().override_text_style = Some(TextStyle::Body);
|
||||||
|
let size_text = ui.text_style_height(&TextStyle::Body);
|
||||||
|
let height = (ui.style().spacing.button_padding.y * 2.0) + size_text;
|
||||||
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (width / 3.0) - (SPACE * 4.0);
|
let width =
|
||||||
|
((ui.available_width() / 3.0) - (SPACE * 4.0)).max(size_text * 9.0);
|
||||||
|
let width_button =
|
||||||
|
((ui.available_width() / 3.0 / 4.0) - SPACE).max(size_text * 4.0);
|
||||||
ui.add_sized(
|
ui.add_sized(
|
||||||
[width, text],
|
[width, height],
|
||||||
Label::new(
|
Label::new(
|
||||||
RichText::new(format!("Total Payouts: {}", api.payout))
|
RichText::new(format!("Total Payouts: {}", api.payout))
|
||||||
.underline()
|
.underline()
|
||||||
|
@ -40,9 +49,9 @@ impl Status {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_PAYOUT);
|
.on_hover_text(STATUS_SUBMENU_PAYOUT);
|
||||||
ui.separator();
|
ui.add(Separator::default().vertical());
|
||||||
ui.add_sized(
|
ui.add_sized(
|
||||||
[width, text],
|
[width, height],
|
||||||
Label::new(
|
Label::new(
|
||||||
RichText::new(format!("Total XMR: {}", api.xmr))
|
RichText::new(format!("Total XMR: {}", api.xmr))
|
||||||
.underline()
|
.underline()
|
||||||
|
@ -50,92 +59,63 @@ impl Status {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_XMR);
|
.on_hover_text(STATUS_SUBMENU_XMR);
|
||||||
let width = width / 4.0;
|
// });
|
||||||
ui.separator();
|
ui.add(Separator::default().vertical());
|
||||||
|
PayoutView::iter().enumerate().for_each(|(count, p)| {
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.add_sized(
|
||||||
[width, text],
|
[width_button, height],
|
||||||
SelectableLabel::new(self.payout_view == PayoutView::Latest, "Latest"),
|
SelectableLabel::new(self.payout_view == p, p.to_string()),
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_LATEST)
|
.on_hover_text(p.msg_help())
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.payout_view = PayoutView::Latest;
|
self.payout_view = p;
|
||||||
}
|
}
|
||||||
ui.separator();
|
if count + 1 < PayoutView::COUNT {
|
||||||
if ui
|
ui.add(Separator::default().vertical());
|
||||||
.add_sized(
|
|
||||||
[width, text],
|
|
||||||
SelectableLabel::new(self.payout_view == PayoutView::Oldest, "Oldest"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_OLDEST)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.payout_view = PayoutView::Oldest;
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
if ui
|
|
||||||
.add_sized(
|
|
||||||
[width, text],
|
|
||||||
SelectableLabel::new(self.payout_view == PayoutView::Biggest, "Biggest"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_BIGGEST)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.payout_view = PayoutView::Biggest;
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
if ui
|
|
||||||
.add_sized(
|
|
||||||
[width, text],
|
|
||||||
SelectableLabel::new(self.payout_view == PayoutView::Smallest, "Smallest"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_SMALLEST)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.payout_view = PayoutView::Smallest;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.separator();
|
});
|
||||||
|
});
|
||||||
|
// ui.separator();
|
||||||
// Actual logs
|
// Actual logs
|
||||||
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
||||||
egui::ScrollArea::vertical()
|
egui::ScrollArea::vertical()
|
||||||
.stick_to_bottom(self.payout_view == PayoutView::Oldest)
|
.stick_to_bottom(self.payout_view == PayoutView::Oldest)
|
||||||
.max_width(width)
|
.max_width(ui.available_width())
|
||||||
.max_height(log)
|
.max_height(ui.available_height() / 2.8)
|
||||||
.auto_shrink([false; 2])
|
.auto_shrink([false; 2])
|
||||||
.show_viewport(ui, |ui, _| {
|
.show_viewport(ui, |ui, _| {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
|
||||||
|
ui.style_mut().spacing.text_edit_width = ui.available_width();
|
||||||
match self.payout_view {
|
match self.payout_view {
|
||||||
PayoutView::Latest => ui.add_sized(
|
PayoutView::Latest => {
|
||||||
[width, log],
|
ui.text_edit_multiline(&mut api.log_rev.as_str())
|
||||||
TextEdit::multiline(&mut api.log_rev.as_str()),
|
}
|
||||||
),
|
PayoutView::Oldest => ui.text_edit_multiline(&mut api.log.as_str()),
|
||||||
PayoutView::Oldest => ui.add_sized(
|
PayoutView::Biggest => {
|
||||||
[width, log],
|
ui.text_edit_multiline(&mut api.payout_high.as_str())
|
||||||
TextEdit::multiline(&mut api.log.as_str()),
|
}
|
||||||
),
|
PayoutView::Smallest => {
|
||||||
PayoutView::Biggest => ui.add_sized(
|
ui.text_edit_multiline(&mut api.payout_low.as_str())
|
||||||
[width, log],
|
}
|
||||||
TextEdit::multiline(&mut api.payout_high.as_str()),
|
|
||||||
),
|
|
||||||
PayoutView::Smallest => ui.add_sized(
|
|
||||||
[width, log],
|
|
||||||
TextEdit::multiline(&mut api.payout_low.as_str()),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// });
|
||||||
drop(api);
|
drop(api);
|
||||||
// Payout/Share Calculator
|
// Payout/Share Calculator
|
||||||
let button = (width / 20.0) - (SPACE * 1.666);
|
// let button = (width / 20.0) - (SPACE * 1.666);
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
|
ui.set_width(ui.available_width());
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.set_min_width(width - SPACE);
|
// ui.set_min_width(width - SPACE);
|
||||||
|
let width = ui.available_width() / 10.0;
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.add_sized(
|
||||||
[button * 2.0, text],
|
[width, height],
|
||||||
SelectableLabel::new(!self.manual_hash, "Automatic"),
|
SelectableLabel::new(!self.manual_hash, "Automatic"),
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_AUTOMATIC)
|
.on_hover_text(STATUS_SUBMENU_AUTOMATIC)
|
||||||
|
@ -146,7 +126,7 @@ impl Status {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.add_sized(
|
||||||
[button * 2.0, text],
|
[width, height],
|
||||||
SelectableLabel::new(self.manual_hash, "Manual"),
|
SelectableLabel::new(self.manual_hash, "Manual"),
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_MANUAL)
|
.on_hover_text(STATUS_SUBMENU_MANUAL)
|
||||||
|
@ -157,10 +137,7 @@ impl Status {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.add_enabled_ui(self.manual_hash, |ui| {
|
ui.add_enabled_ui(self.manual_hash, |ui| {
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.selectable_label(self.hash_metric == Hash::Hash, "Hash")
|
||||||
[button, text],
|
|
||||||
SelectableLabel::new(self.hash_metric == Hash::Hash, "Hash"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_HASH)
|
.on_hover_text(STATUS_SUBMENU_HASH)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -168,10 +145,7 @@ impl Status {
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.selectable_label(self.hash_metric == Hash::Kilo, "Kilo")
|
||||||
[button, text],
|
|
||||||
SelectableLabel::new(self.hash_metric == Hash::Kilo, "Kilo"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_KILO)
|
.on_hover_text(STATUS_SUBMENU_KILO)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -179,10 +153,7 @@ impl Status {
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.selectable_label(self.hash_metric == Hash::Mega, "Mega")
|
||||||
[button, text],
|
|
||||||
SelectableLabel::new(self.hash_metric == Hash::Mega, "Mega"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_MEGA)
|
.on_hover_text(STATUS_SUBMENU_MEGA)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
@ -190,177 +161,132 @@ impl Status {
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.selectable_label(self.hash_metric == Hash::Giga, "Giga")
|
||||||
[button, text],
|
|
||||||
SelectableLabel::new(self.hash_metric == Hash::Giga, "Giga"),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_GIGA)
|
.on_hover_text(STATUS_SUBMENU_GIGA)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.hash_metric = Hash::Giga;
|
self.hash_metric = Hash::Giga;
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.spacing_mut().slider_width = button * 11.5;
|
ui.spacing_mut().slider_width = (ui.available_width() / 1.2).max(0.0);
|
||||||
ui.add_sized(
|
ui.add_sized(
|
||||||
[button * 14.0, text],
|
[0.0, height],
|
||||||
Slider::new(&mut self.hashrate, 1.0..=1_000.0),
|
Slider::new(&mut self.hashrate, 1.0..=1_000.0)
|
||||||
|
.suffix(format!(" {}", self.hash_metric)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
// Actual stats
|
// Actual stats
|
||||||
|
ui.add_space(height / 2.0);
|
||||||
ui.add_enabled_ui(p2pool_alive, |ui| {
|
ui.add_enabled_ui(p2pool_alive, |ui| {
|
||||||
let text = height / 25.0;
|
let min_height = ui.available_height() / 1.5;
|
||||||
let width = (width / 3.0) - (SPACE * 1.666);
|
|
||||||
let min_height = ui.available_height() / 1.3;
|
|
||||||
let api = p2pool_api.lock().unwrap();
|
let api = p2pool_api.lock().unwrap();
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.group(|ui| {
|
ui.columns_const(|[col1, col2, col3]| {
|
||||||
ui.vertical(|ui| {
|
col1.group(|ui| {
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(height * 2.0);
|
||||||
ui.set_min_height(min_height);
|
ui.set_min_height(min_height);
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
RichText::new("Monero Difficulty").underline().color(BONE),
|
||||||
Label::new(RichText::new("Monero Difficulty").underline().color(BONE)),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_MONERO_DIFFICULTY);
|
.on_hover_text(STATUS_SUBMENU_MONERO_DIFFICULTY);
|
||||||
ui.add_sized([width, text], Label::new(api.monero_difficulty.as_str()));
|
ui.label(api.monero_difficulty.as_str());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Monero Hashrate").underline().color(BONE))
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("Monero Hashrate").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_MONERO_HASHRATE);
|
.on_hover_text(STATUS_SUBMENU_MONERO_HASHRATE);
|
||||||
ui.add_sized([width, text], Label::new(api.monero_hashrate.as_str()));
|
ui.label(api.monero_hashrate.as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
RichText::new("P2Pool Difficulty").underline().color(BONE),
|
||||||
Label::new(RichText::new("P2Pool Difficulty").underline().color(BONE)),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_DIFFICULTY);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_DIFFICULTY);
|
||||||
ui.add_sized([width, text], Label::new(api.p2pool_difficulty.as_str()));
|
ui.label(api.p2pool_difficulty.as_str());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("P2Pool Hashrate").underline().color(BONE))
|
||||||
[width, text],
|
|
||||||
Label::new(RichText::new("P2Pool Hashrate").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_HASHRATE);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_HASHRATE);
|
||||||
ui.add_sized([width, text], Label::new(api.p2pool_hashrate.as_str()));
|
ui.label(api.p2pool_hashrate.as_str());
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
ui.group(|ui| {
|
col2.group(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(height * 2.0);
|
||||||
ui.set_min_height(min_height);
|
ui.set_min_height(min_height);
|
||||||
if self.manual_hash {
|
if self.manual_hash {
|
||||||
let hashrate =
|
let hashrate =
|
||||||
Hash::convert_to_hash(self.hashrate, self.hash_metric) as u64;
|
Hash::convert_to_hash(self.hashrate, self.hash_metric)
|
||||||
let p2pool_share_mean = PubP2poolApi::calculate_share_or_block_time(
|
as u64;
|
||||||
|
let p2pool_share_mean =
|
||||||
|
PubP2poolApi::calculate_share_or_block_time(
|
||||||
hashrate,
|
hashrate,
|
||||||
api.p2pool_difficulty_u64,
|
api.p2pool_difficulty_u64,
|
||||||
);
|
);
|
||||||
let solo_block_mean = PubP2poolApi::calculate_share_or_block_time(
|
let solo_block_mean =
|
||||||
|
PubP2poolApi::calculate_share_or_block_time(
|
||||||
hashrate,
|
hashrate,
|
||||||
api.monero_difficulty_u64,
|
api.monero_difficulty_u64,
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Manually Inputted Hashrate")
|
RichText::new("Manually Inputted Hashrate")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
ui.label(format!("{} H/s", Unsigned::from(hashrate)));
|
||||||
[width, text],
|
ui.label(
|
||||||
Label::new(format!("{} H/s", Unsigned::from(hashrate))),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("P2Pool Block Mean").underline().color(BONE),
|
RichText::new("P2Pool Block Mean").underline().color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
|
||||||
ui.add_sized(
|
ui.label(api.p2pool_block_mean.to_string());
|
||||||
[width, text],
|
ui.label(
|
||||||
Label::new(api.p2pool_block_mean.to_string()),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your P2Pool Share Mean")
|
RichText::new("Your P2Pool Share Mean")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
|
||||||
ui.add_sized([width, text], Label::new(p2pool_share_mean.to_string()));
|
ui.label(p2pool_share_mean.to_string());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your Solo Block Mean")
|
RichText::new("Your Solo Block Mean")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
|
.on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
|
||||||
ui.add_sized([width, text], Label::new(solo_block_mean.to_string()));
|
ui.label(solo_block_mean.to_string());
|
||||||
} else {
|
} else {
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your P2Pool Hashrate")
|
RichText::new("Your P2Pool Hashrate")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
|
.on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
|
||||||
ui.add_sized(
|
ui.label(format!("{} H/s", api.hashrate_1h));
|
||||||
[width, text],
|
ui.label(
|
||||||
Label::new(format!("{} H/s", api.hashrate_1h)),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("P2Pool Block Mean").underline().color(BONE),
|
RichText::new("P2Pool Block Mean").underline().color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
|
||||||
ui.add_sized(
|
ui.label(api.p2pool_block_mean.to_string());
|
||||||
[width, text],
|
ui.label(
|
||||||
Label::new(api.p2pool_block_mean.to_string()),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your P2Pool Share Mean")
|
RichText::new("Your P2Pool Share Mean")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
|
||||||
ui.add_sized(
|
ui.label(api.p2pool_share_mean.to_string());
|
||||||
[width, text],
|
ui.label(
|
||||||
Label::new(api.p2pool_share_mean.to_string()),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your Solo Block Mean")
|
RichText::new("Your Solo Block Mean")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
|
.on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
|
||||||
ui.add_sized(
|
ui.label(api.solo_block_mean.to_string());
|
||||||
[width, text],
|
|
||||||
Label::new(api.solo_block_mean.to_string()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
ui.group(|ui| {
|
col3.group(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(height * 2.0);
|
||||||
ui.set_min_height(min_height);
|
ui.set_min_height(min_height);
|
||||||
if self.manual_hash {
|
if self.manual_hash {
|
||||||
let hashrate =
|
let hashrate =
|
||||||
Hash::convert_to_hash(self.hashrate, self.hash_metric) as u64;
|
Hash::convert_to_hash(self.hashrate, self.hash_metric)
|
||||||
|
as u64;
|
||||||
let user_p2pool_percent = PubP2poolApi::calculate_dominance(
|
let user_p2pool_percent = PubP2poolApi::calculate_dominance(
|
||||||
hashrate,
|
hashrate,
|
||||||
api.p2pool_hashrate_u64,
|
api.p2pool_hashrate_u64,
|
||||||
|
@ -369,92 +295,67 @@ impl Status {
|
||||||
hashrate,
|
hashrate,
|
||||||
api.monero_hashrate_u64,
|
api.monero_hashrate_u64,
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
RichText::new("P2Pool Miners").underline().color(BONE),
|
||||||
Label::new(RichText::new("P2Pool Miners").underline().color(BONE)),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
|
||||||
ui.add_sized([width, text], Label::new(api.miners.as_str()));
|
ui.label(api.miners.as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("P2Pool Dominance").underline().color(BONE),
|
RichText::new("P2Pool Dominance").underline().color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
|
||||||
ui.add_sized([width, text], Label::new(api.p2pool_percent.as_str()));
|
ui.label(api.p2pool_percent.as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your P2Pool Dominance")
|
RichText::new("Your P2Pool Dominance")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
|
.on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
|
||||||
ui.add_sized([width, text], Label::new(user_p2pool_percent.as_str()));
|
ui.label(user_p2pool_percent.as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your Monero Dominance")
|
RichText::new("Your Monero Dominance")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
|
.on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
|
||||||
ui.add_sized([width, text], Label::new(user_monero_percent.as_str()));
|
ui.label(user_monero_percent.as_str());
|
||||||
} else {
|
} else {
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
RichText::new("P2Pool Miners").underline().color(BONE),
|
||||||
Label::new(RichText::new("P2Pool Miners").underline().color(BONE)),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
|
||||||
ui.add_sized([width, text], Label::new(api.miners.as_str()));
|
ui.label(api.miners.as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("P2Pool Dominance").underline().color(BONE),
|
RichText::new("P2Pool Dominance").underline().color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
|
.on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
|
||||||
ui.add_sized([width, text], Label::new(api.p2pool_percent.as_str()));
|
ui.label(api.p2pool_percent.as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your P2Pool Dominance")
|
RichText::new("Your P2Pool Dominance")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
|
.on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
|
||||||
ui.add_sized(
|
ui.label(api.user_p2pool_percent.as_str());
|
||||||
[width, text],
|
ui.label(
|
||||||
Label::new(api.user_p2pool_percent.as_str()),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text],
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Your Monero Dominance")
|
RichText::new("Your Monero Dominance")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
|
.on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
|
||||||
ui.add_sized(
|
ui.label(api.user_monero_percent.as_str());
|
||||||
[width, text],
|
|
||||||
Label::new(api.user_monero_percent.as_str()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
// Tick bar
|
// Tick bar
|
||||||
ui.add_sized(
|
ui.vertical_centered(|ui| {
|
||||||
[ui.available_width(), text],
|
ui.label(api.calculate_tick_bar())
|
||||||
Label::new(api.calculate_tick_bar()),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_SUBMENU_PROGRESS_BAR);
|
.on_hover_text(STATUS_SUBMENU_PROGRESS_BAR);
|
||||||
|
});
|
||||||
drop(api);
|
drop(api);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use egui::{ScrollArea, Ui, Vec2};
|
use egui::{ScrollArea, Ui};
|
||||||
use readable::up::UptimeFull;
|
use readable::up::UptimeFull;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
@ -12,14 +12,13 @@ use crate::helper::xvb::{PubXvbApi, rounds::XvbRound};
|
||||||
use crate::helper::{ProcessName, Sys};
|
use crate::helper::{ProcessName, Sys};
|
||||||
|
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use egui::{Label, RichText, TextStyle};
|
use egui::{RichText, TextStyle};
|
||||||
use log::*;
|
use log::*;
|
||||||
impl Status {
|
impl Status {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(super) fn processes(
|
pub(super) fn processes(
|
||||||
&mut self,
|
&mut self,
|
||||||
sys: &Arc<Mutex<Sys>>,
|
sys: &Arc<Mutex<Sys>>,
|
||||||
size: Vec2,
|
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
node_api: &Arc<Mutex<PubNodeApi>>,
|
node_api: &Arc<Mutex<PubNodeApi>>,
|
||||||
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
|
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
|
||||||
|
@ -28,534 +27,359 @@ impl Status {
|
||||||
xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
|
xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
|
||||||
xmrig_img: &Arc<Mutex<ImgXmrig>>,
|
xmrig_img: &Arc<Mutex<ImgXmrig>>,
|
||||||
xvb_api: &Arc<Mutex<PubXvbApi>>,
|
xvb_api: &Arc<Mutex<PubXvbApi>>,
|
||||||
max_threads: usize,
|
max_threads: u16,
|
||||||
states: &ProcessStatesGui,
|
states: &ProcessStatesGui,
|
||||||
) {
|
) {
|
||||||
// set fixed text size, temporary solution before refactoring text/widget size.
|
let width_column = ui.text_style_height(&TextStyle::Body) * 16.0;
|
||||||
let width = ((size.x / 5.0) - (SPACE * 1.7500)).max(0.0);
|
let height_column = width_column * 2.4;
|
||||||
let height = size.y / 25.0;
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
// height must be height - top - bottom - space * 2 - space of text
|
// let width = ((ui.available_width() / 5.0) - (SPACE * 1.7500)).max(0.0);
|
||||||
let size: Vec2 = [width, height].into();
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
let min_height = (size.y - SPACE).max(0.0);
|
|
||||||
// min width must allow to display text without wrapping.
|
|
||||||
let size_text = ui.text_style_height(&TextStyle::Body);
|
|
||||||
// ui.spacing_mut().item_spacing = Vec2::new(2.0, 2.0);
|
|
||||||
let min_width = size_text * 14.0;
|
|
||||||
let min_size: Vec2 = [min_width, min_height].into();
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ScrollArea::horizontal().show(ui, |ui| {
|
ScrollArea::horizontal().show(ui, |ui| {
|
||||||
ui.set_min_height(min_height * 34.2);
|
ui.vertical(|ui| {
|
||||||
gupax(ui, min_size, size, sys);
|
ui.group(|ui| {
|
||||||
node(
|
ui.set_width(width_column);
|
||||||
ui,
|
ui.set_height(height_column);
|
||||||
min_size,
|
ui.vertical_centered(|ui| {
|
||||||
size,
|
// ui.set_min_width(ui.text_style_height(&TextStyle::Body) * 2.0);
|
||||||
states.is_alive(ProcessName::Node),
|
gupax(ui, sys);
|
||||||
node_api,
|
});
|
||||||
);
|
});
|
||||||
|
});
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.set_width(width_column);
|
||||||
|
ui.set_height(height_column);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
node(ui, states.is_alive(ProcessName::Node), node_api);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.set_width(width_column);
|
||||||
|
ui.set_height(height_column);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
p2pool(
|
p2pool(
|
||||||
ui,
|
ui,
|
||||||
min_size,
|
|
||||||
size,
|
|
||||||
states.is_alive(ProcessName::P2pool),
|
states.is_alive(ProcessName::P2pool),
|
||||||
p2pool_api,
|
p2pool_api,
|
||||||
p2pool_img,
|
p2pool_img,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.set_width(width_column);
|
||||||
|
ui.set_height(height_column);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
xmrig(
|
xmrig(
|
||||||
ui,
|
ui,
|
||||||
min_size,
|
|
||||||
size,
|
|
||||||
states.is_alive(ProcessName::Xmrig),
|
states.is_alive(ProcessName::Xmrig),
|
||||||
xmrig_api,
|
xmrig_api,
|
||||||
xmrig_img,
|
xmrig_img,
|
||||||
max_threads,
|
max_threads,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.set_width(width_column);
|
||||||
|
ui.set_height(height_column);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
xmrig_proxy(
|
xmrig_proxy(
|
||||||
ui,
|
ui,
|
||||||
min_size,
|
|
||||||
size,
|
|
||||||
states.is_alive(ProcessName::XmrigProxy),
|
states.is_alive(ProcessName::XmrigProxy),
|
||||||
xmrig_proxy_api,
|
xmrig_proxy_api,
|
||||||
);
|
);
|
||||||
xvb(
|
});
|
||||||
ui,
|
});
|
||||||
min_size,
|
});
|
||||||
size,
|
ui.vertical(|ui| {
|
||||||
states.is_alive(ProcessName::Xvb),
|
ui.group(|ui| {
|
||||||
xvb_api,
|
ui.set_width(width_column);
|
||||||
);
|
ui.set_height(height_column);
|
||||||
})
|
ui.vertical_centered(|ui| {
|
||||||
|
xvb(ui, states.is_alive(ProcessName::Xvb), xvb_api);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn gupax(ui: &mut Ui, min_size: Vec2, size: Vec2, sys: &Arc<Mutex<Sys>>) {
|
|
||||||
ui.group(|ui| {
|
fn gupax(ui: &mut Ui, sys: &Arc<Mutex<Sys>>) {
|
||||||
ui.vertical(|ui| {
|
ui.label(
|
||||||
ui.set_min_size(min_size);
|
|
||||||
ui.set_min_height(min_size.y * 34.0);
|
|
||||||
debug!("Status Tab | Rendering [Gupaxx]");
|
|
||||||
// ui.set_min_size([min_size.x, min_size.y / 2.0].into());
|
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("[Gupaxx]")
|
RichText::new("[Gupaxx]")
|
||||||
.color(LIGHT_GRAY)
|
.color(LIGHT_GRAY)
|
||||||
.text_style(TextStyle::Heading),
|
.text_style(TextStyle::Heading),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text("Gupaxx is online");
|
.on_hover_text("Gupaxx is online");
|
||||||
let sys = sys.lock().unwrap();
|
let sys = sys.lock().unwrap();
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Uptime").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Uptime").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_GUPAX_UPTIME);
|
.on_hover_text(STATUS_GUPAX_UPTIME);
|
||||||
ui.add_sized(size, Label::new(sys.gupax_uptime.to_string()));
|
ui.label(sys.gupax_uptime.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Gupaxx CPU").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Gupaxx CPU").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_GUPAX_CPU_USAGE);
|
.on_hover_text(STATUS_GUPAX_CPU_USAGE);
|
||||||
ui.add_sized(size, Label::new(sys.gupax_cpu_usage.to_string()));
|
ui.label(sys.gupax_cpu_usage.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Gupaxx Memory").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Gupaxx Memory").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_GUPAX_MEMORY_USAGE);
|
.on_hover_text(STATUS_GUPAX_MEMORY_USAGE);
|
||||||
ui.add_sized(size, Label::new(sys.gupax_memory_used_mb.to_string()));
|
ui.label(sys.gupax_memory_used_mb.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("System CPU").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("System CPU").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_GUPAX_SYSTEM_CPU_USAGE);
|
.on_hover_text(STATUS_GUPAX_SYSTEM_CPU_USAGE);
|
||||||
ui.add_sized(size, Label::new(sys.system_cpu_usage.to_string()));
|
ui.label(sys.system_cpu_usage.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("System Memory").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("System Memory").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_GUPAX_SYSTEM_MEMORY);
|
.on_hover_text(STATUS_GUPAX_SYSTEM_MEMORY);
|
||||||
ui.add_sized(size, Label::new(sys.system_memory.to_string()));
|
ui.label(sys.system_memory.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("System CPU Model").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("System CPU Model").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_GUPAX_SYSTEM_CPU_MODEL);
|
.on_hover_text(STATUS_GUPAX_SYSTEM_CPU_MODEL);
|
||||||
ui.add_sized(size, Label::new(sys.system_cpu_model.to_string()));
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Wrap);
|
||||||
|
ui.label(sys.system_cpu_model.to_string());
|
||||||
drop(sys);
|
drop(sys);
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn p2pool(
|
fn p2pool(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
min_size: Vec2,
|
|
||||||
size: Vec2,
|
|
||||||
p2pool_alive: bool,
|
p2pool_alive: bool,
|
||||||
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
|
p2pool_api: &Arc<Mutex<PubP2poolApi>>,
|
||||||
p2pool_img: &Arc<Mutex<ImgP2pool>>,
|
p2pool_img: &Arc<Mutex<ImgP2pool>>,
|
||||||
) {
|
) {
|
||||||
ui.group(|ui| {
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
|
||||||
ui.set_min_height(min_size.y * 34.0);
|
|
||||||
ui.set_min_size(min_size);
|
|
||||||
debug!("Status Tab | Rendering [P2Pool]");
|
|
||||||
ui.add_enabled_ui(p2pool_alive, |ui| {
|
ui.add_enabled_ui(p2pool_alive, |ui| {
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("[P2Pool]")
|
RichText::new("[P2Pool]")
|
||||||
.color(LIGHT_GRAY)
|
.color(LIGHT_GRAY)
|
||||||
.text_style(TextStyle::Heading),
|
.text_style(TextStyle::Heading),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text("P2Pool is online")
|
.on_hover_text("P2Pool is online")
|
||||||
.on_disabled_hover_text("P2Pool is offline");
|
.on_disabled_hover_text("P2Pool is offline");
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
||||||
let size = [size.x, size.y / 1.4];
|
|
||||||
let api = p2pool_api.lock().unwrap();
|
let api = p2pool_api.lock().unwrap();
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Uptime").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Uptime").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_UPTIME);
|
.on_hover_text(STATUS_P2POOL_UPTIME);
|
||||||
ui.add_sized(size, Label::new(format!("{}", api.uptime)));
|
ui.label(format!("{}", api.uptime));
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Current Shares").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Current Shares").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_CURRENT_SHARES);
|
.on_hover_text(STATUS_P2POOL_CURRENT_SHARES);
|
||||||
ui.add_sized(size, Label::new(api.sidechain_shares.to_string()));
|
ui.label(api.sidechain_shares.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Shares Found").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Shares Found").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_SHARES);
|
.on_hover_text(STATUS_P2POOL_SHARES);
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
(if let Some(s) = api.shares_found {
|
(if let Some(s) = api.shares_found {
|
||||||
s.to_string()
|
s.to_string()
|
||||||
} else {
|
} else {
|
||||||
UNKNOWN_DATA.to_string()
|
UNKNOWN_DATA.to_string()
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Payouts").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Payouts").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_PAYOUTS);
|
.on_hover_text(STATUS_P2POOL_PAYOUTS);
|
||||||
ui.add_sized(size, Label::new(format!("Total: {}", api.payouts)));
|
ui.label(format!("Total: {}", api.payouts));
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
|
"[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
|
||||||
api.payouts_hour, api.payouts_day, api.payouts_month
|
api.payouts_hour, api.payouts_day, api.payouts_month
|
||||||
)),
|
));
|
||||||
);
|
ui.label(RichText::new("XMR Mined").underline().color(BONE))
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(RichText::new("XMR Mined").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_XMR);
|
.on_hover_text(STATUS_P2POOL_XMR);
|
||||||
ui.add_sized(size, Label::new(format!("Total: {:.13} XMR", api.xmr)));
|
ui.label(format!("Total: {:.13} XMR", api.xmr));
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
|
"[{:.7}/hour]\n[{:.7}/day]\n[{:.7}/month]",
|
||||||
api.xmr_hour, api.xmr_day, api.xmr_month
|
api.xmr_hour, api.xmr_day, api.xmr_month
|
||||||
)),
|
));
|
||||||
);
|
ui.label(
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Hashrate (15m/1h/24h)")
|
RichText::new("Hashrate (15m/1h/24h)")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_P2POOL_HASHRATE);
|
.on_hover_text(STATUS_P2POOL_HASHRATE);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
"[{} H/s]\n[{} H/s]\n[{} H/s]",
|
||||||
Label::new(format!(
|
|
||||||
"[{} H/s] [{} H/s] [{} H/s]",
|
|
||||||
api.hashrate_15m, api.hashrate_1h, api.hashrate_24h
|
api.hashrate_15m, api.hashrate_1h, api.hashrate_24h
|
||||||
)),
|
));
|
||||||
);
|
ui.label(RichText::new("Miners Connected").underline().color(BONE))
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Miners Connected").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_CONNECTIONS);
|
.on_hover_text(STATUS_P2POOL_CONNECTIONS);
|
||||||
ui.add_sized(size, Label::new(format!("{}", api.connections)));
|
ui.label(format!("{}", api.connections));
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Effort").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Effort").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_EFFORT);
|
.on_hover_text(STATUS_P2POOL_EFFORT);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"[Average: {}] [Current: {}]",
|
"[Average: {}] [Current: {}]",
|
||||||
api.average_effort, api.current_effort
|
api.average_effort, api.current_effort
|
||||||
)),
|
));
|
||||||
);
|
|
||||||
let img = p2pool_img.lock().unwrap();
|
let img = p2pool_img.lock().unwrap();
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Monero Node").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Monero Node").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_MONERO_NODE);
|
.on_hover_text(STATUS_P2POOL_MONERO_NODE);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
"IP: {}]\n[RPC: {}] [ZMQ: {}]",
|
||||||
Label::new(format!(
|
|
||||||
"[IP: {}]\n[RPC: {}] [ZMQ: {}]",
|
|
||||||
&img.host, &img.rpc, &img.zmq
|
&img.host, &img.rpc, &img.zmq
|
||||||
)),
|
));
|
||||||
);
|
ui.label(RichText::new("Sidechain").underline().color(BONE))
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Sidechain").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_POOL);
|
.on_hover_text(STATUS_P2POOL_POOL);
|
||||||
ui.add_sized(size, Label::new(&img.mini));
|
ui.label(&img.mini);
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Address").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Address").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_P2POOL_ADDRESS);
|
.on_hover_text(STATUS_P2POOL_ADDRESS);
|
||||||
ui.add_sized(size, Label::new(&img.address));
|
ui.label(&img.address);
|
||||||
drop(img);
|
drop(img);
|
||||||
drop(api);
|
drop(api);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn xmrig_proxy(
|
fn xmrig_proxy(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
min_size: Vec2,
|
|
||||||
size: Vec2,
|
|
||||||
xmrig_proxy_alive: bool,
|
xmrig_proxy_alive: bool,
|
||||||
xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
|
xmrig_proxy_api: &Arc<Mutex<PubXmrigProxyApi>>,
|
||||||
) {
|
) {
|
||||||
ui.group(|ui| {
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.set_min_height(min_size.y * 34.0);
|
|
||||||
debug!("Status Tab | Rendering [XMRig-Proxy]");
|
|
||||||
ui.add_enabled_ui(xmrig_proxy_alive, |ui| {
|
ui.add_enabled_ui(xmrig_proxy_alive, |ui| {
|
||||||
ui.set_min_size(min_size);
|
ui.label(
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("[XMRig-Proxy]")
|
RichText::new("[XMRig-Proxy]")
|
||||||
.color(LIGHT_GRAY)
|
.color(LIGHT_GRAY)
|
||||||
.text_style(TextStyle::Heading),
|
.text_style(TextStyle::Heading),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text("XMRig-Proxy is online")
|
.on_hover_text("XMRig-Proxy is online")
|
||||||
.on_disabled_hover_text("XMRig-Proxy is offline");
|
.on_disabled_hover_text("XMRig-Proxy is offline");
|
||||||
let api = xmrig_proxy_api.lock().unwrap();
|
let api = xmrig_proxy_api.lock().unwrap();
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Uptime").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Uptime").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_PROXY_UPTIME);
|
.on_hover_text(STATUS_XMRIG_PROXY_UPTIME);
|
||||||
ui.add_sized(size, Label::new(UptimeFull::from(api.uptime).as_str()));
|
ui.label(UptimeFull::from(api.uptime).as_str());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Hashrate\n(1m/10m/1h/12h/24h)")
|
RichText::new("Hashrate\n(1m/10m/1h/12h/24h)")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_XMRIG_PROXY_HASHRATE);
|
.on_hover_text(STATUS_XMRIG_PROXY_HASHRATE);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
"[{} H/s]\n[{} H/s]\n[{} H/s]\n[{} H/s]\n[{} H/s]",
|
||||||
Label::new(format!(
|
api.hashrate_1m, api.hashrate_10m, api.hashrate_1h, api.hashrate_12h, api.hashrate_24h
|
||||||
"[{} H/s] [{} H/s]\n[{} H/s] [{} H/s] [{} H/s]",
|
));
|
||||||
api.hashrate_1m,
|
ui.label(format!(
|
||||||
api.hashrate_10m,
|
|
||||||
api.hashrate_1h,
|
|
||||||
api.hashrate_12h,
|
|
||||||
api.hashrate_24h
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"[Accepted: {}]\n[Rejected: {}]",
|
"[Accepted: {}]\n[Rejected: {}]",
|
||||||
api.accepted, api.rejected
|
api.accepted, api.rejected
|
||||||
)),
|
));
|
||||||
);
|
ui.label(RichText::new("Pool").underline().color(BONE))
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Pool").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_PROXY_POOL);
|
.on_hover_text(STATUS_XMRIG_PROXY_POOL);
|
||||||
ui.add_sized(size, Label::new(api.node.to_string()));
|
ui.label(api.node.to_string());
|
||||||
drop(api);
|
drop(api);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn xmrig(
|
fn xmrig(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
min_size: Vec2,
|
|
||||||
size: Vec2,
|
|
||||||
xmrig_alive: bool,
|
xmrig_alive: bool,
|
||||||
xmrig_api: &Arc<Mutex<PubXmrigApi>>,
|
xmrig_api: &Arc<Mutex<PubXmrigApi>>,
|
||||||
xmrig_img: &Arc<Mutex<ImgXmrig>>,
|
xmrig_img: &Arc<Mutex<ImgXmrig>>,
|
||||||
max_threads: usize,
|
max_threads: u16,
|
||||||
) {
|
) {
|
||||||
ui.group(|ui| {
|
|
||||||
// ScrollArea::vertical().show(ui, |ui| {
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.set_min_height(min_size.y * 34.0);
|
|
||||||
ui.spacing_mut().item_spacing = Vec2::new(2.0, 2.0);
|
|
||||||
debug!("Status Tab | Rendering [XMRig]");
|
debug!("Status Tab | Rendering [XMRig]");
|
||||||
ui.add_enabled_ui(xmrig_alive, |ui| {
|
ui.add_enabled_ui(xmrig_alive, |ui| {
|
||||||
// ui.set_min_size(min_size);
|
// ui.set_min_size(min_size);
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("[XMRig]")
|
RichText::new("[XMRig]")
|
||||||
.color(LIGHT_GRAY)
|
.color(LIGHT_GRAY)
|
||||||
.text_style(TextStyle::Heading),
|
.text_style(TextStyle::Heading),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text("XMRig is online")
|
.on_hover_text("XMRig is online")
|
||||||
.on_disabled_hover_text("XMRig is offline");
|
.on_disabled_hover_text("XMRig is offline");
|
||||||
let api = xmrig_api.lock().unwrap();
|
let api = xmrig_api.lock().unwrap();
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Uptime").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Uptime").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_UPTIME);
|
.on_hover_text(STATUS_XMRIG_UPTIME);
|
||||||
ui.add_sized(size, Label::new(UptimeFull::from(api.uptime).as_str()));
|
ui.label(UptimeFull::from(api.uptime).as_str());
|
||||||
ui.add_sized(size, Label::new(api.resources.to_string()));
|
ui.label(api.resources.to_string());
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Hashrate\n(10s/1m/15m)")
|
RichText::new("Hashrate\n(10s/1m/15m)")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_XMRIG_HASHRATE);
|
.on_hover_text(STATUS_XMRIG_HASHRATE);
|
||||||
ui.add_sized(size, Label::new(api.hashrate.to_string()));
|
ui.label(api.hashrate.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Difficulty").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Difficulty").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_DIFFICULTY);
|
.on_hover_text(STATUS_XMRIG_DIFFICULTY);
|
||||||
ui.add_sized(size, Label::new(api.diff.to_string()));
|
ui.label(api.diff.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Shares").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Shares").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_SHARES);
|
.on_hover_text(STATUS_XMRIG_SHARES);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"[Accepted: {}]\n[Rejected: {}]",
|
"[Accepted: {}]\n[Rejected: {}]",
|
||||||
api.accepted, api.rejected
|
api.accepted, api.rejected
|
||||||
)),
|
));
|
||||||
);
|
ui.label(RichText::new("Pool").underline().color(BONE))
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Pool").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_POOL);
|
.on_hover_text(STATUS_XMRIG_POOL);
|
||||||
ui.add_sized(size, Label::new(api.node.to_string()));
|
ui.label(api.node.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Threads").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Threads").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XMRIG_THREADS);
|
.on_hover_text(STATUS_XMRIG_THREADS);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
&xmrig_img.lock().unwrap().threads,
|
&xmrig_img.lock().unwrap().threads,
|
||||||
max_threads
|
max_threads
|
||||||
)),
|
));
|
||||||
);
|
|
||||||
drop(api);
|
drop(api);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
// })
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xvb(ui: &mut Ui, min_size: Vec2, size: Vec2, xvb_alive: bool, xvb_api: &Arc<Mutex<PubXvbApi>>) {
|
fn xvb(ui: &mut Ui, xvb_alive: bool, xvb_api: &Arc<Mutex<PubXvbApi>>) {
|
||||||
//
|
//
|
||||||
let api = &xvb_api.lock().unwrap().stats_pub;
|
let api = &xvb_api.lock().unwrap().stats_pub;
|
||||||
let enabled = xvb_alive;
|
let enabled = xvb_alive;
|
||||||
ui.group(|ui| {
|
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
|
||||||
ui.set_min_height(min_size.y * 34.0);
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
debug!("Status Tab | Rendering [XvB]");
|
debug!("Status Tab | Rendering [XvB]");
|
||||||
ui.add_enabled_ui(enabled, |ui| {
|
ui.add_enabled_ui(enabled, |ui| {
|
||||||
// for now there is no API ping or /health, so we verify if the field reward_yearly is empty or not.
|
// for now there is no API ping or /health, so we verify if the field reward_yearly is empty or not.
|
||||||
// ui.set_min_size(min_size);
|
// ui.set_min_size(min_size);
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("[XvB Raffle]")
|
RichText::new("[XvB Raffle]")
|
||||||
.color(LIGHT_GRAY)
|
.color(LIGHT_GRAY)
|
||||||
.text_style(TextStyle::Heading),
|
.text_style(TextStyle::Heading),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text("XvB API stats")
|
.on_hover_text("XvB API stats")
|
||||||
.on_disabled_hover_text("No data received from XvB API");
|
.on_disabled_hover_text("No data received from XvB API");
|
||||||
// [Round Type]
|
// [Round Type]
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Round Type").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Round Type").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XVB_ROUND_TYPE);
|
.on_hover_text(STATUS_XVB_ROUND_TYPE);
|
||||||
ui.add_sized(size, Label::new(api.round_type.to_string()));
|
ui.label(api.round_type.to_string());
|
||||||
// [Time Remaining]
|
// [Time Remaining]
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Round Time Remaining")
|
RichText::new("Round Time Remaining")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_XVB_TIME_REMAIN);
|
.on_hover_text(STATUS_XVB_TIME_REMAIN);
|
||||||
ui.add_sized(size, Label::new(format!("{} minutes", api.time_remain)));
|
ui.label(format!("{} minutes", api.time_remain));
|
||||||
// Donated Hashrate
|
// Donated Hashrate
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Bonus Hashrate").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Bonus Hashrate").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XVB_DONATED_HR);
|
.on_hover_text(STATUS_XVB_DONATED_HR);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"{}kH/s\n+\n{}kH/s\ndonated by\n{} donors\n with\n{} miners",
|
"{}kH/s\n+\n{}kH/s\ndonated by\n{} donors\n with\n{} miners",
|
||||||
api.bonus_hr, api.donate_hr, api.donate_miners, api.donate_workers
|
api.bonus_hr, api.donate_hr, api.donate_miners, api.donate_workers
|
||||||
)),
|
));
|
||||||
);
|
|
||||||
// Players
|
// Players
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Players").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Players").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XVB_PLAYERS);
|
.on_hover_text(STATUS_XVB_PLAYERS);
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"[Registered: {}]\n[Playing: {}]",
|
"[Registered: {}]\n[Playing: {}]",
|
||||||
api.players, api.players_round
|
api.players, api.players_round
|
||||||
)),
|
));
|
||||||
);
|
|
||||||
// Winner
|
// Winner
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Winner").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Winner").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XVB_WINNER);
|
.on_hover_text(STATUS_XVB_WINNER);
|
||||||
ui.add_sized(size, Label::new(&api.winner));
|
ui.label(&api.winner);
|
||||||
// Share effort
|
// Share effort
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Share Effort").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Share Effort").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XVB_SHARE);
|
.on_hover_text(STATUS_XVB_SHARE);
|
||||||
ui.add_sized(size, Label::new(api.share_effort.to_string()));
|
ui.label(api.share_effort.to_string());
|
||||||
// Block reward
|
// Block reward
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Block Reward").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Block Reward").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_XVB_BLOCK_REWARD);
|
.on_hover_text(STATUS_XVB_BLOCK_REWARD);
|
||||||
ui.add_sized(size, Label::new(api.block_reward.to_string()));
|
ui.label(api.block_reward.to_string());
|
||||||
// reward yearly
|
// reward yearly
|
||||||
ui.add_sized(
|
ui.label(
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("Est. Reward (Yearly)")
|
RichText::new("Est. Reward (Yearly)")
|
||||||
.underline()
|
.underline()
|
||||||
.color(BONE),
|
.color(BONE),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text(STATUS_XVB_YEARLY);
|
.on_hover_text(STATUS_XVB_YEARLY);
|
||||||
if api.reward_yearly.is_empty() {
|
if api.reward_yearly.is_empty() {
|
||||||
ui.add_sized(size, Label::new("No information".to_string()));
|
ui.label("No information".to_string());
|
||||||
} else {
|
} else {
|
||||||
ui.add_sized(
|
ui.label(format!(
|
||||||
size,
|
|
||||||
Label::new(format!(
|
|
||||||
"{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR",
|
"{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR\n{}: {} XMR",
|
||||||
XvbRound::Vip,
|
XvbRound::Vip,
|
||||||
api.reward_yearly[0],
|
api.reward_yearly[0],
|
||||||
|
@ -567,103 +391,53 @@ fn xvb(ui: &mut Ui, min_size: Vec2, size: Vec2, xvb_alive: bool, xvb_api: &Arc<M
|
||||||
api.reward_yearly[3],
|
api.reward_yearly[3],
|
||||||
XvbRound::DonorMega,
|
XvbRound::DonorMega,
|
||||||
api.reward_yearly[4]
|
api.reward_yearly[4]
|
||||||
)),
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
|
||||||
// by round
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn node(
|
fn node(ui: &mut Ui, node_alive: bool, node_api: &Arc<Mutex<PubNodeApi>>) {
|
||||||
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]");
|
debug!("Status Tab | Rendering [Node]");
|
||||||
ui.add_enabled_ui(node_alive, |ui| {
|
ui.add_enabled_ui(node_alive, |ui| {
|
||||||
ui.set_min_size(min_size);
|
ui.label(
|
||||||
ui.add_sized(
|
|
||||||
size,
|
|
||||||
Label::new(
|
|
||||||
RichText::new("[Node]")
|
RichText::new("[Node]")
|
||||||
.color(LIGHT_GRAY)
|
.color(LIGHT_GRAY)
|
||||||
.text_style(TextStyle::Heading),
|
.text_style(TextStyle::Heading),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.on_hover_text("Node is online")
|
.on_hover_text("Node is online")
|
||||||
.on_disabled_hover_text("Node is offline");
|
.on_disabled_hover_text("Node is offline");
|
||||||
let api = node_api.lock().unwrap();
|
let api = node_api.lock().unwrap();
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Uptime").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Uptime").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_UPTIME);
|
.on_hover_text(STATUS_NODE_UPTIME);
|
||||||
ui.add_sized(size, Label::new(api.uptime.to_string()));
|
ui.label(api.uptime.to_string());
|
||||||
|
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Block Height").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Block Height").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_BLOCK_HEIGHT);
|
.on_hover_text(STATUS_NODE_BLOCK_HEIGHT);
|
||||||
ui.add_sized(size, Label::new(api.blockheight.to_string()));
|
ui.label(api.blockheight.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Network Difficulty").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Network Difficulty").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_DIFFICULTY);
|
.on_hover_text(STATUS_NODE_DIFFICULTY);
|
||||||
ui.add_sized(size, Label::new(api.difficulty.to_string()));
|
ui.label(api.difficulty.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Database size").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Database size").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_DB_SIZE);
|
.on_hover_text(STATUS_NODE_DB_SIZE);
|
||||||
ui.add_sized(size, Label::new(api.database_size.to_owned()));
|
ui.label(api.database_size.to_owned());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Free space").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Free space").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_FREESPACE);
|
.on_hover_text(STATUS_NODE_FREESPACE);
|
||||||
ui.add_sized(size, Label::new(api.free_space.to_owned()));
|
ui.label(api.free_space.to_owned());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Network Type").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Network Type").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_NETTYPE);
|
.on_hover_text(STATUS_NODE_NETTYPE);
|
||||||
ui.add_sized(size, Label::new(api.nettype.to_string()));
|
ui.label(api.nettype.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Outgoing peers").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Outgoing peers").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_OUT);
|
.on_hover_text(STATUS_NODE_OUT);
|
||||||
ui.add_sized(size, Label::new(api.outgoing_connections.to_string()));
|
ui.label(api.outgoing_connections.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Incoming peers").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Incoming peers").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_IN);
|
.on_hover_text(STATUS_NODE_IN);
|
||||||
ui.add_sized(size, Label::new(api.incoming_connections.to_string()));
|
ui.label(api.incoming_connections.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Synchronized").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Synchronized").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_SYNC);
|
.on_hover_text(STATUS_NODE_SYNC);
|
||||||
ui.add_sized(size, Label::new(api.synchronized.to_string()));
|
ui.label(api.synchronized.to_string());
|
||||||
ui.add_sized(
|
ui.label(RichText::new("Status").underline().color(BONE))
|
||||||
size,
|
|
||||||
Label::new(RichText::new("Status").underline().color(BONE)),
|
|
||||||
)
|
|
||||||
.on_hover_text(STATUS_NODE_STATUS);
|
.on_hover_text(STATUS_NODE_STATUS);
|
||||||
ui.add_sized(size, Label::new(api.status.to_string()));
|
ui.label(api.status.to_string());
|
||||||
drop(api);
|
drop(api);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,471 +15,138 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
|
||||||
|
use crate::app::panels::middle::common::list_poolnode::list_poolnode;
|
||||||
|
use crate::app::panels::middle::common::state_edit_field::{
|
||||||
|
monero_address_field, slider_state_field,
|
||||||
|
};
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::disk::pool::Pool;
|
|
||||||
use crate::disk::state::Xmrig;
|
use crate::disk::state::Xmrig;
|
||||||
use crate::helper::Process;
|
use crate::helper::Process;
|
||||||
use crate::helper::xrig::xmrig::PubXmrigApi;
|
use crate::helper::xrig::xmrig::PubXmrigApi;
|
||||||
use crate::regex::{REGEXES, num_lines};
|
use crate::miscs::height_txt_before_button;
|
||||||
use crate::utils::regex::Regexes;
|
use crate::regex::REGEXES;
|
||||||
use egui::{
|
use egui::{Checkbox, Ui, vec2};
|
||||||
Button, Checkbox, ComboBox, Label, RichText, SelectableLabel, Slider, TextEdit, TextStyle,
|
|
||||||
Vec2, vec2,
|
|
||||||
};
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use super::common::list_poolnode::PoolNode;
|
||||||
|
use super::common::state_edit_field::StateTextEdit;
|
||||||
|
|
||||||
impl Xmrig {
|
impl Xmrig {
|
||||||
#[inline(always)] // called once
|
#[inline(always)] // called once
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn show(
|
pub fn show(
|
||||||
&mut self,
|
&mut self,
|
||||||
pool_vec: &mut Vec<(String, Pool)>,
|
pool_vec: &mut Vec<(String, PoolNode)>,
|
||||||
process: &Arc<Mutex<Process>>,
|
process: &Arc<Mutex<Process>>,
|
||||||
api: &Arc<Mutex<PubXmrigApi>>,
|
api: &Arc<Mutex<PubXmrigApi>>,
|
||||||
buffer: &mut String,
|
buffer: &mut String,
|
||||||
size: Vec2,
|
|
||||||
_ctx: &egui::Context,
|
_ctx: &egui::Context,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
) {
|
) {
|
||||||
let text_edit = size.y / 25.0;
|
|
||||||
//---------------------------------------------------------------------------------------------------- [Simple] Console
|
|
||||||
debug!("XMRig Tab | Rendering [Console]");
|
debug!("XMRig Tab | Rendering [Console]");
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let text = &api.lock().unwrap().output;
|
let text = &api.lock().unwrap().output;
|
||||||
let nb_lines = num_lines(text);
|
console(ui, text);
|
||||||
let (height, width) = if self.simple {
|
|
||||||
(size.y / 1.5, size.x - SPACE)
|
|
||||||
} else {
|
|
||||||
(size.y / 2.8, size.x - SPACE)
|
|
||||||
};
|
|
||||||
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
|
||||||
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::Small),
|
|
||||||
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 {
|
if !self.simple {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
let response = ui
|
input_args_field(
|
||||||
.add_sized(
|
ui,
|
||||||
[width, text_edit],
|
buffer,
|
||||||
TextEdit::hint_text(
|
process,
|
||||||
TextEdit::singleline(buffer),
|
|
||||||
r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#,
|
r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#,
|
||||||
),
|
XMRIG_INPUT,
|
||||||
)
|
);
|
||||||
.on_hover_text(XMRIG_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 = process.lock().unwrap(); // Lock
|
|
||||||
if process.is_alive() {
|
|
||||||
process.input.push(buffer);
|
|
||||||
} // Push only if alive
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Arguments
|
|
||||||
if !self.simple {
|
if !self.simple {
|
||||||
debug!("XMRig Tab | Rendering [Arguments]");
|
debug!("XMRig Tab | Rendering [Arguments]");
|
||||||
ui.group(|ui| {
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (size.x / 10.0) - SPACE;
|
start_options_field(
|
||||||
ui.add_sized([width, text_edit], Label::new("Command arguments:"));
|
ui,
|
||||||
ui.add_sized(
|
&mut self.arguments,
|
||||||
[ui.available_width(), text_edit],
|
|
||||||
TextEdit::hint_text(
|
|
||||||
TextEdit::singleline(&mut self.arguments),
|
|
||||||
r#"--url <...> --user <...> --config <...>"#,
|
r#"--url <...> --user <...> --config <...>"#,
|
||||||
),
|
XMRIG_ARGUMENTS,
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_ARGUMENTS);
|
|
||||||
self.arguments.truncate(1024);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
ui.add_enabled_ui(self.arguments.is_empty(), |ui|{
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Address
|
|
||||||
debug!("XMRig Tab | Rendering [Address]");
|
|
||||||
ui.group(|ui| {
|
|
||||||
let width = size.x - SPACE;
|
|
||||||
ui.spacing_mut().text_edit_width = (width) - (SPACE * 3.0);
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.address.len());
|
|
||||||
if self.address.is_empty() {
|
|
||||||
text = format!("Monero Address [{}/95] ➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
} else if Regexes::addr_ok(&self.address) {
|
|
||||||
text = format!("Monero Address [{}/95] ✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("Monero Address [{}/95] ❌", len);
|
|
||||||
color = RED;
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Label::new(RichText::new(text).color(color)),
|
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
TextEdit::hint_text(TextEdit::singleline(&mut self.address), "4..."),
|
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_ADDRESS);
|
|
||||||
self.address.truncate(95);
|
|
||||||
});
|
});
|
||||||
|
ui.add_enabled_ui(self.arguments.is_empty(), |ui| {
|
||||||
|
debug!("XMRig Tab | Rendering [Address]");
|
||||||
|
monero_address_field(&mut self.address, ui, XMRIG_ADDRESS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Threads
|
|
||||||
if self.simple {
|
if self.simple {
|
||||||
ui.add_space(SPACE);
|
ui.add_space(SPACE);
|
||||||
}
|
}
|
||||||
debug!("XMRig Tab | Rendering [Threads]");
|
debug!("XMRig Tab | Rendering [Threads]");
|
||||||
ui.vertical(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
let width = size.x / 10.0;
|
ui.set_max_width(ui.available_width() * 0.75);
|
||||||
let text_width = width * 2.4;
|
slider_state_field(
|
||||||
ui.spacing_mut().slider_width = width * 6.5;
|
ui,
|
||||||
ui.spacing_mut().icon_width = width / 25.0;
|
&format!("Threads [1-{}]:", self.max_threads),
|
||||||
ui.horizontal(|ui| {
|
XMRIG_THREADS,
|
||||||
ui.add_sized(
|
&mut self.current_threads,
|
||||||
[text_width, text_edit],
|
1..=self.max_threads,
|
||||||
Label::new(format!("Threads [1-{}]:", self.max_threads)),
|
|
||||||
);
|
);
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Slider::new(&mut self.current_threads, 1..=self.max_threads),
|
|
||||||
)
|
|
||||||
.on_hover_text(XMRIG_THREADS);
|
|
||||||
});
|
|
||||||
#[cfg(not(target_os = "linux"))] // Pause on active isn't supported on Linux
|
#[cfg(not(target_os = "linux"))] // Pause on active isn't supported on Linux
|
||||||
ui.horizontal(|ui| {
|
slider_state_field(
|
||||||
ui.add_sized(
|
ui,
|
||||||
[text_width, text_edit],
|
"Pause on active [0-255]:",
|
||||||
Label::new("Pause on active [0-255]:".to_string()),
|
&format!("{} [{}] seconds.", XMRIG_PAUSE, self.pause),
|
||||||
|
&mut self.pause,
|
||||||
|
0..=255,
|
||||||
);
|
);
|
||||||
ui.add_sized([width, text_edit], Slider::new(&mut self.pause, 0..=255))
|
|
||||||
.on_hover_text(format!("{} [{}] seconds.", XMRIG_PAUSE, self.pause));
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Simple
|
|
||||||
if !self.simple {
|
if !self.simple {
|
||||||
debug!("XMRig Tab | Rendering [Pool List] elements");
|
debug!("XMRig Tab | Rendering [Pool List] elements");
|
||||||
let width = ui.available_width() - 10.0;
|
|
||||||
let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
|
let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
|
||||||
// [Pool IP/Port]
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let width = width/10.0;
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.spacing_mut().text_edit_width = width*3.32;
|
if !self.name_field(ui) {
|
||||||
ui.horizontal(|ui| {
|
incorrect_input = false;
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.name.len());
|
|
||||||
if self.name.is_empty() {
|
|
||||||
text = format!("Name [ {}/30 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.name.is_match(&self.name) {
|
|
||||||
text = format!("Name [ {}/30 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("Name [ {}/30 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.ip_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.name).on_hover_text(XMRIG_NAME);
|
incorrect_input = false;
|
||||||
self.name.truncate(30);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:03}", self.ip.len());
|
|
||||||
if self.ip.is_empty() {
|
|
||||||
text = format!(" IP [{}/255]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if self.ip == "localhost" || REGEXES.ipv4.is_match(&self.ip) || REGEXES.domain.is_match(&self.ip) {
|
|
||||||
text = format!(" IP [{}/255]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!(" IP [{}/255]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.rpc_port_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.ip).on_hover_text(XMRIG_IP);
|
incorrect_input = false;
|
||||||
self.ip.truncate(255);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = self.port.len();
|
|
||||||
if self.port.is_empty() {
|
|
||||||
text = format!("Port [ {}/5 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.port.is_match(&self.port) {
|
|
||||||
text = format!("Port [ {}/5 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("Port [ {}/5 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.rig_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.port).on_hover_text(XMRIG_PORT);
|
incorrect_input = false;
|
||||||
self.port.truncate(5);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.rig.len());
|
|
||||||
if self.rig.is_empty() {
|
|
||||||
text = format!(" Rig [ {}/30 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
} else if REGEXES.name.is_match(&self.rig) {
|
|
||||||
text = format!(" Rig [ {}/30 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!(" Rig [ {}/30 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
|
||||||
ui.text_edit_singleline(&mut self.rig).on_hover_text(XMRIG_RIG);
|
|
||||||
self.rig.truncate(30);
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let width = ui.available_width();
|
list_poolnode(
|
||||||
ui.add_space(1.0);
|
ui,
|
||||||
// [Manual node selection]
|
&mut (&mut self.name, &mut self.ip, &mut self.port, &mut self.rig),
|
||||||
ui.spacing_mut().slider_width = width - 8.0;
|
&mut self.selected_pool,
|
||||||
ui.spacing_mut().icon_width = width / 25.0;
|
pool_vec,
|
||||||
// [Node List]
|
incorrect_input,
|
||||||
debug!("XMRig Tab | Rendering [Node List] ComboBox");
|
);
|
||||||
let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
|
|
||||||
ComboBox::from_id_salt("manual_pool").selected_text(text).width(width).show_ui(ui, |ui| {
|
|
||||||
for (n, (name, pool)) in pool_vec.iter().enumerate() {
|
|
||||||
let text = format!("{}. {}\n IP: {}\n Port: {}\n Rig: {}", n+1, name, pool.ip, pool.port, pool.rig);
|
|
||||||
if ui.add(SelectableLabel::new(self.selected_name == *name, text)).clicked() {
|
|
||||||
self.selected_index = n;
|
|
||||||
let pool = pool.clone();
|
|
||||||
self.selected_name.clone_from(name);
|
|
||||||
self.selected_rig.clone_from(&pool.rig);
|
|
||||||
self.selected_ip.clone_from(&pool.ip);
|
|
||||||
self.selected_port.clone_from(&pool.port);
|
|
||||||
self.name.clone_from(name);
|
|
||||||
self.rig = pool.rig;
|
|
||||||
self.ip = pool.ip;
|
|
||||||
self.port = pool.port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// [Add/Save]
|
|
||||||
let pool_vec_len = pool_vec.len();
|
|
||||||
let mut exists = false;
|
|
||||||
let mut save_diff = true;
|
|
||||||
let mut existing_index = 0;
|
|
||||||
for (name, pool) in pool_vec.iter() {
|
|
||||||
if *name == self.name {
|
|
||||||
exists = true;
|
|
||||||
if self.rig == pool.rig && self.ip == pool.ip && self.port == pool.port {
|
|
||||||
save_diff = false;
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
existing_index += 1;
|
|
||||||
}
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text = if exists { LIST_SAVE } else { LIST_ADD };
|
|
||||||
let text = format!("{}\n Currently selected pool: {}. {}\n Current amount of pools: {}/1000", text, self.selected_index+1, self.selected_name, pool_vec_len);
|
|
||||||
// If the pool already exists, show [Save] and mutate the already existing pool
|
|
||||||
if exists {
|
|
||||||
ui.add_enabled_ui(!incorrect_input && save_diff, |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
|
|
||||||
let pool = Pool {
|
|
||||||
rig: self.rig.clone(),
|
|
||||||
ip: self.ip.clone(),
|
|
||||||
port: self.port.clone(),
|
|
||||||
};
|
|
||||||
pool_vec[existing_index].1 = pool;
|
|
||||||
self.selected_name.clone_from(&self.name);
|
|
||||||
self.selected_rig.clone_from(&self.rig);
|
|
||||||
self.selected_ip.clone_from(&self.ip);
|
|
||||||
self.selected_port.clone_from(&self.port);
|
|
||||||
info!("Node | S | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", existing_index+1, self.name, self.ip, self.port, self.rig);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Else, add to the list
|
|
||||||
} else {
|
|
||||||
ui.add_enabled_ui(!incorrect_input && pool_vec_len < 1000, |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Add")).on_hover_text(text).clicked() {
|
|
||||||
let pool = Pool {
|
|
||||||
rig: self.rig.clone(),
|
|
||||||
ip: self.ip.clone(),
|
|
||||||
port: self.port.clone(),
|
|
||||||
};
|
|
||||||
pool_vec.push((self.name.clone(), pool));
|
|
||||||
self.selected_index = pool_vec_len;
|
|
||||||
self.selected_name.clone_from(&self.name);
|
|
||||||
self.selected_rig.clone_from(&self.rig);
|
|
||||||
self.selected_ip.clone_from(&self.ip);
|
|
||||||
self.selected_port.clone_from(&self.port);
|
|
||||||
info!("Node | A | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", pool_vec_len, self.name, self.ip, self.port, self.rig);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// [Delete]
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(pool_vec_len > 1, |ui|{
|
|
||||||
let text = format!("{}\n Currently selected pool: {}. {}\n Current amount of pools: {}/1000", LIST_DELETE, self.selected_index+1, self.selected_name, pool_vec_len);
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Delete")).on_hover_text(text).clicked() {
|
|
||||||
let new_name;
|
|
||||||
let new_pool;
|
|
||||||
match self.selected_index {
|
|
||||||
0 => {
|
|
||||||
new_name = pool_vec[1].0.clone();
|
|
||||||
new_pool = pool_vec[1].1.clone();
|
|
||||||
pool_vec.remove(0);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
pool_vec.remove(self.selected_index);
|
|
||||||
self.selected_index -= 1;
|
|
||||||
new_name = pool_vec[self.selected_index].0.clone();
|
|
||||||
new_pool = pool_vec[self.selected_index].1.clone();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.selected_name.clone_from(&new_name);
|
|
||||||
self.selected_rig.clone_from(&new_pool.rig);
|
|
||||||
self.selected_ip.clone_from(&new_pool.ip);
|
|
||||||
self.selected_port.clone_from(&new_pool.port);
|
|
||||||
self.name = new_name;
|
|
||||||
self.rig = new_pool.rig;
|
|
||||||
self.ip = new_pool.ip;
|
|
||||||
self.port = new_pool.port;
|
|
||||||
info!("Node | D | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig\"{}\"]", self.selected_index, self.selected_name, self.selected_ip, self.selected_port, self.selected_rig);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(!self.name.is_empty() || !self.ip.is_empty() || !self.port.is_empty(), |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Clear")).on_hover_text(LIST_CLEAR).clicked() {
|
|
||||||
self.name.clear();
|
|
||||||
self.rig.clear();
|
|
||||||
self.ip.clear();
|
|
||||||
self.port.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.add_space(5.0);
|
ui.add_space(5.0);
|
||||||
|
|
||||||
debug!("XMRig Tab | Rendering [API] TextEdits");
|
debug!("XMRig Tab | Rendering [API] TextEdits");
|
||||||
// [HTTP API IP/Port]
|
// [HTTP API IP/Port]
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let width = width / 10.0;
|
self.api_ip_field(ui);
|
||||||
ui.spacing_mut().text_edit_width = width * 2.39;
|
self.api_port_field(ui);
|
||||||
// HTTP API
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:03}", self.api_ip.len());
|
|
||||||
if self.api_ip.is_empty() {
|
|
||||||
text = format!("HTTP API IP [{}/255]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if self.api_ip == "localhost"
|
|
||||||
|| REGEXES.ipv4.is_match(&self.api_ip)
|
|
||||||
|| REGEXES.domain.is_match(&self.api_ip)
|
|
||||||
{
|
|
||||||
text = format!("HTTP API IP [{}/255]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("HTTP API IP [{}/255]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Label::new(RichText::new(text).color(color)),
|
|
||||||
);
|
|
||||||
ui.text_edit_singleline(&mut self.api_ip)
|
|
||||||
.on_hover_text(XMRIG_API_IP);
|
|
||||||
self.api_ip.truncate(255);
|
|
||||||
});
|
});
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = self.api_port.len();
|
|
||||||
if self.api_port.is_empty() {
|
|
||||||
text = format!("HTTP API Port [ {}/5 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.port.is_match(&self.api_port) {
|
|
||||||
text = format!("HTTP API Port [ {}/5 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("HTTP API Port [ {}/5 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Label::new(RichText::new(text).color(color)),
|
|
||||||
);
|
|
||||||
ui.text_edit_singleline(&mut self.api_port)
|
|
||||||
.on_hover_text(XMRIG_API_PORT);
|
|
||||||
self.api_port.truncate(5);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
debug!("XMRig Tab | Rendering [TLS/Keepalive] buttons");
|
debug!("XMRig Tab | Rendering [TLS/Keepalive] buttons");
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
// TLS/Keepalive
|
// TLS/Keepalive
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (ui.available_width() / 2.0) - 11.0;
|
let width = (ui.available_width() / 2.0) - 11.0;
|
||||||
let height = text_edit * 2.0;
|
let height =
|
||||||
|
height_txt_before_button(ui, &egui::TextStyle::Button) * 2.0;
|
||||||
let size = vec2(width, height);
|
let size = vec2(width, height);
|
||||||
// let mut style = (*ctx.style()).clone();
|
|
||||||
// style.spacing.icon_width_inner = width / 8.0;
|
|
||||||
// style.spacing.icon_width = width / 6.0;
|
|
||||||
// style.spacing.icon_spacing = 20.0;
|
|
||||||
// ctx.set_style(style);
|
|
||||||
ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
|
ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
|
||||||
.on_hover_text(XMRIG_TLS);
|
.on_hover_text(XMRIG_TLS);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
@ -492,4 +159,51 @@ impl Xmrig {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
fn name_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" Name ")
|
||||||
|
.max_ch(30)
|
||||||
|
.help_msg(XMRIG_NAME)
|
||||||
|
.validations(&[|x| REGEXES.name.is_match(x)])
|
||||||
|
.build(ui, &mut self.name)
|
||||||
|
}
|
||||||
|
fn rpc_port_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" RPC PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(XMRIG_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, &mut self.port)
|
||||||
|
}
|
||||||
|
fn ip_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(XMRIG_IP)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, &mut self.ip)
|
||||||
|
}
|
||||||
|
fn rig_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" Name ")
|
||||||
|
.max_ch(30)
|
||||||
|
.help_msg(XMRIG_RIG)
|
||||||
|
.build(ui, &mut self.rig)
|
||||||
|
}
|
||||||
|
fn api_ip_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" API IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(XMRIG_API_IP)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, &mut self.api_ip)
|
||||||
|
}
|
||||||
|
fn api_port_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" API PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(XMRIG_API_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, &mut self.api_port)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,122 +1,78 @@
|
||||||
use egui::{
|
use egui::{Checkbox, Label, TextStyle, Ui, vec2};
|
||||||
Button, Checkbox, ComboBox, Label, RichText, SelectableLabel, TextEdit, TextStyle, Vec2, vec2,
|
|
||||||
};
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use log::{debug, info};
|
use log::debug;
|
||||||
|
|
||||||
use crate::disk::pool::Pool;
|
use crate::app::panels::middle::common::console::{console, input_args_field, start_options_field};
|
||||||
|
use crate::app::panels::middle::common::list_poolnode::list_poolnode;
|
||||||
use crate::disk::state::XmrigProxy;
|
use crate::disk::state::XmrigProxy;
|
||||||
use crate::helper::Process;
|
use crate::helper::Process;
|
||||||
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
|
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
|
||||||
use crate::regex::{REGEXES, num_lines};
|
use crate::miscs::height_txt_before_button;
|
||||||
use crate::utils::constants::DARK_GRAY;
|
use crate::regex::REGEXES;
|
||||||
use crate::{
|
use crate::{
|
||||||
GREEN, LIGHT_GRAY, LIST_ADD, LIST_CLEAR, LIST_DELETE, LIST_SAVE, RED, SPACE, XMRIG_API_IP,
|
SPACE, XMRIG_API_IP, XMRIG_API_PORT, XMRIG_IP, XMRIG_KEEPALIVE, XMRIG_NAME, XMRIG_PORT,
|
||||||
XMRIG_API_PORT, XMRIG_IP, XMRIG_KEEPALIVE, XMRIG_NAME, XMRIG_PORT, XMRIG_PROXY_ARGUMENTS,
|
XMRIG_PROXY_ARGUMENTS, XMRIG_PROXY_INPUT, XMRIG_PROXY_REDIRECT, XMRIG_PROXY_URL, XMRIG_RIG,
|
||||||
XMRIG_PROXY_INPUT, XMRIG_PROXY_REDIRECT, XMRIG_PROXY_URL, XMRIG_RIG, XMRIG_TLS,
|
XMRIG_TLS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::common::list_poolnode::PoolNode;
|
||||||
|
use super::common::state_edit_field::StateTextEdit;
|
||||||
|
|
||||||
impl XmrigProxy {
|
impl XmrigProxy {
|
||||||
#[inline(always)] // called once
|
#[inline(always)] // called once
|
||||||
pub fn show(
|
pub fn show(
|
||||||
&mut self,
|
&mut self,
|
||||||
process: &Arc<Mutex<Process>>,
|
process: &Arc<Mutex<Process>>,
|
||||||
pool_vec: &mut Vec<(String, Pool)>,
|
pool_vec: &mut Vec<(String, PoolNode)>,
|
||||||
api: &Arc<Mutex<PubXmrigProxyApi>>,
|
api: &Arc<Mutex<PubXmrigProxyApi>>,
|
||||||
buffer: &mut String,
|
buffer: &mut String,
|
||||||
size: Vec2,
|
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
) {
|
) {
|
||||||
let width = size.x;
|
|
||||||
let height = size.y;
|
|
||||||
let space_h = height / 48.0;
|
|
||||||
let text_edit = size.y / 25.0;
|
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
||||||
ui.hyperlink_to("XMRig-Proxy", XMRIG_PROXY_URL);
|
ui.hyperlink_to("XMRig-Proxy", XMRIG_PROXY_URL);
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Body);
|
ui.style_mut().override_text_style = Some(TextStyle::Body);
|
||||||
ui.add(Label::new("High performant proxy for your miners"));
|
ui.add(Label::new("High performant proxy for your miners"));
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
});
|
});
|
||||||
// console output for log
|
// console output for log
|
||||||
debug!("Xmrig-Proxy Tab | Rendering [Console]");
|
debug!("Xmrig-Proxy Tab | Rendering [Console]");
|
||||||
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let text = &api.lock().unwrap().output;
|
let text = &api.lock().unwrap().output;
|
||||||
let nb_lines = num_lines(text);
|
console(ui, 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(egui::TextStyle::Small
|
|
||||||
);
|
|
||||||
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::Small),
|
|
||||||
nb_lines,
|
|
||||||
|ui, row_range| {
|
|
||||||
for i in row_range {
|
|
||||||
if let Some(line) = text.lines().nth(i) {
|
|
||||||
ui.label(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
//---------------------------------------------------------------------------------------------------- [Advanced] Console
|
//---------------------------------------------------------------------------------------------------- [Advanced] Console
|
||||||
if !self.simple {
|
if !self.simple {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
let response = ui
|
input_args_field(
|
||||||
.add_sized(
|
ui,
|
||||||
[width, text_edit],
|
buffer,
|
||||||
TextEdit::hint_text(
|
process,
|
||||||
TextEdit::singleline(buffer),
|
|
||||||
r#"Commands: [h]ashrate, [c]onnections, [v]erbose, [w]orkers"#,
|
r#"Commands: [h]ashrate, [c]onnections, [v]erbose, [w]orkers"#,
|
||||||
),
|
XMRIG_PROXY_INPUT,
|
||||||
)
|
);
|
||||||
.on_hover_text(XMRIG_PROXY_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 = process.lock().unwrap(); // Lock
|
|
||||||
if process.is_alive() {
|
|
||||||
process.input.push(buffer);
|
|
||||||
} // Push only if alive
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
if !self.simple {
|
||||||
//---------------------------------------------------------------------------------------------------- Arguments
|
//---------------------------------------------------------------------------------------------------- Arguments
|
||||||
debug!("XMRig-Proxy Tab | Rendering [Arguments]");
|
debug!("XMRig-Proxy Tab | Rendering [Arguments]");
|
||||||
ui.group(|ui| {
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (size.x / 10.0) - SPACE;
|
start_options_field(
|
||||||
ui.add_sized([width, text_edit], Label::new("Command arguments:"));
|
ui,
|
||||||
ui.add_sized(
|
&mut self.arguments,
|
||||||
[ui.available_width(), text_edit],
|
|
||||||
TextEdit::hint_text(
|
|
||||||
TextEdit::singleline(&mut self.arguments),
|
|
||||||
r#"--url <...> --user <...> --config <...>"#,
|
r#"--url <...> --user <...> --config <...>"#,
|
||||||
),
|
XMRIG_PROXY_ARGUMENTS,
|
||||||
)
|
);
|
||||||
.on_hover_text(XMRIG_PROXY_ARGUMENTS);
|
|
||||||
self.arguments.truncate(1024);
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
if !self.arguments.is_empty() {
|
if !self.arguments.is_empty() {
|
||||||
ui.disable();
|
ui.disable();
|
||||||
}
|
}
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
ui.style_mut().spacing.icon_width_inner = width / 45.0;
|
// ui.style_mut().spacing.icon_width_inner = width / 45.0;
|
||||||
ui.style_mut().spacing.icon_width = width / 35.0;
|
// ui.style_mut().spacing.icon_width = width / 35.0;
|
||||||
ui.style_mut().spacing.icon_spacing = space_h;
|
// ui.style_mut().spacing.icon_spacing = space_h;
|
||||||
ui.checkbox(
|
ui.checkbox(
|
||||||
&mut self.redirect_local_xmrig,
|
&mut self.redirect_local_xmrig,
|
||||||
"Auto Redirect local Xmrig to Xmrig-Proxy",
|
"Auto Redirect local Xmrig to Xmrig-Proxy",
|
||||||
|
@ -130,220 +86,35 @@ impl XmrigProxy {
|
||||||
// need to show public ip
|
// need to show public ip
|
||||||
|
|
||||||
debug!("XMRig-Proxy Tab | Rendering [Pool List] elements");
|
debug!("XMRig-Proxy Tab | Rendering [Pool List] elements");
|
||||||
let width = ui.available_width() - 10.0;
|
// let width = ui.available_width() - 10.0;
|
||||||
let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
|
let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
|
||||||
// [Pool IP/Port]
|
// [Pool IP/Port]
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let width = width/10.0;
|
// let width = width / 10.0;
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.spacing_mut().text_edit_width = width*3.32;
|
if !self.name_field(ui) {
|
||||||
ui.horizontal(|ui| {
|
incorrect_input = false;
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.name.len());
|
|
||||||
if self.name.is_empty() {
|
|
||||||
text = format!("Name [ {}/30 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.name.is_match(&self.name) {
|
|
||||||
text = format!("Name [ {}/30 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("Name [ {}/30 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.ip_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.name).on_hover_text(XMRIG_NAME);
|
incorrect_input = false;
|
||||||
self.name.truncate(30);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:03}", self.p2pool_ip.len());
|
|
||||||
if self.p2pool_ip.is_empty() {
|
|
||||||
text = format!(" IP [{}/255]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if self.p2pool_ip == "localhost" || REGEXES.ipv4.is_match(&self.p2pool_ip) || REGEXES.domain.is_match(&self.p2pool_ip) {
|
|
||||||
text = format!(" IP [{}/255]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!(" IP [{}/255]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.rpc_port_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.p2pool_ip).on_hover_text(XMRIG_IP);
|
incorrect_input = false;
|
||||||
self.p2pool_ip.truncate(255);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = self.p2pool_port.len();
|
|
||||||
if self.p2pool_port.is_empty() {
|
|
||||||
text = format!("Port [ {}/5 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.port.is_match(&self.p2pool_port) {
|
|
||||||
text = format!("Port [ {}/5 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("Port [ {}/5 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
if !self.rig_field(ui) {
|
||||||
ui.text_edit_singleline(&mut self.p2pool_port).on_hover_text(XMRIG_PORT);
|
incorrect_input = false;
|
||||||
self.p2pool_port.truncate(5);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = format!("{:02}", self.rig.len());
|
|
||||||
if self.rig.is_empty() {
|
|
||||||
text = format!(" Rig [ {}/30 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
} else if REGEXES.name.is_match(&self.rig) {
|
|
||||||
text = format!(" Rig [ {}/30 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!(" Rig [ {}/30 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
}
|
||||||
ui.add_sized([width, text_edit], Label::new(RichText::new(text).color(color)));
|
|
||||||
ui.text_edit_singleline(&mut self.rig).on_hover_text(XMRIG_RIG);
|
|
||||||
self.rig.truncate(30);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let width = ui.available_width();
|
list_poolnode(
|
||||||
ui.add_space(1.0);
|
ui,
|
||||||
// [Manual node selection]
|
&mut (&mut self.name, &mut self.ip, &mut self.port, &mut self.rig),
|
||||||
ui.spacing_mut().slider_width = width - 8.0;
|
&mut self.selected_pool,
|
||||||
ui.spacing_mut().icon_width = width / 25.0;
|
pool_vec,
|
||||||
// [Node List]
|
incorrect_input,
|
||||||
debug!("XMRig-Proxy Tab | Rendering [Node List] ComboBox");
|
);
|
||||||
let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
|
|
||||||
ComboBox::from_id_salt("manual_pool").selected_text(text).width(width).show_ui(ui, |ui| {
|
|
||||||
for (n, (name, pool)) in pool_vec.iter().enumerate() {
|
|
||||||
let text = format!("{}. {}\n IP: {}\n Port: {}\n Rig: {}", n+1, name, pool.ip, pool.port, pool.rig);
|
|
||||||
if ui.add(SelectableLabel::new(self.selected_name == *name, text)).clicked() {
|
|
||||||
self.selected_index = n;
|
|
||||||
let pool = pool.clone();
|
|
||||||
self.selected_name.clone_from(name);
|
|
||||||
self.selected_rig.clone_from(&pool.rig);
|
|
||||||
self.selected_ip.clone_from(&pool.ip);
|
|
||||||
self.selected_port.clone_from(&pool.port);
|
|
||||||
self.name.clone_from(name);
|
|
||||||
self.rig = pool.rig;
|
|
||||||
self.p2pool_ip = pool.ip;
|
|
||||||
self.p2pool_port = pool.port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// [Add/Save]
|
|
||||||
let pool_vec_len = pool_vec.len();
|
|
||||||
let mut exists = false;
|
|
||||||
let mut save_diff = true;
|
|
||||||
let mut existing_index = 0;
|
|
||||||
for (name, pool) in pool_vec.iter() {
|
|
||||||
if *name == self.name {
|
|
||||||
exists = true;
|
|
||||||
if self.rig == pool.rig && self.p2pool_ip == pool.ip && self.p2pool_port == pool.port {
|
|
||||||
save_diff = false;
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
existing_index += 1;
|
|
||||||
}
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text = if exists { LIST_SAVE } else { LIST_ADD };
|
|
||||||
let text = format!("{}\n Currently selected pool: {}. {}\n Current amount of pools: {}/1000", text, self.selected_index+1, self.selected_name, pool_vec_len);
|
|
||||||
// If the pool already exists, show [Save] and mutate the already existing pool
|
|
||||||
if exists {
|
|
||||||
ui.add_enabled_ui(!incorrect_input && save_diff, |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
|
|
||||||
let pool = Pool {
|
|
||||||
rig: self.rig.clone(),
|
|
||||||
ip: self.p2pool_ip.clone(),
|
|
||||||
port: self.p2pool_port.clone(),
|
|
||||||
};
|
|
||||||
pool_vec[existing_index].1 = pool;
|
|
||||||
self.selected_name.clone_from(&self.name);
|
|
||||||
self.selected_rig.clone_from(&self.rig);
|
|
||||||
self.selected_ip.clone_from(&self.p2pool_ip);
|
|
||||||
self.selected_port.clone_from(&self.p2pool_port);
|
|
||||||
info!("Node | S | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", existing_index+1, self.name, self.p2pool_ip, self.p2pool_port, self.rig);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
// Else, add to the list
|
|
||||||
} else {
|
|
||||||
ui.add_enabled_ui(!incorrect_input && pool_vec_len < 1000, |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Add")).on_hover_text(text).clicked() {
|
|
||||||
let pool = Pool {
|
|
||||||
rig: self.rig.clone(),
|
|
||||||
ip: self.p2pool_ip.clone(),
|
|
||||||
port: self.p2pool_port.clone(),
|
|
||||||
};
|
|
||||||
pool_vec.push((self.name.clone(), pool));
|
|
||||||
self.selected_index = pool_vec_len;
|
|
||||||
self.selected_name.clone_from(&self.name);
|
|
||||||
self.selected_rig.clone_from(&self.rig);
|
|
||||||
self.selected_ip.clone_from(&self.p2pool_ip);
|
|
||||||
self.selected_port.clone_from(&self.p2pool_port);
|
|
||||||
info!("Node | A | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig: \"{}\"]", pool_vec_len, self.name, self.p2pool_ip, self.p2pool_port, self.rig);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// [Delete]
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(pool_vec_len > 1, |ui|{
|
|
||||||
let text = format!("{}\n Currently selected pool: {}. {}\n Current amount of pools: {}/1000", LIST_DELETE, self.selected_index+1, self.selected_name, pool_vec_len);
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Delete")).on_hover_text(text).clicked() {
|
|
||||||
let new_name;
|
|
||||||
let new_pool;
|
|
||||||
match self.selected_index {
|
|
||||||
0 => {
|
|
||||||
new_name = pool_vec[1].0.clone();
|
|
||||||
new_pool = pool_vec[1].1.clone();
|
|
||||||
pool_vec.remove(0);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
pool_vec.remove(self.selected_index);
|
|
||||||
self.selected_index -= 1;
|
|
||||||
new_name = pool_vec[self.selected_index].0.clone();
|
|
||||||
new_pool = pool_vec[self.selected_index].1.clone();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.selected_name.clone_from(&new_name);
|
|
||||||
self.selected_rig.clone_from(&new_pool.rig);
|
|
||||||
self.selected_ip.clone_from(&new_pool.ip);
|
|
||||||
self.selected_port.clone_from(&new_pool.port);
|
|
||||||
self.name = new_name;
|
|
||||||
self.rig = new_pool.rig;
|
|
||||||
self.p2pool_ip = new_pool.ip;
|
|
||||||
self.p2pool_port = new_pool.port;
|
|
||||||
info!("Node | D | [index: {}, name: \"{}\", ip: \"{}\", port: {}, rig\"{}\"]", self.selected_index, self.selected_name, self.selected_ip, self.selected_port, self.selected_rig);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(!self.name.is_empty() || !self.p2pool_ip.is_empty() || !self.p2pool_port.is_empty(), |ui|{
|
|
||||||
if ui.add_sized([width, text_edit], Button::new("Clear")).on_hover_text(LIST_CLEAR).clicked() {
|
|
||||||
self.name.clear();
|
|
||||||
self.rig.clear();
|
|
||||||
self.p2pool_ip.clear();
|
|
||||||
self.p2pool_port.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -354,60 +125,9 @@ impl XmrigProxy {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let width = width / 10.0;
|
|
||||||
ui.spacing_mut().text_edit_width = width * 2.39;
|
|
||||||
// HTTP API
|
// HTTP API
|
||||||
ui.horizontal(|ui| {
|
self.api_ip_field(ui);
|
||||||
let text;
|
self.api_port_field(ui);
|
||||||
let color;
|
|
||||||
let len = format!("{:03}", self.api_ip.len());
|
|
||||||
if self.api_ip.is_empty() {
|
|
||||||
text = format!("HTTP API IP [{}/255]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if self.api_ip == "localhost"
|
|
||||||
|| REGEXES.ipv4.is_match(&self.api_ip)
|
|
||||||
|| REGEXES.domain.is_match(&self.api_ip)
|
|
||||||
{
|
|
||||||
text = format!("HTTP API IP [{}/255]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("HTTP API IP [{}/255]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Label::new(RichText::new(text).color(color)),
|
|
||||||
);
|
|
||||||
ui.text_edit_singleline(&mut self.api_ip)
|
|
||||||
.on_hover_text(XMRIG_API_IP);
|
|
||||||
self.api_ip.truncate(255);
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let text;
|
|
||||||
let color;
|
|
||||||
let len = self.api_port.len();
|
|
||||||
if self.api_port.is_empty() {
|
|
||||||
text = format!("HTTP API Port [ {}/5 ]➖", len);
|
|
||||||
color = LIGHT_GRAY;
|
|
||||||
incorrect_input = true;
|
|
||||||
} else if REGEXES.port.is_match(&self.api_port) {
|
|
||||||
text = format!("HTTP API Port [ {}/5 ]✔", len);
|
|
||||||
color = GREEN;
|
|
||||||
} else {
|
|
||||||
text = format!("HTTP API Port [ {}/5 ]❌", len);
|
|
||||||
color = RED;
|
|
||||||
incorrect_input = true;
|
|
||||||
}
|
|
||||||
ui.add_sized(
|
|
||||||
[width, text_edit],
|
|
||||||
Label::new(RichText::new(text).color(color)),
|
|
||||||
);
|
|
||||||
ui.text_edit_singleline(&mut self.api_port)
|
|
||||||
.on_hover_text(XMRIG_API_PORT);
|
|
||||||
self.api_port.truncate(5);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
@ -417,13 +137,8 @@ impl XmrigProxy {
|
||||||
// TLS/Keepalive
|
// TLS/Keepalive
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let width = (ui.available_width() / 2.0) - 11.0;
|
let width = (ui.available_width() / 2.0) - 11.0;
|
||||||
let height = text_edit * 2.0;
|
let height = height_txt_before_button(ui, &TextStyle::Button) * 2.0;
|
||||||
let size = vec2(width, height);
|
let size = vec2(width, height);
|
||||||
// let mut style = (*ctx.style()).clone();
|
|
||||||
// style.spacing.icon_width_inner = width / 8.0;
|
|
||||||
// style.spacing.icon_width = width / 6.0;
|
|
||||||
// style.spacing.icon_spacing = 20.0;
|
|
||||||
// ctx.set_style(style);
|
|
||||||
ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
|
ui.add_sized(size, Checkbox::new(&mut self.tls, "TLS Connection"))
|
||||||
.on_hover_text(XMRIG_TLS);
|
.on_hover_text(XMRIG_TLS);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
@ -436,4 +151,51 @@ impl XmrigProxy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
fn name_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" Name ")
|
||||||
|
.max_ch(30)
|
||||||
|
.help_msg(XMRIG_NAME)
|
||||||
|
.validations(&[|x| REGEXES.name.is_match(x)])
|
||||||
|
.build(ui, &mut self.name)
|
||||||
|
}
|
||||||
|
fn rpc_port_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" RPC PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(XMRIG_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, &mut self.port)
|
||||||
|
}
|
||||||
|
fn ip_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(XMRIG_IP)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, &mut self.ip)
|
||||||
|
}
|
||||||
|
fn rig_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" Name ")
|
||||||
|
.max_ch(30)
|
||||||
|
.help_msg(XMRIG_RIG)
|
||||||
|
.build(ui, &mut self.rig)
|
||||||
|
}
|
||||||
|
fn api_ip_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" API IP ")
|
||||||
|
.max_ch(255)
|
||||||
|
.help_msg(XMRIG_API_IP)
|
||||||
|
.validations(&[|x| REGEXES.ipv4.is_match(x) || REGEXES.domain.is_match(x)])
|
||||||
|
.build(ui, &mut self.api_ip)
|
||||||
|
}
|
||||||
|
fn api_port_field(&mut self, ui: &mut Ui) -> bool {
|
||||||
|
StateTextEdit::new(ui)
|
||||||
|
.description(" API PORT ")
|
||||||
|
.max_ch(5)
|
||||||
|
.help_msg(XMRIG_API_PORT)
|
||||||
|
.validations(&[|x| REGEXES.port.is_match(x)])
|
||||||
|
.build(ui, &mut self.api_port)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,33 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use egui::{Image, RichText, TextEdit, TextStyle, Ui, Vec2, vec2};
|
use egui::{Align, Image, RichText, ScrollArea, TextStyle, Ui};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use readable::num::Float;
|
use readable::num::Float;
|
||||||
use readable::up::Uptime;
|
use readable::up::Uptime;
|
||||||
|
use strum::EnumCount;
|
||||||
|
|
||||||
use crate::XVB_MINING_ON_FIELD;
|
use crate::XVB_MINING_ON_FIELD;
|
||||||
|
use crate::app::panels::middle::common::console::console;
|
||||||
|
use crate::app::panels::middle::common::header_tab::header_tab;
|
||||||
|
use crate::app::panels::middle::common::state_edit_field::StateTextEdit;
|
||||||
use crate::disk::state::{ManualDonationLevel, ManualDonationMetric, XvbMode};
|
use crate::disk::state::{ManualDonationLevel, ManualDonationMetric, XvbMode};
|
||||||
use crate::helper::xrig::xmrig::PubXmrigApi;
|
use crate::helper::xrig::xmrig::PubXmrigApi;
|
||||||
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
|
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
|
||||||
use crate::helper::xvb::PubXvbApi;
|
use crate::helper::xvb::PubXvbApi;
|
||||||
use crate::helper::xvb::priv_stats::RuntimeMode;
|
use crate::helper::xvb::priv_stats::RuntimeMode;
|
||||||
use crate::regex::num_lines;
|
use crate::miscs::height_txt_before_button;
|
||||||
use crate::utils::constants::{
|
use crate::utils::constants::{
|
||||||
GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD,
|
ORANGE, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD, XVB_DONATION_LEVEL_DONOR_HELP,
|
||||||
XVB_DONATION_LEVEL_DONOR_HELP, XVB_DONATION_LEVEL_MEGA_DONOR_HELP,
|
XVB_DONATION_LEVEL_MEGA_DONOR_HELP, XVB_DONATION_LEVEL_VIP_DONOR_HELP,
|
||||||
XVB_DONATION_LEVEL_VIP_DONOR_HELP, XVB_DONATION_LEVEL_WHALE_DONOR_HELP, XVB_FAILURE_FIELD,
|
XVB_DONATION_LEVEL_WHALE_DONOR_HELP, XVB_FAILURE_FIELD, XVB_HELP, XVB_HERO_SELECT,
|
||||||
XVB_HELP, XVB_HERO_SELECT, XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP,
|
XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP, XVB_MANUAL_SLIDER_MANUAL_XVB_HELP,
|
||||||
XVB_MANUAL_SLIDER_MANUAL_XVB_HELP, XVB_MODE_MANUAL_DONATION_LEVEL_HELP,
|
XVB_MODE_MANUAL_DONATION_LEVEL_HELP, XVB_MODE_MANUAL_P2POOL_HELP, XVB_MODE_MANUAL_XVB_HELP,
|
||||||
XVB_MODE_MANUAL_P2POOL_HELP, XVB_MODE_MANUAL_XVB_HELP, XVB_ROUND_TYPE_FIELD, XVB_TOKEN_FIELD,
|
XVB_ROUND_TYPE_FIELD, XVB_TOKEN_LEN, XVB_URL_RULES, XVB_WINNER_FIELD,
|
||||||
XVB_TOKEN_LEN, XVB_URL_RULES, XVB_WINNER_FIELD,
|
|
||||||
};
|
};
|
||||||
use crate::utils::regex::Regexes;
|
use crate::utils::regex::Regexes;
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{BYTES_XVB, SPACE},
|
constants::{BYTES_XVB, SPACE},
|
||||||
utils::constants::{DARK_GRAY, XVB_URL},
|
utils::constants::XVB_URL,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl crate::disk::state::Xvb {
|
impl crate::disk::state::Xvb {
|
||||||
|
@ -32,7 +35,6 @@ impl crate::disk::state::Xvb {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn show(
|
pub fn show(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Vec2,
|
|
||||||
address: &str,
|
address: &str,
|
||||||
_ctx: &egui::Context,
|
_ctx: &egui::Context,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
|
@ -41,96 +43,47 @@ impl crate::disk::state::Xvb {
|
||||||
gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>,
|
gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>,
|
||||||
is_alive: bool,
|
is_alive: bool,
|
||||||
) {
|
) {
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
// let text_edit = ui.available_height() / 25.0;
|
||||||
|
// let website_height = ui.available_height() / 10.0;
|
||||||
let text_edit = size.y / 25.0;
|
|
||||||
let website_height = size.y / 10.0;
|
|
||||||
let width = size.x;
|
|
||||||
let height = size.y;
|
|
||||||
let space_h = height / 48.0;
|
|
||||||
|
|
||||||
// logo and website link
|
// logo and website link
|
||||||
ui.vertical_centered(|ui| {
|
let logo = Some(Image::from_bytes("bytes:/xvb.png", BYTES_XVB));
|
||||||
ui.add_sized(
|
header_tab(
|
||||||
[width, website_height],
|
ui,
|
||||||
Image::from_bytes("bytes:/xvb.png", BYTES_XVB),
|
logo,
|
||||||
|
&[
|
||||||
|
("XMRvsBEAST", XVB_URL, ""),
|
||||||
|
(
|
||||||
|
"Rules",
|
||||||
|
XVB_URL_RULES,
|
||||||
|
"Click here to read the rules and understand how the raffle works.",
|
||||||
|
),
|
||||||
|
("FAQ", "https://xmrvsbeast.com/p2pool/faq.html", ""),
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.add_space(space_h);
|
|
||||||
ui.hyperlink_to("XMRvsBeast", XVB_URL);
|
|
||||||
ui.add_space(space_h);
|
|
||||||
});
|
|
||||||
|
|
||||||
// console output for log
|
// console output for log
|
||||||
debug!("XvB Tab | Rendering [Console]");
|
debug!("XvB Tab | Rendering [Console]");
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let text = &api.lock().unwrap().output;
|
let text = &api.lock().unwrap().output;
|
||||||
let nb_lines = num_lines(text);
|
// let nb_lines = num_lines(text);
|
||||||
let height = size.y / 2.8;
|
console(ui, text);
|
||||||
let width = size.x - (space_h / 2.0);
|
|
||||||
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
|
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Small);
|
|
||||||
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::Small),
|
|
||||||
nb_lines,
|
|
||||||
|ui, row_range| {
|
|
||||||
for i in row_range {
|
|
||||||
if let Some(line) = text.lines().nth(i) {
|
|
||||||
ui.label(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
// input token
|
// input token
|
||||||
let len_token = format!("{}", self.token.len());
|
ui.add_space(SPACE);
|
||||||
let (text, color) = if self.token.is_empty() {
|
|
||||||
(
|
|
||||||
format!("{} [{}/{}] ➖", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
|
|
||||||
LIGHT_GRAY,
|
|
||||||
)
|
|
||||||
} else if self.token.parse::<u32>().is_ok() && self.token.len() < XVB_TOKEN_LEN {
|
|
||||||
(
|
|
||||||
format!("{} [{}/{}]", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
|
|
||||||
GREEN,
|
|
||||||
)
|
|
||||||
} else if self.token.parse::<u32>().is_ok() && self.token.len() == XVB_TOKEN_LEN {
|
|
||||||
(format!("{} ✔", XVB_TOKEN_FIELD), GREEN)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
format!("{} [{}/{}] ❌", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
|
|
||||||
RED,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
ui.add_space(space_h);
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
// hovering text is difficult because egui doesn't hover over inner widget. But on disabled does.
|
ui.group(|ui|{
|
||||||
ui.group(|ui| {
|
ui.style_mut().override_text_valign = Some(Align::Center);
|
||||||
ui.colored_label(color, text)
|
// ui.set_height(height_txt_before_button(ui, &TextStyle::Body));
|
||||||
.on_hover_text(XVB_HELP);
|
self.field_token(ui);
|
||||||
ui.add(
|
|
||||||
TextEdit::singleline(&mut self.token)
|
|
||||||
.char_limit(9)
|
|
||||||
.desired_width(ui.text_style_height(&TextStyle::Body) * 9.0)
|
|
||||||
.vertical_align(egui::Align::Center),
|
|
||||||
).on_hover_text(XVB_HELP)
|
|
||||||
});
|
});
|
||||||
// .on_hover_text(XVB_HELP);
|
|
||||||
ui.add_space(height / 48.0);
|
|
||||||
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;
|
|
||||||
|
|
||||||
// --------------------------- XVB Simple -------------------------------------------
|
// --------------------------- XVB Simple -------------------------------------------
|
||||||
if self.simple {
|
if self.simple {
|
||||||
|
ui.add_space(SPACE);
|
||||||
ui.checkbox(&mut self.simple_hero_mode, "Hero Mode").on_hover_text(XVB_HERO_SELECT);
|
ui.checkbox(&mut self.simple_hero_mode, "Hero Mode").on_hover_text(XVB_HERO_SELECT);
|
||||||
// set runtime mode immediately if we are on simple mode.
|
// set runtime mode immediately if we are on simple mode.
|
||||||
if self.simple_hero_mode {
|
if self.simple_hero_mode {
|
||||||
|
@ -140,14 +93,19 @@ impl crate::disk::state::Xvb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
// --------------------------- XVB Advanced -----------------------------------------
|
// --------------------------- XVB Advanced -----------------------------------------
|
||||||
if !self.simple {
|
if !self.simple {
|
||||||
|
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.style_mut().override_text_valign = Some(Align::Center);
|
||||||
egui::ComboBox::from_label("")
|
ui.set_height(0.0);
|
||||||
|
// ui.horizontal_centered(|ui| {
|
||||||
|
ui.set_height(0.0);
|
||||||
|
let text_height = height_txt_before_button(ui, &TextStyle::Heading) * 1.4;
|
||||||
|
// let text_height = 0.0;
|
||||||
|
egui::ComboBox::from_label("").height(XvbMode::COUNT as f32 * (ui.text_style_height(&TextStyle::Button) + (ui.spacing().button_padding.y * 2.0) + ui.spacing().item_spacing.y))
|
||||||
.selected_text(self.mode.to_string())
|
.selected_text(self.mode.to_string())
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
ui.selectable_value(&mut self.mode, XvbMode::Auto,
|
ui.selectable_value(&mut self.mode, XvbMode::Auto,
|
||||||
|
@ -166,7 +124,7 @@ impl crate::disk::state::Xvb {
|
||||||
});
|
});
|
||||||
if self.mode == XvbMode::ManualXvb || self.mode == XvbMode::ManualP2pool {
|
if self.mode == XvbMode::ManualXvb || self.mode == XvbMode::ManualP2pool {
|
||||||
|
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
|
|
||||||
let default_xmrig_hashrate = match self.manual_donation_metric {
|
let default_xmrig_hashrate = match self.manual_donation_metric {
|
||||||
ManualDonationMetric::Hash => 1_000.0,
|
ManualDonationMetric::Hash => 1_000.0,
|
||||||
|
@ -203,22 +161,22 @@ impl crate::disk::state::Xvb {
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|
||||||
if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Hash, "Hash")).clicked() {
|
if ui.add_sized([0.0, text_height],egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Hash, "Hash")).clicked() {
|
||||||
self.manual_donation_metric = ManualDonationMetric::Hash;
|
self.manual_donation_metric = ManualDonationMetric::Hash;
|
||||||
self.manual_slider_amount = self.manual_amount_raw;
|
self.manual_slider_amount = self.manual_amount_raw;
|
||||||
}
|
}
|
||||||
if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Kilo, "Kilo")).clicked() {
|
if ui.add_sized([0.0, text_height],egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Kilo, "Kilo")).clicked() {
|
||||||
self.manual_donation_metric = ManualDonationMetric::Kilo;
|
self.manual_donation_metric = ManualDonationMetric::Kilo;
|
||||||
self.manual_slider_amount = self.manual_amount_raw / 1000.0;
|
self.manual_slider_amount = self.manual_amount_raw / 1000.0;
|
||||||
};
|
};
|
||||||
if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Mega, "Mega")).clicked() {
|
if ui.add_sized([0.0, text_height],egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Mega, "Mega")).clicked() {
|
||||||
self.manual_donation_metric = ManualDonationMetric::Mega;
|
self.manual_donation_metric = ManualDonationMetric::Mega;
|
||||||
self.manual_slider_amount = self.manual_amount_raw / 1_000_000.0;
|
self.manual_slider_amount = self.manual_amount_raw / 1_000_000.0;
|
||||||
};
|
};
|
||||||
|
// less menu, less metrics buttons,less space, less metrics.
|
||||||
ui.spacing_mut().slider_width = width * 0.5;
|
ui.spacing_mut().slider_width = ui.available_width() * 0.3;
|
||||||
ui.add_sized(
|
ui.add_sized(
|
||||||
[width, text_edit],
|
[ui.available_width(), text_height],
|
||||||
egui::Slider::new(&mut self.manual_slider_amount, 0.0..=(hashrate_xmrig as f64))
|
egui::Slider::new(&mut self.manual_slider_amount, 0.0..=(hashrate_xmrig as f64))
|
||||||
.text(self.manual_donation_metric.to_string())
|
.text(self.manual_donation_metric.to_string())
|
||||||
.max_decimals(3)
|
.max_decimals(3)
|
||||||
|
@ -228,6 +186,8 @@ impl crate::disk::state::Xvb {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.mode == XvbMode::ManualDonationLevel {
|
if self.mode == XvbMode::ManualDonationLevel {
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
ui.horizontal(|ui| {
|
||||||
ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::Donor,
|
ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::Donor,
|
||||||
ManualDonationLevel::Donor.to_string())
|
ManualDonationLevel::Donor.to_string())
|
||||||
.on_hover_text(XVB_DONATION_LEVEL_DONOR_HELP);
|
.on_hover_text(XVB_DONATION_LEVEL_DONOR_HELP);
|
||||||
|
@ -242,10 +202,12 @@ impl crate::disk::state::Xvb {
|
||||||
.on_hover_text(XVB_DONATION_LEVEL_MEGA_DONOR_HELP);
|
.on_hover_text(XVB_DONATION_LEVEL_MEGA_DONOR_HELP);
|
||||||
|
|
||||||
api.lock().unwrap().stats_priv.runtime_manual_donation_level = self.manual_donation_level.clone().into();
|
api.lock().unwrap().stats_priv.runtime_manual_donation_level = self.manual_donation_level.clone().into();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
ui.add_space(SPACE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Update manual_amount_raw based on slider
|
// Update manual_amount_raw based on slider
|
||||||
match self.manual_donation_metric {
|
match self.manual_donation_metric {
|
||||||
|
@ -263,18 +225,18 @@ impl crate::disk::state::Xvb {
|
||||||
// Set runtime_mode & runtime_manual_amount
|
// Set runtime_mode & runtime_manual_amount
|
||||||
api.lock().unwrap().stats_priv.runtime_mode = self.mode.clone().into();
|
api.lock().unwrap().stats_priv.runtime_mode = self.mode.clone().into();
|
||||||
api.lock().unwrap().stats_priv.runtime_manual_amount = self.manual_amount_raw;
|
api.lock().unwrap().stats_priv.runtime_manual_amount = self.manual_amount_raw;
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
|
|
||||||
// allow user to modify the buffer for p2pool
|
// allow user to modify the buffer for p2pool
|
||||||
// button
|
// button
|
||||||
ui.add_sized(
|
ui.add_sized(
|
||||||
[width, text_edit],
|
[ui.available_width() * 0.8, height_txt_before_button(ui, &TextStyle::Button)],
|
||||||
egui::Slider::new(&mut self.p2pool_buffer, -100..=100)
|
egui::Slider::new(&mut self.p2pool_buffer, -100..=100)
|
||||||
.text("% P2Pool Buffer" )
|
.text("% P2Pool Buffer" )
|
||||||
).on_hover_text("Set the % amount of additional HR to send to p2pool. Will reduce (if positive) or augment (if negative) the chances to miss the p2pool window");
|
).on_hover_text("Set the % amount of additional HR to send to p2pool. Will reduce (if positive) or augment (if negative) the chances to miss the p2pool window");
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
// need to warn the user if no address is set in p2pool tab
|
// need to warn the user if no address is set in p2pool tab
|
||||||
if !Regexes::addr_ok(address) {
|
if !Regexes::addr_ok(address) {
|
||||||
debug!("XvB Tab | Rendering warning text");
|
debug!("XvB Tab | Rendering warning text");
|
||||||
|
@ -284,100 +246,62 @@ impl crate::disk::state::Xvb {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// private stats
|
// private stats
|
||||||
ui.add_space(space_h);
|
ui.add_space(SPACE);
|
||||||
// ui.add_enabled_ui(is_alive, |ui| {
|
// ui.add_enabled_ui(is_alive, |ui| {
|
||||||
ui.add_enabled_ui(is_alive, |ui| {
|
ui.add_enabled_ui(is_alive, |ui| {
|
||||||
let api = &api.lock().unwrap();
|
let api = &api.lock().unwrap();
|
||||||
let priv_stats = &api.stats_priv;
|
let priv_stats = &api.stats_priv;
|
||||||
let current_node = &api.current_node;
|
let current_node = &api.current_node;
|
||||||
let width_stat = (ui.available_width() - SPACE * 4.0) / 5.0;
|
let style_height = ui.text_style_height(&TextStyle::Body);
|
||||||
let height_stat = 0.0;
|
ui.spacing_mut().item_spacing = [style_height * 2.0, style_height * 2.0].into();
|
||||||
let size_stat = vec2(width_stat, height_stat);
|
|
||||||
|
// let width_stat = (ui.available_width() - SPACE * 4.0) / 5.0;
|
||||||
|
let width_column = ui.text_style_height(&TextStyle::Body) * 16.0;
|
||||||
|
let height_column = 0.0;
|
||||||
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
|
ScrollArea::horizontal().id_salt("horizontal").show(ui, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
// Failures
|
||||||
|
stat_box(ui, XVB_FAILURE_FIELD, &priv_stats.fails.to_string(), width_column, height_column, style_height);
|
||||||
|
stat_box(ui, XVB_DONATED_1H_FIELD,
|
||||||
|
&[
|
||||||
|
Float::from_3(priv_stats.donor_1hr_avg as f64).to_string(),
|
||||||
|
" kH/s".to_string(),
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
, width_column, height_column, style_height);
|
||||||
|
stat_box(ui, XVB_DONATED_24H_FIELD,
|
||||||
|
&[
|
||||||
|
Float::from_3(priv_stats.donor_24hr_avg as f64).to_string(),
|
||||||
|
" kH/s".to_string(),
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
, width_column, height_column, style_height);
|
||||||
|
ui.add_enabled_ui(priv_stats.round_participate.is_some(), |ui| {
|
||||||
let round = match &priv_stats.round_participate {
|
let round = match &priv_stats.round_participate {
|
||||||
Some(r) => r.to_string(),
|
Some(r) => r.to_string(),
|
||||||
None => "None".to_string(),
|
None => "None".to_string(),
|
||||||
};
|
};
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
stat_box(ui, XVB_ROUND_TYPE_FIELD, &round, width_column, height_column, style_height);
|
||||||
ui.group(|ui| {
|
}).response
|
||||||
let size_stat = vec2(
|
|
||||||
ui.available_width(),
|
|
||||||
0.0, // + ui.spacing().item_spacing.y,
|
|
||||||
);
|
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
|
||||||
ui.label(XVB_FAILURE_FIELD);
|
|
||||||
ui.label(priv_stats.fails.to_string());
|
|
||||||
})
|
|
||||||
.response
|
|
||||||
});
|
|
||||||
ui.separator();
|
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
|
||||||
ui.label(XVB_DONATED_1H_FIELD);
|
|
||||||
ui.label(
|
|
||||||
[
|
|
||||||
Float::from_3(priv_stats.donor_1hr_avg as f64).to_string(),
|
|
||||||
" kH/s".to_string(),
|
|
||||||
]
|
|
||||||
.concat(),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.response
|
|
||||||
});
|
|
||||||
ui.separator();
|
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
|
||||||
ui.label(XVB_DONATED_24H_FIELD);
|
|
||||||
ui.label(
|
|
||||||
[
|
|
||||||
Float::from_3(priv_stats.donor_24hr_avg as f64).to_string(),
|
|
||||||
" kH/s".to_string(),
|
|
||||||
]
|
|
||||||
.concat(),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.response
|
|
||||||
});
|
|
||||||
ui.separator();
|
|
||||||
ui.add_enabled_ui(priv_stats.round_participate.is_some(), |ui| {
|
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
|
||||||
ui.label(XVB_ROUND_TYPE_FIELD);
|
|
||||||
ui.label(round);
|
|
||||||
})
|
|
||||||
.response
|
|
||||||
})
|
|
||||||
.on_disabled_hover_text(
|
.on_disabled_hover_text(
|
||||||
"You do not yet have a share in the PPLNS Window.",
|
"You do not yet have a share in the PPLNS Window.",
|
||||||
);
|
);
|
||||||
});
|
stat_box(ui, XVB_WINNER_FIELD,
|
||||||
ui.separator();
|
if priv_stats.win_current {
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
|
||||||
ui.label(XVB_WINNER_FIELD);
|
|
||||||
ui.label(if priv_stats.win_current {
|
|
||||||
"You are Winning the round !"
|
"You are Winning the round !"
|
||||||
} else {
|
} else {
|
||||||
"You are not the winner"
|
"You are not the winner"
|
||||||
});
|
}
|
||||||
})
|
, width_column, height_column, style_height);
|
||||||
.response
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.response
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// indicators
|
ui.vertical(|ui| {
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let size_stat = vec2(
|
ui.set_width(width_column);
|
||||||
ui.available_width(),
|
ui.set_height(height_column);
|
||||||
0.0, // + ui.spacing().item_spacing.y,
|
|
||||||
);
|
|
||||||
ui.add_sized(size_stat, |ui: &mut Ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(SPACE);
|
||||||
ui.label(XVB_MINING_ON_FIELD)
|
ui.label(XVB_MINING_ON_FIELD)
|
||||||
.on_hover_text_at_pointer(&priv_stats.msg_indicator);
|
.on_hover_text_at_pointer(&priv_stats.msg_indicator);
|
||||||
ui.label(
|
ui.label(
|
||||||
|
@ -389,24 +313,44 @@ impl crate::disk::state::Xvb {
|
||||||
ui.label(Uptime::from(priv_stats.time_switch_node).to_string())
|
ui.label(Uptime::from(priv_stats.time_switch_node).to_string())
|
||||||
.on_hover_text_at_pointer(&priv_stats.msg_indicator)
|
.on_hover_text_at_pointer(&priv_stats.msg_indicator)
|
||||||
})
|
})
|
||||||
.response
|
});
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.response
|
.response
|
||||||
.on_disabled_hover_text("Algorithm is not running.")
|
.on_disabled_hover_text("Algorithm is not running.");
|
||||||
|
// indicators
|
||||||
})
|
})
|
||||||
// currently mining on
|
// currently mining on
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
// Rules link help
|
fn field_token(&mut self, ui: &mut Ui) {
|
||||||
ui.horizontal_centered(|ui| {
|
StateTextEdit::new(ui)
|
||||||
// can't have horizontal and vertical centering work together so fix by this.
|
.help_msg(XVB_HELP)
|
||||||
ui.add_space((width / 2.0) - (ui.text_style_height(&TextStyle::Heading) * 1.5));
|
.max_ch(XVB_TOKEN_LEN as u8)
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
.text_edit_width_same_as_max_ch(ui)
|
||||||
ui.hyperlink_to("Rules", XVB_URL_RULES)
|
.description(" Token ")
|
||||||
.on_hover_text("Click here to read the rules and understand how the raffle works.");
|
.validations(&[|x| x.parse::<u32>().is_ok() && x.len() == XVB_TOKEN_LEN])
|
||||||
});
|
.build(ui, &mut self.token);
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn stat_box(
|
||||||
|
ui: &mut Ui,
|
||||||
|
title: &str,
|
||||||
|
value: &str,
|
||||||
|
column_width: f32,
|
||||||
|
column_height: f32,
|
||||||
|
style_height: f32,
|
||||||
|
) {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.set_width(column_width);
|
||||||
|
ui.set_height(column_height);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing = [style_height / 2.0, style_height / 2.0].into();
|
||||||
|
ui.add_space(SPACE * 3.0);
|
||||||
|
ui.label(title);
|
||||||
|
ui.label(value);
|
||||||
|
ui.add_space(SPACE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -189,7 +189,7 @@ impl crate::app::App {
|
||||||
.add_sized([width, height / 2.0], Button::new("Quit"))
|
.add_sized([width, height / 2.0], Button::new("Quit"))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
if self.state.gupax.save_before_quit {
|
if self.state.gupax.auto.save_before_quit {
|
||||||
self.save_before_quit();
|
self.save_before_quit();
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
|
@ -12,8 +12,6 @@ impl crate::app::App {
|
||||||
ui.style_mut().spacing.item_spacing.x = 4.0;
|
ui.style_mut().spacing.item_spacing.x = 4.0;
|
||||||
// spacing of separator, will reduce width size of the button. Low value so that tabs can be selected easily.
|
// spacing of separator, will reduce width size of the button. Low value so that tabs can be selected easily.
|
||||||
let spacing_separator = 2.0;
|
let spacing_separator = 2.0;
|
||||||
// TODO if screen smaller, go on two lines.
|
|
||||||
// TODO if screen really to small, go on tab per line.
|
|
||||||
ui.with_layout(egui::Layout::left_to_right(egui::Align::Min), |ui| {
|
ui.with_layout(egui::Layout::left_to_right(egui::Align::Min), |ui| {
|
||||||
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
ui.style_mut().override_text_style = Some(TextStyle::Heading);
|
||||||
let height = ui
|
let height = ui
|
||||||
|
|
|
@ -16,11 +16,11 @@ impl App {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
info!("quit");
|
info!("quit");
|
||||||
if self.state.gupax.ask_before_quit {
|
if self.state.gupax.auto.ask_before_quit {
|
||||||
// If we're already on the [ask_before_quit] screen and
|
// If we're already on the [ask_before_quit] screen and
|
||||||
// the user tried to exit again, exit.
|
// the user tried to exit again, exit.
|
||||||
if self.error_state.quit_twice {
|
if self.error_state.quit_twice {
|
||||||
if self.state.gupax.save_before_quit {
|
if self.state.gupax.auto.save_before_quit {
|
||||||
self.save_before_quit();
|
self.save_before_quit();
|
||||||
}
|
}
|
||||||
return Some(ViewportCommand::Close);
|
return Some(ViewportCommand::Close);
|
||||||
|
@ -32,7 +32,7 @@ impl App {
|
||||||
Some(ViewportCommand::CancelClose)
|
Some(ViewportCommand::CancelClose)
|
||||||
// Else, just quit.
|
// Else, just quit.
|
||||||
} else {
|
} else {
|
||||||
if self.state.gupax.save_before_quit {
|
if self.state.gupax.auto.save_before_quit {
|
||||||
self.save_before_quit();
|
self.save_before_quit();
|
||||||
}
|
}
|
||||||
Some(ViewportCommand::Close)
|
Some(ViewportCommand::Close)
|
||||||
|
|
|
@ -241,7 +241,7 @@ impl Update {
|
||||||
#[cfg(feature = "distro")]
|
#[cfg(feature = "distro")]
|
||||||
return;
|
return;
|
||||||
// verify validity of absolute path for p2pool, xmrig and xmrig-proxy only if we want to update them.
|
// verify validity of absolute path for p2pool, xmrig and xmrig-proxy only if we want to update them.
|
||||||
if og.lock().unwrap().gupax.bundled {
|
if og.lock().unwrap().gupax.auto.bundled {
|
||||||
// Check P2Pool path for safety
|
// Check P2Pool path for safety
|
||||||
// Attempt relative to absolute path
|
// Attempt relative to absolute path
|
||||||
// it's ok if file doesn't exist. User could enable bundled version for the first time.
|
// it's ok if file doesn't exist. User could enable bundled version for the first time.
|
||||||
|
@ -465,7 +465,7 @@ impl Update {
|
||||||
// arch
|
// arch
|
||||||
// standalone or bundled
|
// standalone or bundled
|
||||||
// archive extension
|
// archive extension
|
||||||
let bundle = if og.lock().unwrap().gupax.bundled {
|
let bundle = if og.lock().unwrap().gupax.auto.bundled {
|
||||||
"bundle"
|
"bundle"
|
||||||
} else {
|
} else {
|
||||||
"standalone"
|
"standalone"
|
||||||
|
@ -577,7 +577,7 @@ impl Update {
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
// if bundled, create directory for p2pool, xmrig and xmrig-proxy if not present
|
// if bundled, create directory for p2pool, xmrig and xmrig-proxy if not present
|
||||||
if og.lock().unwrap().gupax.bundled
|
if og.lock().unwrap().gupax.auto.bundled
|
||||||
&& (name == P2POOL_BINARY
|
&& (name == P2POOL_BINARY
|
||||||
|| name == XMRIG_BINARY
|
|| name == XMRIG_BINARY
|
||||||
|| name == XMRIG_PROXY_BINARY
|
|| name == XMRIG_PROXY_BINARY
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
use crate::disk::*;
|
use crate::{app::panels::middle::common::list_poolnode::PoolNode, disk::*};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
//---------------------------------------------------------------------------------------------------- [Node] Impl
|
//---------------------------------------------------------------------------------------------------- [Node] Impl
|
||||||
impl Node {
|
impl Node {
|
||||||
pub fn localhost() -> Self {
|
pub fn localhost() -> PoolNode {
|
||||||
Self {
|
PoolNode::Node(Self {
|
||||||
ip: "localhost".to_string(),
|
ip: "localhost".to_string(),
|
||||||
rpc: "18081".to_string(),
|
rpc: "18081".to_string(),
|
||||||
zmq: "18083".to_string(),
|
zmq: "18083".to_string(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_vec() -> Vec<(String, Self)> {
|
pub fn new_vec() -> Vec<(String, PoolNode)> {
|
||||||
vec![("Local Monero Node".to_string(), Self::localhost())]
|
vec![("Local Monero Node".to_string(), Self::localhost())]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_tuple() -> (String, Self) {
|
pub fn new_tuple() -> (String, PoolNode) {
|
||||||
("Local Monero Node".to_string(), Self::localhost())
|
("Local Monero Node".to_string(), Self::localhost())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert [String] to [Node] Vec
|
// Convert [String] to [Node] Vec
|
||||||
pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, Self)>, TomlError> {
|
pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, PoolNode)>, TomlError> {
|
||||||
let nodes: toml::map::Map<String, toml::Value> = match toml::de::from_str(string) {
|
let nodes: toml::map::Map<String, toml::Value> = match toml::de::from_str(string) {
|
||||||
Ok(map) => {
|
Ok(map) => {
|
||||||
info!("Node | Parse ... OK");
|
info!("Node | Parse ... OK");
|
||||||
|
@ -73,20 +73,23 @@ impl Node {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let node = Node { ip, rpc, zmq };
|
let node = Node { ip, rpc, zmq };
|
||||||
vec.push((key.clone(), node));
|
vec.push((key.clone(), PoolNode::Node(node)));
|
||||||
}
|
}
|
||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert [Vec<(String, Self)>] into [String]
|
// Convert [Vec<(String, Self)>] into [String]
|
||||||
// that can be written as a proper TOML file
|
// that can be written as a proper TOML file
|
||||||
pub fn to_string(vec: &[(String, Self)]) -> Result<String, TomlError> {
|
pub fn to_string(vec: &[(String, PoolNode)]) -> Result<String, TomlError> {
|
||||||
let mut toml = String::new();
|
let mut toml = String::new();
|
||||||
for (key, value) in vec.iter() {
|
for (key, value) in vec.iter() {
|
||||||
write!(
|
write!(
|
||||||
toml,
|
toml,
|
||||||
"[\'{}\']\nip = {:#?}\nrpc = {:#?}\nzmq = {:#?}\n\n",
|
"[\'{}\']\nip = {:#?}\nrpc = {:#?}\nzmq = {:#?}\n\n",
|
||||||
key, value.ip, value.rpc, value.zmq,
|
key,
|
||||||
|
value.ip(),
|
||||||
|
value.port(),
|
||||||
|
value.custom(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(toml)
|
Ok(toml)
|
||||||
|
@ -97,7 +100,7 @@ impl Node {
|
||||||
// |_ Create a default file if not found
|
// |_ Create a default file if not found
|
||||||
// 2. Deserialize [String] into a proper [Struct]
|
// 2. Deserialize [String] into a proper [Struct]
|
||||||
// |_ Attempt to merge if deserialization fails
|
// |_ Attempt to merge if deserialization fails
|
||||||
pub fn get(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
|
pub fn get(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
|
||||||
// Read
|
// Read
|
||||||
let file = File::Node;
|
let file = File::Node;
|
||||||
let string = match read_to_string(file, path) {
|
let string = match read_to_string(file, path) {
|
||||||
|
@ -114,7 +117,7 @@ impl Node {
|
||||||
|
|
||||||
// Completely overwrite current [node.toml]
|
// Completely overwrite current [node.toml]
|
||||||
// with a new default version, and return [Vec<String, Self>].
|
// with a new default version, and return [Vec<String, Self>].
|
||||||
pub fn create_new(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
|
pub fn create_new(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
|
||||||
info!("Node | Creating new default...");
|
info!("Node | Creating new default...");
|
||||||
let new = Self::new_vec();
|
let new = Self::new_vec();
|
||||||
let string = Self::to_string(&Self::new_vec())?;
|
let string = Self::to_string(&Self::new_vec())?;
|
||||||
|
@ -124,7 +127,7 @@ impl Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save [Node] onto disk file [node.toml]
|
// Save [Node] onto disk file [node.toml]
|
||||||
pub fn save(vec: &[(String, Self)], path: &PathBuf) -> Result<(), TomlError> {
|
pub fn save(vec: &[(String, PoolNode)], path: &PathBuf) -> Result<(), TomlError> {
|
||||||
info!("Node | Saving to disk ... [{}]", path.display());
|
info!("Node | Saving to disk ... [{}]", path.display());
|
||||||
let string = Self::to_string(vec)?;
|
let string = Self::to_string(vec)?;
|
||||||
match fs::write(path, string) {
|
match fs::write(path, string) {
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
|
use crate::app::panels::middle::common::list_poolnode::PoolNode;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
//---------------------------------------------------------------------------------------------------- [Pool] impl
|
//---------------------------------------------------------------------------------------------------- [Pool] impl
|
||||||
impl Pool {
|
impl Pool {
|
||||||
pub fn p2pool() -> Self {
|
pub fn p2pool() -> PoolNode {
|
||||||
Self {
|
PoolNode::Pool(Self {
|
||||||
rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
||||||
ip: "localhost".to_string(),
|
ip: "localhost".to_string(),
|
||||||
port: "3333".to_string(),
|
port: "3333".to_string(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_vec() -> Vec<(String, Self)> {
|
pub fn new_vec() -> Vec<(String, PoolNode)> {
|
||||||
vec![("Local P2Pool".to_string(), Self::p2pool())]
|
vec![("Local P2Pool".to_string(), Self::p2pool())]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_tuple() -> (String, Self) {
|
pub fn new_tuple() -> (String, PoolNode) {
|
||||||
("Local P2Pool".to_string(), Self::p2pool())
|
("Local P2Pool".to_string(), Self::p2pool())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, Self)>, TomlError> {
|
pub fn from_str_to_vec(string: &str) -> Result<Vec<(String, PoolNode)>, TomlError> {
|
||||||
let pools: toml::map::Map<String, toml::Value> = match toml::de::from_str(string) {
|
let pools: toml::map::Map<String, toml::Value> = match toml::de::from_str(string) {
|
||||||
Ok(map) => {
|
Ok(map) => {
|
||||||
info!("Pool | Parse ... OK");
|
info!("Pool | Parse ... OK");
|
||||||
|
@ -72,24 +74,27 @@ impl Pool {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let pool = Pool { rig, ip, port };
|
let pool = Pool { rig, ip, port };
|
||||||
vec.push((key.clone(), pool));
|
vec.push((key.clone(), PoolNode::Pool(pool)));
|
||||||
}
|
}
|
||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string(vec: &[(String, Self)]) -> Result<String, TomlError> {
|
pub fn to_string(vec: &[(String, PoolNode)]) -> Result<String, TomlError> {
|
||||||
let mut toml = String::new();
|
let mut toml = String::new();
|
||||||
for (key, value) in vec.iter() {
|
for (key, value) in vec.iter() {
|
||||||
write!(
|
write!(
|
||||||
toml,
|
toml,
|
||||||
"[\'{}\']\nrig = {:#?}\nip = {:#?}\nport = {:#?}\n\n",
|
"[\'{}\']\nrig = {:#?}\nip = {:#?}\nport = {:#?}\n\n",
|
||||||
key, value.rig, value.ip, value.port,
|
key,
|
||||||
|
value.custom(),
|
||||||
|
value.ip(),
|
||||||
|
value.port(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(toml)
|
Ok(toml)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
|
pub fn get(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
|
||||||
// Read
|
// Read
|
||||||
let file = File::Pool;
|
let file = File::Pool;
|
||||||
let string = match read_to_string(file, path) {
|
let string = match read_to_string(file, path) {
|
||||||
|
@ -104,7 +109,7 @@ impl Pool {
|
||||||
Self::from_str_to_vec(&string)
|
Self::from_str_to_vec(&string)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_new(path: &PathBuf) -> Result<Vec<(String, Self)>, TomlError> {
|
pub fn create_new(path: &PathBuf) -> Result<Vec<(String, PoolNode)>, TomlError> {
|
||||||
info!("Pool | Creating new default...");
|
info!("Pool | Creating new default...");
|
||||||
let new = Self::new_vec();
|
let new = Self::new_vec();
|
||||||
let string = Self::to_string(&Self::new_vec())?;
|
let string = Self::to_string(&Self::new_vec())?;
|
||||||
|
@ -113,7 +118,7 @@ impl Pool {
|
||||||
Ok(new)
|
Ok(new)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(vec: &[(String, Self)], path: &PathBuf) -> Result<(), TomlError> {
|
pub fn save(vec: &[(String, PoolNode)], path: &PathBuf) -> Result<(), TomlError> {
|
||||||
info!("Pool | Saving to disk ... [{}]", path.display());
|
info!("Pool | Saving to disk ... [{}]", path.display());
|
||||||
let string = Self::to_string(vec)?;
|
let string = Self::to_string(vec)?;
|
||||||
match fs::write(path, string) {
|
match fs::write(path, string) {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rand::{Rng, distributions::Alphanumeric, thread_rng};
|
use rand::{Rng, distributions::Alphanumeric, thread_rng};
|
||||||
|
use strum::{EnumCount, EnumIter};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{components::node::RemoteNode, disk::status::*};
|
use crate::{components::node::RemoteNode, disk::status::*, helper::ProcessName};
|
||||||
//---------------------------------------------------------------------------------------------------- [State] Impl
|
//---------------------------------------------------------------------------------------------------- [State] Impl
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -12,7 +13,7 @@ impl Default for State {
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let max_threads = benri::threads!();
|
let max_threads = benri::threads!() as u16;
|
||||||
let current_threads = if max_threads == 1 { 1 } else { max_threads / 2 };
|
let current_threads = if max_threads == 1 { 1 } else { max_threads / 2 };
|
||||||
Self {
|
Self {
|
||||||
status: Status::default(),
|
status: Status::default(),
|
||||||
|
@ -132,7 +133,6 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take [String] as input, merge it with whatever the current [default] is,
|
// Take [String] as input, merge it with whatever the current [default] is,
|
||||||
// leaving behind old keys+values and updating [default] with old valid ones.
|
// leaving behind old keys+values and updating [default] with old valid ones.
|
||||||
pub fn merge(old: &str) -> Result<Self, TomlError> {
|
pub fn merge(old: &str) -> Result<Self, TomlError> {
|
||||||
|
@ -179,14 +179,7 @@ pub struct Status {
|
||||||
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
pub struct Gupax {
|
pub struct Gupax {
|
||||||
pub simple: bool,
|
pub simple: bool,
|
||||||
pub auto_update: bool,
|
pub auto: AutoEnabled,
|
||||||
pub auto_p2pool: bool,
|
|
||||||
pub auto_node: bool,
|
|
||||||
pub auto_xmrig: bool,
|
|
||||||
pub auto_xp: bool,
|
|
||||||
pub auto_xvb: bool,
|
|
||||||
pub ask_before_quit: bool,
|
|
||||||
pub save_before_quit: bool,
|
|
||||||
pub p2pool_path: String,
|
pub p2pool_path: String,
|
||||||
pub node_path: String,
|
pub node_path: String,
|
||||||
pub xmrig_path: String,
|
pub xmrig_path: String,
|
||||||
|
@ -200,9 +193,94 @@ pub struct Gupax {
|
||||||
pub selected_scale: f32,
|
pub selected_scale: f32,
|
||||||
pub tab: Tab,
|
pub tab: Tab,
|
||||||
pub ratio: Ratio,
|
pub ratio: Ratio,
|
||||||
pub bundled: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct AutoEnabled {
|
||||||
|
pub update: bool,
|
||||||
|
pub bundled: bool,
|
||||||
|
pub ask_before_quit: bool,
|
||||||
|
pub save_before_quit: bool,
|
||||||
|
pub processes: Vec<ProcessName>,
|
||||||
|
}
|
||||||
|
impl AutoEnabled {
|
||||||
|
pub fn enable(&mut self, auto: &AutoStart, enable: bool) {
|
||||||
|
match auto {
|
||||||
|
AutoStart::Update => self.update = enable,
|
||||||
|
AutoStart::Bundle => self.bundled = enable,
|
||||||
|
AutoStart::AskBeforeQuit => self.ask_before_quit = enable,
|
||||||
|
AutoStart::SaveBeforequit => self.save_before_quit = enable,
|
||||||
|
AutoStart::Process(p) => {
|
||||||
|
let processes = &mut self.processes;
|
||||||
|
if !processes.iter().any(|a| a == p) && enable {
|
||||||
|
self.processes.push(*p);
|
||||||
|
} else if let Some(i) = processes.iter().position(|a| a == p) {
|
||||||
|
if !enable {
|
||||||
|
processes.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_enabled(&self, auto: &AutoStart) -> bool {
|
||||||
|
match auto {
|
||||||
|
AutoStart::Update => self.update,
|
||||||
|
AutoStart::Bundle => self.bundled,
|
||||||
|
AutoStart::AskBeforeQuit => self.ask_before_quit,
|
||||||
|
AutoStart::SaveBeforequit => self.save_before_quit,
|
||||||
|
AutoStart::Process(p) => self.processes.iter().any(|a| a == p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(PartialEq, strum::Display, EnumCount, EnumIter)]
|
||||||
|
pub enum AutoStart {
|
||||||
|
#[strum(to_string = "Auto-Update")]
|
||||||
|
Update,
|
||||||
|
Bundle,
|
||||||
|
#[strum(to_string = "Confirm quit")]
|
||||||
|
AskBeforeQuit,
|
||||||
|
#[strum(to_string = "Save on exit")]
|
||||||
|
SaveBeforequit,
|
||||||
|
#[strum(to_string = "Auto-{0}")]
|
||||||
|
Process(ProcessName),
|
||||||
|
}
|
||||||
|
impl AutoStart {
|
||||||
|
pub const fn help_msg(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
AutoStart::Update => GUPAX_AUTO_UPDATE,
|
||||||
|
AutoStart::Bundle => GUPAX_BUNDLED_UPDATE,
|
||||||
|
AutoStart::AskBeforeQuit => GUPAX_ASK_BEFORE_QUIT,
|
||||||
|
AutoStart::SaveBeforequit => GUPAX_SAVE_BEFORE_QUIT,
|
||||||
|
AutoStart::Process(p) => p.msg_auto_help(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// todo: generate as const with all process in middle ?
|
||||||
|
// Would necessities unstable feature https://github.com/rust-lang/rust/issues/87575
|
||||||
|
pub const ALL: &[AutoStart] = &[
|
||||||
|
AutoStart::Update,
|
||||||
|
AutoStart::Bundle,
|
||||||
|
AutoStart::Process(ProcessName::Node),
|
||||||
|
AutoStart::Process(ProcessName::P2pool),
|
||||||
|
AutoStart::Process(ProcessName::Xmrig),
|
||||||
|
AutoStart::Process(ProcessName::XmrigProxy),
|
||||||
|
AutoStart::Process(ProcessName::Xvb),
|
||||||
|
AutoStart::AskBeforeQuit,
|
||||||
|
AutoStart::SaveBeforequit,
|
||||||
|
];
|
||||||
|
// non const:
|
||||||
|
// let mut autos = AutoStart::iter().collect::<Vec<_>>();
|
||||||
|
// // remove ProcessName default
|
||||||
|
// autos.remove(AutoStart::COUNT - 1);
|
||||||
|
// // insert ProcessName before AskBeforeQuit
|
||||||
|
// let before_quit_index = autos
|
||||||
|
// .iter()
|
||||||
|
// .position(|a| *a == AutoStart::AskBeforeQuit)
|
||||||
|
// .expect("Before quit should be in iter");
|
||||||
|
// ProcessName::iter()
|
||||||
|
// .rev()
|
||||||
|
// .for_each(|p| autos.insert(before_quit_index, AutoStart::Process(p)));
|
||||||
|
// autos
|
||||||
|
}
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
pub struct P2pool {
|
pub struct P2pool {
|
||||||
pub simple: bool,
|
pub simple: bool,
|
||||||
|
@ -213,7 +291,7 @@ pub struct P2pool {
|
||||||
pub backup_host: bool,
|
pub backup_host: bool,
|
||||||
pub out_peers: u16,
|
pub out_peers: u16,
|
||||||
pub in_peers: u16,
|
pub in_peers: u16,
|
||||||
pub log_level: u8,
|
pub log_level: u16,
|
||||||
pub node: String,
|
pub node: String,
|
||||||
pub arguments: String,
|
pub arguments: String,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
|
@ -221,11 +299,17 @@ pub struct P2pool {
|
||||||
pub ip: String,
|
pub ip: String,
|
||||||
pub rpc: String,
|
pub rpc: String,
|
||||||
pub zmq: String,
|
pub zmq: String,
|
||||||
pub selected_index: usize,
|
pub selected_node: SelectedPoolNode,
|
||||||
pub selected_name: String,
|
}
|
||||||
pub selected_ip: String,
|
|
||||||
pub selected_rpc: String,
|
// compatible for P2Pool and Xmrig/Proxy
|
||||||
pub selected_zmq: String,
|
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct SelectedPoolNode {
|
||||||
|
pub index: usize,
|
||||||
|
pub name: String,
|
||||||
|
pub ip: String,
|
||||||
|
pub rpc: String,
|
||||||
|
pub zmq_rig: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
|
@ -235,7 +319,7 @@ pub struct Node {
|
||||||
pub api_port: String,
|
pub api_port: String,
|
||||||
pub out_peers: u16,
|
pub out_peers: u16,
|
||||||
pub in_peers: u16,
|
pub in_peers: u16,
|
||||||
pub log_level: u8,
|
pub log_level: u16,
|
||||||
pub arguments: String,
|
pub arguments: String,
|
||||||
pub zmq_ip: String,
|
pub zmq_ip: String,
|
||||||
pub zmq_port: String,
|
pub zmq_port: String,
|
||||||
|
@ -268,13 +352,13 @@ impl Default for Node {
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
pub struct Xmrig {
|
pub struct Xmrig {
|
||||||
pub simple: bool,
|
pub simple: bool,
|
||||||
pub pause: u8,
|
pub pause: u16,
|
||||||
pub simple_rig: String,
|
pub simple_rig: String,
|
||||||
pub arguments: String,
|
pub arguments: String,
|
||||||
pub tls: bool,
|
pub tls: bool,
|
||||||
pub keepalive: bool,
|
pub keepalive: bool,
|
||||||
pub max_threads: usize,
|
pub max_threads: u16,
|
||||||
pub current_threads: usize,
|
pub current_threads: u16,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
pub api_ip: String,
|
pub api_ip: String,
|
||||||
pub api_port: String,
|
pub api_port: String,
|
||||||
|
@ -282,11 +366,7 @@ pub struct Xmrig {
|
||||||
pub rig: String,
|
pub rig: String,
|
||||||
pub ip: String,
|
pub ip: String,
|
||||||
pub port: String,
|
pub port: String,
|
||||||
pub selected_index: usize,
|
pub selected_pool: SelectedPoolNode,
|
||||||
pub selected_name: String,
|
|
||||||
pub selected_rig: String,
|
|
||||||
pub selected_ip: String,
|
|
||||||
pub selected_port: String,
|
|
||||||
pub token: String,
|
pub token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,15 +387,41 @@ pub struct XmrigProxy {
|
||||||
pub api_port: String,
|
pub api_port: String,
|
||||||
pub p2pool_ip: String,
|
pub p2pool_ip: String,
|
||||||
pub p2pool_port: String,
|
pub p2pool_port: String,
|
||||||
pub selected_index: usize,
|
pub selected_pool: SelectedPoolNode,
|
||||||
pub selected_name: String,
|
|
||||||
pub selected_rig: String,
|
|
||||||
pub selected_ip: String,
|
|
||||||
pub selected_port: String,
|
|
||||||
pub token: String,
|
pub token: String,
|
||||||
pub redirect_local_xmrig: bool,
|
pub redirect_local_xmrig: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Gupax {
|
||||||
|
pub fn path_binary(&mut self, process: &BundledProcess) -> &mut String {
|
||||||
|
match process {
|
||||||
|
BundledProcess::Node => &mut self.node_path,
|
||||||
|
BundledProcess::P2Pool => &mut self.p2pool_path,
|
||||||
|
BundledProcess::Xmrig => &mut self.xmrig_path,
|
||||||
|
BundledProcess::XmrigProxy => &mut self.xmrig_proxy_path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not include process that are from Gupaxx
|
||||||
|
#[derive(EnumIter)]
|
||||||
|
pub enum BundledProcess {
|
||||||
|
Node,
|
||||||
|
P2Pool,
|
||||||
|
Xmrig,
|
||||||
|
XmrigProxy,
|
||||||
|
}
|
||||||
|
impl BundledProcess {
|
||||||
|
pub fn process_name(&self) -> ProcessName {
|
||||||
|
match self {
|
||||||
|
BundledProcess::Node => ProcessName::Node,
|
||||||
|
BundledProcess::P2Pool => ProcessName::P2pool,
|
||||||
|
BundledProcess::Xmrig => ProcessName::Xmrig,
|
||||||
|
BundledProcess::XmrigProxy => ProcessName::XmrigProxy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for XmrigProxy {
|
impl Default for XmrigProxy {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
XmrigProxy {
|
XmrigProxy {
|
||||||
|
@ -335,11 +441,13 @@ impl Default for XmrigProxy {
|
||||||
port: "3355".to_string(),
|
port: "3355".to_string(),
|
||||||
p2pool_ip: "localhost".to_string(),
|
p2pool_ip: "localhost".to_string(),
|
||||||
p2pool_port: "3333".to_string(),
|
p2pool_port: "3333".to_string(),
|
||||||
selected_index: 0,
|
selected_pool: SelectedPoolNode {
|
||||||
selected_name: "Local P2Pool".to_string(),
|
index: 0,
|
||||||
selected_ip: "localhost".to_string(),
|
name: "Local P2Pool".to_string(),
|
||||||
selected_rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
ip: "localhost".to_string(),
|
||||||
selected_port: "3333".to_string(),
|
rpc: "3333".to_string(),
|
||||||
|
zmq_rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
||||||
|
},
|
||||||
api_ip: "localhost".to_string(),
|
api_ip: "localhost".to_string(),
|
||||||
api_port: "18089".to_string(),
|
api_port: "18089".to_string(),
|
||||||
tls: false,
|
tls: false,
|
||||||
|
@ -361,7 +469,7 @@ pub struct Xvb {
|
||||||
pub p2pool_buffer: i8,
|
pub p2pool_buffer: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)]
|
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default, EnumCount, EnumIter)]
|
||||||
pub enum XvbMode {
|
pub enum XvbMode {
|
||||||
#[default]
|
#[default]
|
||||||
Auto,
|
Auto,
|
||||||
|
@ -435,6 +543,20 @@ pub struct Version {
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [State] Defaults
|
//---------------------------------------------------------------------------------------------------- [State] Defaults
|
||||||
|
impl Default for AutoEnabled {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
update: false,
|
||||||
|
#[cfg(feature = "bundle")]
|
||||||
|
bundled: true,
|
||||||
|
#[cfg(not(feature = "bundle"))]
|
||||||
|
bundled: false,
|
||||||
|
ask_before_quit: true,
|
||||||
|
save_before_quit: true,
|
||||||
|
processes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Default for Status {
|
impl Default for Status {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -452,14 +574,7 @@ impl Default for Gupax {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
simple: true,
|
simple: true,
|
||||||
auto_update: false,
|
auto: AutoEnabled::default(),
|
||||||
auto_p2pool: false,
|
|
||||||
auto_node: false,
|
|
||||||
auto_xmrig: false,
|
|
||||||
auto_xp: false,
|
|
||||||
auto_xvb: false,
|
|
||||||
ask_before_quit: true,
|
|
||||||
save_before_quit: true,
|
|
||||||
p2pool_path: DEFAULT_P2POOL_PATH.to_string(),
|
p2pool_path: DEFAULT_P2POOL_PATH.to_string(),
|
||||||
xmrig_path: DEFAULT_XMRIG_PATH.to_string(),
|
xmrig_path: DEFAULT_XMRIG_PATH.to_string(),
|
||||||
node_path: DEFAULT_NODE_PATH.to_string(),
|
node_path: DEFAULT_NODE_PATH.to_string(),
|
||||||
|
@ -473,10 +588,6 @@ impl Default for Gupax {
|
||||||
selected_scale: APP_DEFAULT_SCALE,
|
selected_scale: APP_DEFAULT_SCALE,
|
||||||
ratio: Ratio::Width,
|
ratio: Ratio::Width,
|
||||||
tab: Tab::Xvb,
|
tab: Tab::Xvb,
|
||||||
#[cfg(feature = "bundle")]
|
|
||||||
bundled: true,
|
|
||||||
#[cfg(not(feature = "bundle"))]
|
|
||||||
bundled: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -500,17 +611,19 @@ impl Default for P2pool {
|
||||||
ip: "localhost".to_string(),
|
ip: "localhost".to_string(),
|
||||||
rpc: "18081".to_string(),
|
rpc: "18081".to_string(),
|
||||||
zmq: "18083".to_string(),
|
zmq: "18083".to_string(),
|
||||||
selected_index: 0,
|
selected_node: SelectedPoolNode {
|
||||||
selected_name: "Local Monero Node".to_string(),
|
index: 0,
|
||||||
selected_ip: "localhost".to_string(),
|
name: "Local Monero Node".to_string(),
|
||||||
selected_rpc: "18081".to_string(),
|
ip: "localhost".to_string(),
|
||||||
selected_zmq: "18083".to_string(),
|
rpc: "18081".to_string(),
|
||||||
|
zmq_rig: "18083".to_string(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Xmrig {
|
impl Xmrig {
|
||||||
fn with_threads(max_threads: usize, current_threads: usize) -> Self {
|
fn with_threads(max_threads: u16, current_threads: u16) -> Self {
|
||||||
let xmrig = Self::default();
|
let xmrig = Self::default();
|
||||||
Self {
|
Self {
|
||||||
max_threads,
|
max_threads,
|
||||||
|
@ -531,17 +644,19 @@ impl Default for Xmrig {
|
||||||
rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
||||||
ip: "localhost".to_string(),
|
ip: "localhost".to_string(),
|
||||||
port: "3333".to_string(),
|
port: "3333".to_string(),
|
||||||
selected_index: 0,
|
|
||||||
selected_name: "Local P2Pool".to_string(),
|
|
||||||
selected_ip: "localhost".to_string(),
|
|
||||||
selected_rig: GUPAX_VERSION_UNDERSCORE.to_string(),
|
|
||||||
selected_port: "3333".to_string(),
|
|
||||||
api_ip: "localhost".to_string(),
|
api_ip: "localhost".to_string(),
|
||||||
api_port: "18088".to_string(),
|
api_port: "18088".to_string(),
|
||||||
tls: false,
|
tls: false,
|
||||||
keepalive: false,
|
keepalive: false,
|
||||||
current_threads: 1,
|
current_threads: 1,
|
||||||
max_threads: 1,
|
max_threads: 1,
|
||||||
|
selected_pool: SelectedPoolNode {
|
||||||
|
index: 0,
|
||||||
|
name: "Local Monero Node".to_string(),
|
||||||
|
ip: "localhost".to_string(),
|
||||||
|
rpc: "18081".to_string(),
|
||||||
|
zmq_rig: "18083".to_string(),
|
||||||
|
},
|
||||||
token: thread_rng()
|
token: thread_rng()
|
||||||
.sample_iter(Alphanumeric)
|
.sample_iter(Alphanumeric)
|
||||||
.take(16)
|
.take(16)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use derive_more::derive::Display;
|
||||||
|
use strum::{EnumCount, EnumIter};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
//---------------------------------------------------------------------------------------------------- [Submenu] enum for [Status] tab
|
//---------------------------------------------------------------------------------------------------- [Submenu] enum for [Status] tab
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
|
@ -25,7 +28,9 @@ impl Display for Submenu {
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [PayoutView] enum for [Status/P2Pool] tab
|
//---------------------------------------------------------------------------------------------------- [PayoutView] enum for [Status/P2Pool] tab
|
||||||
// The enum buttons for selecting which "view" to sort the payout log in.
|
// The enum buttons for selecting which "view" to sort the payout log in.
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(
|
||||||
|
Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize, Display, EnumIter, EnumCount,
|
||||||
|
)]
|
||||||
pub enum PayoutView {
|
pub enum PayoutView {
|
||||||
Latest, // Shows the most recent logs first
|
Latest, // Shows the most recent logs first
|
||||||
Oldest, // Shows the oldest logs first
|
Oldest, // Shows the oldest logs first
|
||||||
|
@ -33,6 +38,17 @@ pub enum PayoutView {
|
||||||
Smallest, // Shows lowest to highest payouts
|
Smallest, // Shows lowest to highest payouts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PayoutView {
|
||||||
|
pub const fn msg_help(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Latest => STATUS_SUBMENU_LATEST,
|
||||||
|
Self::Oldest => STATUS_SUBMENU_OLDEST,
|
||||||
|
Self::Biggest => STATUS_SUBMENU_SMALLEST,
|
||||||
|
Self::Smallest => STATUS_SUBMENU_BIGGEST,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PayoutView {
|
impl PayoutView {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self::Latest
|
Self::Latest
|
||||||
|
@ -45,12 +61,6 @@ impl Default for PayoutView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PayoutView {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(f, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [Hash] enum for [Status/P2Pool]
|
//---------------------------------------------------------------------------------------------------- [Hash] enum for [Status/P2Pool]
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
@ -110,8 +120,10 @@ impl Hash {
|
||||||
impl Display for Hash {
|
impl Display for Hash {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Hash::Hash => write!(f, "Hash"),
|
Hash::Hash => write!(f, "H/s"),
|
||||||
_ => write!(f, "{:?}hash", self),
|
Hash::Kilo => write!(f, "KH/s"),
|
||||||
|
Hash::Mega => write!(f, "MH/s"),
|
||||||
|
Hash::Giga => write!(f, "GH/s"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,13 @@ mod test {
|
||||||
ratio = "Width"
|
ratio = "Width"
|
||||||
bundled = false
|
bundled = false
|
||||||
|
|
||||||
|
[gupax.auto]
|
||||||
|
update = false
|
||||||
|
bundled = false
|
||||||
|
ask_before_quit = false
|
||||||
|
save_before_quit = true
|
||||||
|
processes = []
|
||||||
|
|
||||||
[status]
|
[status]
|
||||||
submenu = "P2pool"
|
submenu = "P2pool"
|
||||||
payout_view = "Oldest"
|
payout_view = "Oldest"
|
||||||
|
@ -76,11 +83,13 @@ mod test {
|
||||||
ip = "192.168.1.123"
|
ip = "192.168.1.123"
|
||||||
rpc = "18089"
|
rpc = "18089"
|
||||||
zmq = "18083"
|
zmq = "18083"
|
||||||
selected_index = 0
|
|
||||||
selected_name = "Local Monero Node"
|
[p2pool.selected_node]
|
||||||
selected_ip = "192.168.1.123"
|
index = 0
|
||||||
selected_rpc = "18089"
|
name = "Local Monero Node"
|
||||||
selected_zmq = "18083"
|
ip = "localhost"
|
||||||
|
rpc = "18081"
|
||||||
|
zmq_rig = "18083"
|
||||||
|
|
||||||
[xmrig]
|
[xmrig]
|
||||||
simple = true
|
simple = true
|
||||||
|
@ -98,13 +107,17 @@ mod test {
|
||||||
rig = "Gupaxx"
|
rig = "Gupaxx"
|
||||||
ip = "192.168.1.122"
|
ip = "192.168.1.122"
|
||||||
port = "3333"
|
port = "3333"
|
||||||
selected_index = 1
|
|
||||||
selected_name = "linux"
|
|
||||||
selected_rig = "Gupaxx"
|
|
||||||
selected_ip = "192.168.1.122"
|
|
||||||
selected_port = "3333"
|
|
||||||
token = "testtoken"
|
token = "testtoken"
|
||||||
|
|
||||||
|
|
||||||
|
[xmrig.selected_pool]
|
||||||
|
index = 0
|
||||||
|
name = "Local Monero Node"
|
||||||
|
ip = "localhost"
|
||||||
|
rpc = "18081"
|
||||||
|
zmq_rig = "18083"
|
||||||
|
|
||||||
|
|
||||||
[xmrig_proxy]
|
[xmrig_proxy]
|
||||||
simple = true
|
simple = true
|
||||||
arguments = ""
|
arguments = ""
|
||||||
|
@ -121,13 +134,15 @@ mod test {
|
||||||
p2pool_ip = "localhost"
|
p2pool_ip = "localhost"
|
||||||
p2pool_port = "18088"
|
p2pool_port = "18088"
|
||||||
token = "testtoken"
|
token = "testtoken"
|
||||||
selected_index = 1
|
|
||||||
selected_name = "linux"
|
|
||||||
selected_rig = "Gupaxx"
|
|
||||||
selected_ip = "192.168.1.122"
|
|
||||||
selected_port = "3333"
|
|
||||||
redirect_local_xmrig = true
|
redirect_local_xmrig = true
|
||||||
|
|
||||||
|
[xmrig_proxy.selected_pool]
|
||||||
|
index = 0
|
||||||
|
name = "Local Monero Node"
|
||||||
|
ip = "localhost"
|
||||||
|
rpc = "18081"
|
||||||
|
zmq_rig = "18083"
|
||||||
|
|
||||||
[xvb]
|
[xvb]
|
||||||
simple = true
|
simple = true
|
||||||
simple_hero_mode = true
|
simple_hero_mode = true
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
// This also includes all things related to handling the child processes (P2Pool/XMRig):
|
// This also includes all things related to handling the child processes (P2Pool/XMRig):
|
||||||
// piping their stdout/stderr/stdin, accessing their APIs (HTTP + disk files), etc.
|
// piping their stdout/stderr/stdin, accessing their APIs (HTTP + disk files), etc.
|
||||||
|
|
||||||
|
use crate::components::gupax::FileType;
|
||||||
use crate::components::update::{NODE_BINARY, P2POOL_BINARY, XMRIG_BINARY, XMRIG_PROXY_BINARY};
|
use crate::components::update::{NODE_BINARY, P2POOL_BINARY, XMRIG_BINARY, XMRIG_PROXY_BINARY};
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
|
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
|
||||||
|
@ -46,6 +47,7 @@ use log::*;
|
||||||
use node::PubNodeApi;
|
use node::PubNodeApi;
|
||||||
use portable_pty::Child;
|
use portable_pty::Child;
|
||||||
use readable::up::Uptime;
|
use readable::up::Uptime;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -54,7 +56,7 @@ use std::{
|
||||||
thread,
|
thread,
|
||||||
time::*,
|
time::*,
|
||||||
};
|
};
|
||||||
use strum::EnumIter;
|
use strum::{EnumCount, EnumIter};
|
||||||
|
|
||||||
use self::xvb::{PubXvbApi, nodes::XvbNode};
|
use self::xvb::{PubXvbApi, nodes::XvbNode};
|
||||||
pub mod node;
|
pub mod node;
|
||||||
|
@ -250,18 +252,21 @@ impl Default for ProcessSignal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, EnumIter)]
|
#[derive(
|
||||||
|
Copy, Clone, Eq, PartialEq, Debug, Display, EnumIter, EnumCount, Serialize, Deserialize, Default,
|
||||||
|
)]
|
||||||
pub enum ProcessName {
|
pub enum ProcessName {
|
||||||
Node,
|
Node,
|
||||||
P2pool,
|
P2pool,
|
||||||
Xmrig,
|
Xmrig,
|
||||||
#[display("Proxy")]
|
#[display("Proxy")]
|
||||||
XmrigProxy,
|
XmrigProxy,
|
||||||
|
#[default]
|
||||||
Xvb,
|
Xvb,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessName {
|
impl ProcessName {
|
||||||
pub fn binary_name(&self) -> &str {
|
pub const fn binary_name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
ProcessName::Node => NODE_BINARY,
|
ProcessName::Node => NODE_BINARY,
|
||||||
ProcessName::P2pool => P2POOL_BINARY,
|
ProcessName::P2pool => P2POOL_BINARY,
|
||||||
|
@ -270,6 +275,69 @@ impl ProcessName {
|
||||||
ProcessName::Xvb => "",
|
ProcessName::Xvb => "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub const fn msg_binary_path_empty(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => NODE_PATH_EMPTY,
|
||||||
|
ProcessName::P2pool => P2POOL_PATH_EMPTY,
|
||||||
|
ProcessName::Xmrig => XMRIG_PATH_EMPTY,
|
||||||
|
ProcessName::XmrigProxy => XMRIG_PROXY_PATH_EMPTY,
|
||||||
|
ProcessName::Xvb => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn msg_binary_path_not_file(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => NODE_PATH_NOT_FILE,
|
||||||
|
ProcessName::P2pool => P2POOL_PATH_NOT_FILE,
|
||||||
|
ProcessName::Xmrig => XMRIG_PATH_NOT_FILE,
|
||||||
|
ProcessName::XmrigProxy => XMRIG_PROXY_PATH_NOT_FILE,
|
||||||
|
ProcessName::Xvb => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn msg_binary_path_invalid(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => NODE_PATH_NOT_VALID,
|
||||||
|
ProcessName::P2pool => P2POOL_PATH_NOT_VALID,
|
||||||
|
ProcessName::Xmrig => XMRIG_PATH_NOT_VALID,
|
||||||
|
ProcessName::XmrigProxy => XMRIG_PROXY_PATH_NOT_VALID,
|
||||||
|
ProcessName::Xvb => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn msg_binary_path_ok(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => NODE_PATH_OK,
|
||||||
|
ProcessName::P2pool => P2POOL_PATH_OK,
|
||||||
|
ProcessName::Xmrig => XMRIG_PATH_OK,
|
||||||
|
ProcessName::XmrigProxy => XMRIG_PROXY_PATH_OK,
|
||||||
|
ProcessName::Xvb => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn msg_path_edit(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => GUPAX_PATH_NODE,
|
||||||
|
ProcessName::P2pool => GUPAX_PATH_P2POOL,
|
||||||
|
ProcessName::Xmrig => GUPAX_PATH_XMRIG,
|
||||||
|
ProcessName::XmrigProxy => GUPAX_PATH_XMRIG_PROXY,
|
||||||
|
ProcessName::Xvb => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn msg_auto_help(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => GUPAX_AUTO_NODE,
|
||||||
|
ProcessName::P2pool => GUPAX_AUTO_P2POOL,
|
||||||
|
ProcessName::Xmrig => GUPAX_AUTO_XMRIG,
|
||||||
|
ProcessName::XmrigProxy => GUPAX_AUTO_XMRIG_PROXY,
|
||||||
|
ProcessName::Xvb => GUPAX_AUTO_XVB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn file_type(&self) -> Option<FileType> {
|
||||||
|
match self {
|
||||||
|
ProcessName::Node => Some(FileType::Node),
|
||||||
|
ProcessName::P2pool => Some(FileType::P2pool),
|
||||||
|
ProcessName::Xmrig => Some(FileType::Xmrig),
|
||||||
|
ProcessName::XmrigProxy => Some(FileType::XmrigProxy),
|
||||||
|
ProcessName::Xvb => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ProcessState {
|
impl std::fmt::Display for ProcessState {
|
||||||
|
@ -374,7 +442,7 @@ impl Helper {
|
||||||
pub_sys: &mut Sys,
|
pub_sys: &mut Sys,
|
||||||
pid: &sysinfo::Pid,
|
pid: &sysinfo::Pid,
|
||||||
helper: &Helper,
|
helper: &Helper,
|
||||||
max_threads: usize,
|
max_threads: u16,
|
||||||
) {
|
) {
|
||||||
let gupax_uptime = helper.uptime.to_string();
|
let gupax_uptime = helper.uptime.to_string();
|
||||||
let cpu = &sysinfo.cpus()[0];
|
let cpu = &sysinfo.cpus()[0];
|
||||||
|
@ -416,7 +484,7 @@ impl Helper {
|
||||||
helper: &Arc<Mutex<Self>>,
|
helper: &Arc<Mutex<Self>>,
|
||||||
mut sysinfo: sysinfo::System,
|
mut sysinfo: sysinfo::System,
|
||||||
pid: sysinfo::Pid,
|
pid: sysinfo::Pid,
|
||||||
max_threads: usize,
|
max_threads: u16,
|
||||||
) {
|
) {
|
||||||
// The ordering of these locks is _very_ important. They MUST be in sync with how the main GUI thread locks stuff
|
// The ordering of these locks is _very_ important. They MUST be in sync with how the main GUI thread locks stuff
|
||||||
// or a deadlock will occur given enough time. They will eventually both want to lock the [Arc<Mutex>] the other
|
// or a deadlock will occur given enough time. They will eventually both want to lock the [Arc<Mutex>] the other
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use super::Helper;
|
use super::Helper;
|
||||||
use super::Process;
|
use super::Process;
|
||||||
|
use crate::app::panels::middle::common::list_poolnode::PoolNode;
|
||||||
use crate::components::node::RemoteNode;
|
use crate::components::node::RemoteNode;
|
||||||
use crate::disk::state::P2pool;
|
use crate::disk::state::P2pool;
|
||||||
use crate::helper::ProcessName;
|
use crate::helper::ProcessName;
|
||||||
|
@ -18,7 +19,7 @@ use crate::regex::estimated_hr;
|
||||||
use crate::regex::nb_current_shares;
|
use crate::regex::nb_current_shares;
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::*,
|
constants::*,
|
||||||
disk::{gupax_p2pool_api::GupaxP2poolApi, node::Node},
|
disk::gupax_p2pool_api::GupaxP2poolApi,
|
||||||
helper::{MONERO_BLOCK_TIME_IN_SECONDS, P2POOL_BLOCK_TIME_IN_SECONDS},
|
helper::{MONERO_BLOCK_TIME_IN_SECONDS, P2POOL_BLOCK_TIME_IN_SECONDS},
|
||||||
human::*,
|
human::*,
|
||||||
macros::*,
|
macros::*,
|
||||||
|
@ -171,7 +172,7 @@ impl Helper {
|
||||||
helper: &Arc<Mutex<Self>>,
|
helper: &Arc<Mutex<Self>>,
|
||||||
state: &P2pool,
|
state: &P2pool,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
backup_hosts: Option<Vec<Node>>,
|
backup_hosts: Option<Vec<PoolNode>>,
|
||||||
) {
|
) {
|
||||||
info!("P2Pool | Attempting to restart...");
|
info!("P2Pool | Attempting to restart...");
|
||||||
helper.lock().unwrap().p2pool.lock().unwrap().signal = ProcessSignal::Restart;
|
helper.lock().unwrap().p2pool.lock().unwrap().signal = ProcessSignal::Restart;
|
||||||
|
@ -200,7 +201,7 @@ impl Helper {
|
||||||
helper: &Arc<Mutex<Self>>,
|
helper: &Arc<Mutex<Self>>,
|
||||||
state: &P2pool,
|
state: &P2pool,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
backup_hosts: Option<Vec<Node>>,
|
backup_hosts: Option<Vec<PoolNode>>,
|
||||||
) {
|
) {
|
||||||
helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
|
helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
|
||||||
|
|
||||||
|
@ -253,7 +254,7 @@ impl Helper {
|
||||||
helper: &Arc<Mutex<Self>>,
|
helper: &Arc<Mutex<Self>>,
|
||||||
state: &P2pool,
|
state: &P2pool,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
backup_hosts: Option<Vec<Node>>,
|
backup_hosts: Option<Vec<PoolNode>>,
|
||||||
) -> (Vec<String>, PathBuf, PathBuf, PathBuf) {
|
) -> (Vec<String>, PathBuf, PathBuf, PathBuf) {
|
||||||
let mut args = Vec::with_capacity(500);
|
let mut args = Vec::with_capacity(500);
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
|
@ -282,13 +283,13 @@ impl Helper {
|
||||||
// Push other nodes if `backup_host`.
|
// Push other nodes if `backup_host`.
|
||||||
if let Some(nodes) = backup_hosts {
|
if let Some(nodes) = backup_hosts {
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
if (node.ip.as_str(), node.rpc.as_str(), node.zmq.as_str()) != (ip, rpc, zmq) {
|
if (node.ip(), node.port(), node.custom()) != (ip, rpc, zmq) {
|
||||||
args.push("--host".to_string());
|
args.push("--host".to_string());
|
||||||
args.push(node.ip.to_string());
|
args.push(node.ip().to_string());
|
||||||
args.push("--rpc-port".to_string());
|
args.push("--rpc-port".to_string());
|
||||||
args.push(node.rpc.to_string());
|
args.push(node.port().to_string());
|
||||||
args.push("--zmq-port".to_string());
|
args.push("--zmq-port".to_string());
|
||||||
args.push(node.zmq.to_string());
|
args.push(node.custom().to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,20 +396,18 @@ impl Helper {
|
||||||
// Push other nodes if `backup_host`.
|
// Push other nodes if `backup_host`.
|
||||||
if let Some(nodes) = backup_hosts {
|
if let Some(nodes) = backup_hosts {
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
let ip = if node.ip == "localhost" {
|
let ip = if node.ip() == "localhost" {
|
||||||
"127.0.0.1"
|
"127.0.0.1"
|
||||||
} else {
|
} else {
|
||||||
&node.ip
|
node.ip()
|
||||||
};
|
};
|
||||||
if (node.ip.as_str(), node.rpc.as_str(), node.zmq.as_str())
|
if (node.ip(), node.port(), node.custom()) != (ip, &state.rpc, &state.zmq) {
|
||||||
!= (ip, &state.rpc, &state.zmq)
|
|
||||||
{
|
|
||||||
args.push("--host".to_string());
|
args.push("--host".to_string());
|
||||||
args.push(node.ip.to_string());
|
args.push(node.ip().to_string());
|
||||||
args.push("--rpc-port".to_string());
|
args.push("--rpc-port".to_string());
|
||||||
args.push(node.rpc.to_string());
|
args.push(node.port().to_string());
|
||||||
args.push("--zmq-port".to_string());
|
args.push("--zmq-port".to_string());
|
||||||
args.push(node.zmq.to_string());
|
args.push(node.custom().to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,9 +419,9 @@ impl Helper {
|
||||||
"P2Pool Main".to_string()
|
"P2Pool Main".to_string()
|
||||||
},
|
},
|
||||||
address: Self::head_tail_of_monero_address(&state.address),
|
address: Self::head_tail_of_monero_address(&state.address),
|
||||||
host: state.selected_ip.to_string(),
|
host: state.selected_node.ip.to_string(),
|
||||||
rpc: state.selected_rpc.to_string(),
|
rpc: state.selected_node.rpc.to_string(),
|
||||||
zmq: state.selected_zmq.to_string(),
|
zmq: state.selected_node.zmq_rig.to_string(),
|
||||||
out_peers: state.out_peers.to_string(),
|
out_peers: state.out_peers.to_string(),
|
||||||
in_peers: state.in_peers.to_string(),
|
in_peers: state.in_peers.to_string(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -298,13 +298,13 @@ Uptime = 0h 2m 4s
|
||||||
assert_eq!(p.miners.to_string(), "1,000");
|
assert_eq!(p.miners.to_string(), "1,000");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p.solo_block_mean.to_string(),
|
p.solo_block_mean.to_string(),
|
||||||
"5 months, 21 days, 9 hours, 52 minutes"
|
"5 months\n21 days\n9 hours\n52 minutes"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p.p2pool_block_mean.to_string(),
|
p.p2pool_block_mean.to_string(),
|
||||||
"3 days, 11 hours, 20 minutes"
|
"3 days\n11 hours\n20 minutes"
|
||||||
);
|
);
|
||||||
assert_eq!(p.p2pool_share_mean.to_string(), "8 minutes, 20 seconds");
|
assert_eq!(p.p2pool_share_mean.to_string(), "8 minutes\n20 seconds");
|
||||||
assert_eq!(p.p2pool_percent.to_string(), "0.040000%");
|
assert_eq!(p.p2pool_percent.to_string(), "0.040000%");
|
||||||
assert_eq!(p.user_p2pool_percent.to_string(), "2.000000%");
|
assert_eq!(p.user_p2pool_percent.to_string(), "2.000000%");
|
||||||
assert_eq!(p.user_monero_percent.to_string(), "0.000800%");
|
assert_eq!(p.user_monero_percent.to_string(), "0.000800%");
|
||||||
|
|
54
src/inits.rs
54
src/inits.rs
|
@ -24,6 +24,7 @@ use std::time::Instant;
|
||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
|
// everything is resized from here with the scale.
|
||||||
pub fn init_text_styles(ctx: &egui::Context, pixels_per_point: f32) {
|
pub fn init_text_styles(ctx: &egui::Context, pixels_per_point: f32) {
|
||||||
ctx.all_styles_mut(|style| {
|
ctx.all_styles_mut(|style| {
|
||||||
style.text_styles = [
|
style.text_styles = [
|
||||||
|
@ -34,13 +35,15 @@ pub fn init_text_styles(ctx: &egui::Context, pixels_per_point: f32) {
|
||||||
(Heading, FontId::new(22.0, egui::FontFamily::Monospace)),
|
(Heading, FontId::new(22.0, egui::FontFamily::Monospace)),
|
||||||
]
|
]
|
||||||
.into();
|
.into();
|
||||||
style.spacing.icon_width_inner = 32.0;
|
style.spacing.icon_width_inner = 24.0;
|
||||||
style.spacing.icon_width = 64.0;
|
style.spacing.icon_width = 48.0;
|
||||||
style.spacing.icon_spacing = 20.0;
|
style.spacing.icon_spacing = 16.0;
|
||||||
style.spacing.scroll = egui::style::ScrollStyle {
|
style.spacing.button_padding = [8.0, 8.0].into();
|
||||||
bar_width: 8.0,
|
style.spacing.item_spacing = [8.0, 8.0].into();
|
||||||
..egui::style::ScrollStyle::solid()
|
// style.spacing.scroll = egui::style::ScrollStyle {
|
||||||
};
|
// bar_width: 8.0,
|
||||||
|
// ..egui::style::ScrollStyle::solid()
|
||||||
|
// };
|
||||||
});
|
});
|
||||||
// Make sure scale f32 is a regular number.
|
// Make sure scale f32 is a regular number.
|
||||||
let pixels_per_point = clamp_scale(pixels_per_point);
|
let pixels_per_point = clamp_scale(pixels_per_point);
|
||||||
|
@ -134,7 +137,7 @@ pub fn init_auto(app: &mut App) {
|
||||||
|
|
||||||
// [Auto-Update]
|
// [Auto-Update]
|
||||||
#[cfg(not(feature = "distro"))]
|
#[cfg(not(feature = "distro"))]
|
||||||
if app.state.gupax.auto_update {
|
if app.state.gupax.auto.is_enabled(&AutoStart::Update) {
|
||||||
Update::spawn_thread(
|
Update::spawn_thread(
|
||||||
&app.og,
|
&app.og,
|
||||||
&app.state.gupax,
|
&app.state.gupax,
|
||||||
|
@ -155,7 +158,12 @@ pub fn init_auto(app: &mut App) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Auto-Node]
|
// [Auto-Node]
|
||||||
if app.state.gupax.auto_node {
|
if app
|
||||||
|
.state
|
||||||
|
.gupax
|
||||||
|
.auto
|
||||||
|
.is_enabled(&AutoStart::Process(ProcessName::Node))
|
||||||
|
{
|
||||||
if !Gupax::path_is_file(&app.state.gupax.node_path) {
|
if !Gupax::path_is_file(&app.state.gupax.node_path) {
|
||||||
warn!("Gupaxx | Node path is not a file! Skipping auto-node...");
|
warn!("Gupaxx | Node path is not a file! Skipping auto-node...");
|
||||||
} else if !check_binary_path(&app.state.gupax.node_path, ProcessName::Node) {
|
} else if !check_binary_path(&app.state.gupax.node_path, ProcessName::Node) {
|
||||||
|
@ -177,7 +185,12 @@ pub fn init_auto(app: &mut App) {
|
||||||
info!("Skipping auto-node...");
|
info!("Skipping auto-node...");
|
||||||
}
|
}
|
||||||
// [Auto-P2Pool]
|
// [Auto-P2Pool]
|
||||||
if app.state.gupax.auto_p2pool {
|
if app
|
||||||
|
.state
|
||||||
|
.gupax
|
||||||
|
.auto
|
||||||
|
.is_enabled(&AutoStart::Process(ProcessName::P2pool))
|
||||||
|
{
|
||||||
if !Regexes::addr_ok(&app.state.p2pool.address) {
|
if !Regexes::addr_ok(&app.state.p2pool.address) {
|
||||||
warn!("Gupaxx | P2Pool address is not valid! Skipping auto-p2pool...");
|
warn!("Gupaxx | P2Pool address is not valid! Skipping auto-p2pool...");
|
||||||
} else if !Gupax::path_is_file(&app.state.gupax.p2pool_path) {
|
} else if !Gupax::path_is_file(&app.state.gupax.p2pool_path) {
|
||||||
|
@ -202,7 +215,12 @@ pub fn init_auto(app: &mut App) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Auto-XMRig]
|
// [Auto-XMRig]
|
||||||
if app.state.gupax.auto_xmrig {
|
if app
|
||||||
|
.state
|
||||||
|
.gupax
|
||||||
|
.auto
|
||||||
|
.is_enabled(&AutoStart::Process(ProcessName::Xmrig))
|
||||||
|
{
|
||||||
if !Gupax::path_is_file(&app.state.gupax.xmrig_path) {
|
if !Gupax::path_is_file(&app.state.gupax.xmrig_path) {
|
||||||
warn!("Gupaxx | XMRig path is not an executable! Skipping auto-xmrig...");
|
warn!("Gupaxx | XMRig path is not an executable! Skipping auto-xmrig...");
|
||||||
} else if !check_binary_path(&app.state.gupax.xmrig_path, ProcessName::Xmrig) {
|
} else if !check_binary_path(&app.state.gupax.xmrig_path, ProcessName::Xmrig) {
|
||||||
|
@ -226,7 +244,12 @@ pub fn init_auto(app: &mut App) {
|
||||||
info!("Skipping auto-xmrig...");
|
info!("Skipping auto-xmrig...");
|
||||||
}
|
}
|
||||||
// [Auto-XMRig-Proxy]
|
// [Auto-XMRig-Proxy]
|
||||||
if app.state.gupax.auto_xp {
|
if app
|
||||||
|
.state
|
||||||
|
.gupax
|
||||||
|
.auto
|
||||||
|
.is_enabled(&AutoStart::Process(ProcessName::XmrigProxy))
|
||||||
|
{
|
||||||
if !Gupax::path_is_file(&app.state.gupax.xmrig_proxy_path) {
|
if !Gupax::path_is_file(&app.state.gupax.xmrig_proxy_path) {
|
||||||
warn!("Gupaxx | Xmrig-Proxy path is not a file! Skipping auto-xmrig_proxy...");
|
warn!("Gupaxx | Xmrig-Proxy path is not a file! Skipping auto-xmrig_proxy...");
|
||||||
} else if !check_binary_path(&app.state.gupax.xmrig_proxy_path, ProcessName::XmrigProxy) {
|
} else if !check_binary_path(&app.state.gupax.xmrig_proxy_path, ProcessName::XmrigProxy) {
|
||||||
|
@ -247,7 +270,12 @@ pub fn init_auto(app: &mut App) {
|
||||||
info!("Skipping auto-XMRig-Proxy...");
|
info!("Skipping auto-XMRig-Proxy...");
|
||||||
}
|
}
|
||||||
// [Auto-XvB]
|
// [Auto-XvB]
|
||||||
if app.state.gupax.auto_xvb {
|
if app
|
||||||
|
.state
|
||||||
|
.gupax
|
||||||
|
.auto
|
||||||
|
.is_enabled(&AutoStart::Process(ProcessName::Xvb))
|
||||||
|
{
|
||||||
Helper::start_xvb(
|
Helper::start_xvb(
|
||||||
&app.helper,
|
&app.helper,
|
||||||
&app.state.xvb,
|
&app.state.xvb,
|
||||||
|
|
|
@ -132,6 +132,8 @@ pub fn cmp_f64(a: f64, b: f64) -> std::cmp::Ordering {
|
||||||
use crate::disk::gupax_p2pool_api::GupaxP2poolApi;
|
use crate::disk::gupax_p2pool_api::GupaxP2poolApi;
|
||||||
use crate::helper::ProcessName;
|
use crate::helper::ProcessName;
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
use egui::TextStyle;
|
||||||
|
use egui::Ui;
|
||||||
use log::error;
|
use log::error;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -182,3 +184,7 @@ pub fn client() -> ClientWithMiddleware {
|
||||||
))
|
))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
/// to get the right height that a text must take before a button to be aligned in the center correctly.
|
||||||
|
pub fn height_txt_before_button(ui: &Ui, style: &TextStyle) -> f32 {
|
||||||
|
ui.style().spacing.button_padding.y * 2.0 + ui.text_style_height(style)
|
||||||
|
}
|
||||||
|
|
|
@ -348,6 +348,7 @@ pub const GUPAX_TAB_STATUS: &str = "Set the tab Gupaxx starts on to: Status";
|
||||||
pub const GUPAX_TAB_GUPAX: &str = "Set the tab Gupaxx starts on to: Gupaxx";
|
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_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_XMRIG: &str = "Set the tab Gupaxx starts on to: XMRig";
|
||||||
|
pub const GUPAX_TAB_XMRIG_PROXY: &str = "Set the tab Gupaxx starts on to: Proxy";
|
||||||
pub const GUPAX_TAB_XVB: &str = "Set the tab Gupaxx starts on to: XvB";
|
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_TAB_NODE: &str = "Set the default tab Gupaxx starts on to: Node";
|
||||||
|
|
||||||
|
@ -526,7 +527,6 @@ pub const XVB_TIME_ALGO: u32 = 600;
|
||||||
pub const XVB_MIN_TIME_SEND: u32 = (XVB_TIME_ALGO as f32 * 0.01) as u32;
|
pub const XVB_MIN_TIME_SEND: u32 = (XVB_TIME_ALGO as f32 * 0.01) as u32;
|
||||||
pub const XVB_TOKEN_LEN: usize = 9;
|
pub const XVB_TOKEN_LEN: usize = 9;
|
||||||
pub const XVB_HERO_SELECT: &str = "Donate as much as possible while keeping a share on p2pool, increases the odds of your round winning\nWhen modified, the algorithm will use the new choice at the next decision.";
|
pub const XVB_HERO_SELECT: &str = "Donate as much as possible while keeping a share on p2pool, increases the odds of your round winning\nWhen modified, the algorithm will use the new choice at the next decision.";
|
||||||
pub const XVB_TOKEN_FIELD: &str = "Token";
|
|
||||||
pub const XVB_FAILURE_FIELD: &str = "Failures";
|
pub const XVB_FAILURE_FIELD: &str = "Failures";
|
||||||
pub const XVB_DONATED_1H_FIELD: &str = "Donated last hour";
|
pub const XVB_DONATED_1H_FIELD: &str = "Donated last hour";
|
||||||
pub const XVB_DONATED_24H_FIELD: &str = "Donated last 24 hours";
|
pub const XVB_DONATED_24H_FIELD: &str = "Donated last 24 hours";
|
||||||
|
|
|
@ -59,7 +59,7 @@ impl HumanTime {
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
if value > 0 {
|
if value > 0 {
|
||||||
if *started {
|
if *started {
|
||||||
f.write_str(", ")?;
|
f.write_str("\n")?;
|
||||||
}
|
}
|
||||||
write!(f, "{} {}", value, name)?;
|
write!(f, "{} {}", value, name)?;
|
||||||
if value > 1 {
|
if value > 1 {
|
||||||
|
@ -332,64 +332,64 @@ mod test {
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(2)).to_string() == "2 seconds");
|
assert!(HumanTime::into_human(Duration::from_secs(2)).to_string() == "2 seconds");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(59)).to_string() == "59 seconds");
|
assert!(HumanTime::into_human(Duration::from_secs(59)).to_string() == "59 seconds");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(60)).to_string() == "1 minute");
|
assert!(HumanTime::into_human(Duration::from_secs(60)).to_string() == "1 minute");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(61)).to_string() == "1 minute, 1 second");
|
assert!(HumanTime::into_human(Duration::from_secs(61)).to_string() == "1 minute\n1 second");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(62)).to_string() == "1 minute, 2 seconds"
|
HumanTime::into_human(Duration::from_secs(62)).to_string() == "1 minute\n2 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(120)).to_string() == "2 minutes");
|
assert!(HumanTime::into_human(Duration::from_secs(120)).to_string() == "2 minutes");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(121)).to_string() == "2 minutes, 1 second"
|
HumanTime::into_human(Duration::from_secs(121)).to_string() == "2 minutes\n1 second"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(122)).to_string() == "2 minutes, 2 seconds"
|
HumanTime::into_human(Duration::from_secs(122)).to_string() == "2 minutes\n2 seconds"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(179)).to_string() == "2 minutes, 59 seconds"
|
HumanTime::into_human(Duration::from_secs(179)).to_string() == "2 minutes\n59 seconds"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(3599)).to_string()
|
HumanTime::into_human(Duration::from_secs(3599)).to_string()
|
||||||
== "59 minutes, 59 seconds"
|
== "59 minutes\n59 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(3600)).to_string() == "1 hour");
|
assert!(HumanTime::into_human(Duration::from_secs(3600)).to_string() == "1 hour");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(3601)).to_string() == "1 hour, 1 second");
|
assert!(HumanTime::into_human(Duration::from_secs(3601)).to_string() == "1 hour\n1 second");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(3602)).to_string() == "1 hour, 2 seconds"
|
HumanTime::into_human(Duration::from_secs(3602)).to_string() == "1 hour\n2 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(3660)).to_string() == "1 hour, 1 minute");
|
assert!(HumanTime::into_human(Duration::from_secs(3660)).to_string() == "1 hour\n1 minute");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(3720)).to_string() == "1 hour, 2 minutes"
|
HumanTime::into_human(Duration::from_secs(3720)).to_string() == "1 hour\n2 minutes"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(86399)).to_string()
|
HumanTime::into_human(Duration::from_secs(86399)).to_string()
|
||||||
== "23 hours, 59 minutes, 59 seconds"
|
== "23 hours\n59 minutes\n59 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(86400)).to_string() == "1 day");
|
assert!(HumanTime::into_human(Duration::from_secs(86400)).to_string() == "1 day");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(86401)).to_string() == "1 day, 1 second");
|
assert!(HumanTime::into_human(Duration::from_secs(86401)).to_string() == "1 day\n1 second");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(86402)).to_string() == "1 day, 2 seconds"
|
HumanTime::into_human(Duration::from_secs(86402)).to_string() == "1 day\n2 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(86460)).to_string() == "1 day, 1 minute");
|
assert!(HumanTime::into_human(Duration::from_secs(86460)).to_string() == "1 day\n1 minute");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(86520)).to_string() == "1 day, 2 minutes"
|
HumanTime::into_human(Duration::from_secs(86520)).to_string() == "1 day\n2 minutes"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(90000)).to_string() == "1 day, 1 hour");
|
assert!(HumanTime::into_human(Duration::from_secs(90000)).to_string() == "1 day\n1 hour");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(93600)).to_string() == "1 day, 2 hours");
|
assert!(HumanTime::into_human(Duration::from_secs(93600)).to_string() == "1 day\n2 hours");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(604799)).to_string()
|
HumanTime::into_human(Duration::from_secs(604799)).to_string()
|
||||||
== "6 days, 23 hours, 59 minutes, 59 seconds"
|
== "6 days\n23 hours\n59 minutes\n59 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(604800)).to_string() == "7 days");
|
assert!(HumanTime::into_human(Duration::from_secs(604800)).to_string() == "7 days");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(2630016)).to_string() == "1 month");
|
assert!(HumanTime::into_human(Duration::from_secs(2630016)).to_string() == "1 month");
|
||||||
assert!(
|
assert!(
|
||||||
HumanTime::into_human(Duration::from_secs(3234815)).to_string()
|
HumanTime::into_human(Duration::from_secs(3234815)).to_string()
|
||||||
== "1 month, 6 days, 23 hours, 59 minutes, 59 seconds"
|
== "1 month\n6 days\n23 hours\n59 minutes\n59 seconds"
|
||||||
);
|
);
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(5260032)).to_string() == "2 months");
|
assert!(HumanTime::into_human(Duration::from_secs(5260032)).to_string() == "2 months");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(31557600)).to_string() == "1 year");
|
assert!(HumanTime::into_human(Duration::from_secs(31557600)).to_string() == "1 year");
|
||||||
assert!(HumanTime::into_human(Duration::from_secs(63115200)).to_string() == "2 years");
|
assert!(HumanTime::into_human(Duration::from_secs(63115200)).to_string() == "2 years");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HumanTime::into_human(Duration::from_secs(18446744073709551615)).to_string(),
|
HumanTime::into_human(Duration::from_secs(18446744073709551615)).to_string(),
|
||||||
"584542046090 years, 7 months, 15 days, 17 hours, 5 minutes, 3 seconds",
|
"584542046090 years\n7 months\n15 days\n17 hours\n5 minutes\n3 seconds",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue