mirror of
https://github.com/hinto-janai/gupax.git
synced 2024-12-23 11:29:38 +00:00
add basic [--flags]
This commit is contained in:
parent
ed7ddeeda1
commit
773bc65593
4 changed files with 236 additions and 150 deletions
|
@ -15,7 +15,7 @@
|
||||||
// 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/>.
|
||||||
|
|
||||||
// These are the versions bundled with Gupax.
|
pub const GUPAX_VERSION: &'static str = "v0.1.0";
|
||||||
pub const P2POOL_VERSION: &'static str = "v2.4";
|
pub const P2POOL_VERSION: &'static str = "v2.4";
|
||||||
pub const XMRIG_VERSION: &'static str = "v6.18.0";
|
pub const XMRIG_VERSION: &'static str = "v6.18.0";
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ pub const BYTES_ICON: &[u8] = include_bytes!("../images/png/icon.png");
|
||||||
pub const BYTES_BANNER: &[u8] = include_bytes!("../images/png/banner.png");
|
pub const BYTES_BANNER: &[u8] = include_bytes!("../images/png/banner.png");
|
||||||
pub const P2POOL_BASE_ARGS: &'static str = "";
|
pub const P2POOL_BASE_ARGS: &'static str = "";
|
||||||
pub const XMRIG_BASE_ARGS: &'static str = "--http-host=127.0.0.1 --http-port=18088 --algo=rx/0 --coin=Monero --randomx-cache-qos";
|
pub const XMRIG_BASE_ARGS: &'static str = "--http-host=127.0.0.1 --http-port=18088 --algo=rx/0 --coin=Monero --randomx-cache-qos";
|
||||||
|
pub const HORIZONTAL: &'static str = "--------------------------------------------";
|
||||||
|
|
||||||
// OS specific
|
// OS specific
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
@ -66,3 +67,19 @@ pub const XMRIG_NICEHASH: &'static str = "Enable nicehash.com support";
|
||||||
pub const XMRIG_KEEPALIVE: &'static str = "Send keepalived packet to prevent timeout (needs pool support)";
|
pub const XMRIG_KEEPALIVE: &'static str = "Send keepalived packet to prevent timeout (needs pool support)";
|
||||||
pub const XMRIG_THREADS: &'static str = "Number of CPU threads to use for mining";
|
pub const XMRIG_THREADS: &'static str = "Number of CPU threads to use for mining";
|
||||||
pub const XMRIG_PRIORITY: &'static str = "Set process priority (0 idle, 2 normal to 5 highest)";
|
pub const XMRIG_PRIORITY: &'static str = "Set process priority (0 idle, 2 normal to 5 highest)";
|
||||||
|
|
||||||
|
// CLI argument messages
|
||||||
|
pub const ARG_HELP: &'static str =
|
||||||
|
r#"USAGE: gupax [--flags]
|
||||||
|
|
||||||
|
-h | --help Print this help message
|
||||||
|
-v | --version Print versions
|
||||||
|
-n | --no-startup Disable auto-update/node connections at startup
|
||||||
|
-r | --reset Reset all Gupax configuration/state"#;
|
||||||
|
pub const ARG_COPYRIGHT: &'static str =
|
||||||
|
r#"For more information:
|
||||||
|
https://github.com/hinto-janaiyo/gupax
|
||||||
|
https://github.com/SChernykh/p2pool
|
||||||
|
https://github.com/xmrig/xmrig
|
||||||
|
|
||||||
|
Gupax, P2Pool, and XMRig are licensed under GPLv3."#;
|
||||||
|
|
196
src/main.rs
196
src/main.rs
|
@ -34,8 +34,9 @@ use env_logger::{Builder,WriteStyle};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::sync::{Arc,Mutex};
|
use std::sync::{Arc,Mutex};
|
||||||
use std::thread;
|
use std::{thread,env};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
mod constants;
|
mod constants;
|
||||||
|
@ -55,10 +56,10 @@ use {constants::*,node::*,state::*,about::*,status::*,gupax::*,p2pool::*,xmrig::
|
||||||
pub struct App {
|
pub struct App {
|
||||||
// Misc state
|
// Misc state
|
||||||
tab: Tab, // What tab are we on?
|
tab: Tab, // What tab are we on?
|
||||||
quit: bool, // Did user click quit button?
|
quit: bool, // Was the quit button clicked?
|
||||||
quit_confirm: bool, // Did user confirm to quit?
|
quit_confirm: bool, // Was the quit confirmed?
|
||||||
ping: bool, // Did user click the ping button?
|
ping: bool, // Was the ping button clicked?
|
||||||
ping_prog: Arc<Mutex<bool>>, // Are we in the progress of pinging?
|
pinging: Arc<Mutex<bool>>, // Is a ping in progress?
|
||||||
node: Arc<Mutex<NodeStruct>>, // Data on community nodes
|
node: Arc<Mutex<NodeStruct>>, // Data on community nodes
|
||||||
// State:
|
// State:
|
||||||
// og = Old state to compare against
|
// og = Old state to compare against
|
||||||
|
@ -68,42 +69,58 @@ pub struct App {
|
||||||
og: State,
|
og: State,
|
||||||
state: State,
|
state: State,
|
||||||
diff: bool,
|
diff: bool,
|
||||||
|
// Process/update state:
|
||||||
|
// Doesn't make sense to save this on disk
|
||||||
|
// so it's represented as a bool here.
|
||||||
|
p2pool: bool, // Is p2pool online?
|
||||||
|
xmrig: bool, // Is xmrig online?
|
||||||
|
updating: bool, // Is an update in progress?
|
||||||
|
// State from [--flags]
|
||||||
|
startup: bool,
|
||||||
|
reset: bool,
|
||||||
// Static stuff
|
// Static stuff
|
||||||
now: Instant,
|
now: Instant, // Internal timer
|
||||||
resolution: Vec2,
|
resolution: Vec2, // Frame resolution
|
||||||
os: &'static str,
|
os: &'static str, // OS
|
||||||
version: String,
|
version: String, // Gupax version
|
||||||
name_version: String,
|
name_version: String, // [Gupax vX.X.X]
|
||||||
banner: RetainedImage,
|
banner: RetainedImage, // Gupax banner image
|
||||||
|
|
||||||
// TEMPORARY FIXME
|
|
||||||
p2pool: bool,
|
|
||||||
xmrig: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
fn cc(cc: &eframe::CreationContext<'_>, app: Self) -> Self {
|
||||||
|
let resolution = cc.integration_info.window_info.size;
|
||||||
|
init_text_styles(&cc.egui_ctx, resolution[0] as f32);
|
||||||
Self {
|
Self {
|
||||||
|
resolution,
|
||||||
|
..app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default() -> Self {
|
||||||
|
let app = Self {
|
||||||
tab: Tab::default(),
|
tab: Tab::default(),
|
||||||
quit: false,
|
quit: false,
|
||||||
quit_confirm: false,
|
quit_confirm: false,
|
||||||
ping: false,
|
ping: false,
|
||||||
ping_prog: Arc::new(Mutex::new(false)),
|
pinging: Arc::new(Mutex::new(false)),
|
||||||
node: Arc::new(Mutex::new(NodeStruct::default())),
|
node: Arc::new(Mutex::new(NodeStruct::default())),
|
||||||
og: State::default(),
|
og: State::default(),
|
||||||
state: State::default(),
|
state: State::default(),
|
||||||
diff: false,
|
diff: false,
|
||||||
|
p2pool: false,
|
||||||
|
xmrig: false,
|
||||||
|
updating: false,
|
||||||
|
startup: true,
|
||||||
|
reset: false,
|
||||||
now: Instant::now(),
|
now: Instant::now(),
|
||||||
resolution: cc.integration_info.window_info.size,
|
resolution: Vec2::new(1280.0, 720.0),
|
||||||
os: OS,
|
os: OS,
|
||||||
version: "v0.0.1".to_string(),
|
version: "v0.0.1".to_string(),
|
||||||
name_version: "Gupax v0.0.1".to_string(),
|
name_version: "Gupax v0.0.1".to_string(),
|
||||||
banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).expect("oops"),
|
banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).expect("oops"),
|
||||||
|
};
|
||||||
// TEMPORARY FIXME
|
parse_args(app)
|
||||||
p2pool: false,
|
|
||||||
xmrig: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +170,10 @@ fn init_text_styles(ctx: &egui::Context, width: f32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let filter = LevelFilter::Info;
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
let filter = LevelFilter::Warn;
|
||||||
use env_logger::fmt::Color;
|
use env_logger::fmt::Color;
|
||||||
Builder::new().format(|buf, record| {
|
Builder::new().format(|buf, record| {
|
||||||
let level;
|
let level;
|
||||||
|
@ -173,7 +194,7 @@ fn init_logger() {
|
||||||
buf.style().set_dimmed(true).value(record.line().unwrap_or(0)),
|
buf.style().set_dimmed(true).value(record.line().unwrap_or(0)),
|
||||||
record.args(),
|
record.args(),
|
||||||
)
|
)
|
||||||
}).filter_level(LevelFilter::Info).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().init();
|
}).filter_level(filter).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().init();
|
||||||
info!("init_logger() ... OK");
|
info!("init_logger() ... OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +216,45 @@ fn init_options() -> NativeOptions {
|
||||||
options
|
options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Misc functions
|
||||||
|
fn into_absolute_path(path: String) -> Result<PathBuf, std::io::Error> {
|
||||||
|
let path = PathBuf::from(path);
|
||||||
|
if path.is_relative() {
|
||||||
|
let mut dir = std::env::current_exe()?;
|
||||||
|
dir.pop();
|
||||||
|
dir.push(path);
|
||||||
|
Ok(dir)
|
||||||
|
} else {
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_args(mut app: App) -> App {
|
||||||
|
info!("Parsing CLI arguments...");
|
||||||
|
let mut args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() == 1 { info!("No args ... OK"); return app } else { args.remove(0); info!("Args ... {:?}", args); }
|
||||||
|
// [help/version], exit early
|
||||||
|
for arg in &args {
|
||||||
|
match arg.as_str() {
|
||||||
|
"-h"|"--help" => { println!("{}", ARG_HELP); exit(0); },
|
||||||
|
"-v"|"--version" => {
|
||||||
|
println!("Gupax | {}\nP2Pool | {}\nXMRig | {}\n\n{}", GUPAX_VERSION, P2POOL_VERSION, XMRIG_VERSION, ARG_COPYRIGHT);
|
||||||
|
exit(0);
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Everything else
|
||||||
|
for arg in args {
|
||||||
|
match arg.as_str() {
|
||||||
|
"-n"|"--no-startup" => { info!("Disabling startup..."); app.startup = false; }
|
||||||
|
"-r"|"--reset" => { info!("Resetting state..."); app.reset = true; }
|
||||||
|
_ => { eprintln!("[Gupax error] Invalid option: [{}]\nFor help, use: [--help]", arg); exit(1); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [App] frame for [Panic] situations
|
//---------------------------------------------------------------------------------------------------- [App] frame for [Panic] situations
|
||||||
struct Panic { error_msg: String, }
|
struct Panic { error_msg: String, }
|
||||||
impl Panic {
|
impl Panic {
|
||||||
|
@ -240,19 +300,19 @@ impl eframe::App for Panic {
|
||||||
//---------------------------------------------------------------------------------------------------- Main [App] frame
|
//---------------------------------------------------------------------------------------------------- Main [App] frame
|
||||||
fn main() {
|
fn main() {
|
||||||
init_logger();
|
init_logger();
|
||||||
// let toml = match State::get() {
|
let app = App::default();
|
||||||
// Ok(toml) => toml,
|
|
||||||
// Err(err) => {
|
|
||||||
// error!("{}", err);
|
|
||||||
// let error_msg = err.to_string();
|
|
||||||
// let options = Panic::options();
|
|
||||||
// eframe::run_native("Gupax", options, Box::new(|cc| Box::new(Panic::new(cc, error_msg))),);
|
|
||||||
// exit(1);
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
let state = State::default();
|
|
||||||
let options = init_options();
|
let options = init_options();
|
||||||
eframe::run_native("Gupax", options, Box::new(|cc| Box::new(App::new(cc))),);
|
let toml = match State::get() {
|
||||||
|
Ok(toml) => toml,
|
||||||
|
Err(err) => {
|
||||||
|
error!("{}", err);
|
||||||
|
let error_msg = err.to_string();
|
||||||
|
let options = Panic::options();
|
||||||
|
eframe::run_native("Gupax", options, Box::new(|cc| Box::new(Panic::new(cc, error_msg))),);
|
||||||
|
exit(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
eframe::run_native("Gupax", options, Box::new(|cc| Box::new(App::cc(cc, app))),);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for App {
|
impl eframe::App for App {
|
||||||
|
@ -262,49 +322,75 @@ impl eframe::App for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
init_text_styles(ctx, 1280.0);
|
// init_text_styles(ctx, 1280.0);
|
||||||
|
|
||||||
// Close confirmation.
|
// Close confirmation.
|
||||||
if self.quit {
|
if self.quit {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
init_text_styles(ctx, ui.available_width());
|
||||||
let width = ui.available_width();
|
let width = ui.available_width();
|
||||||
let width = width - 10.0;
|
let width = width - 10.0;
|
||||||
let height = ui.available_height();
|
let height = ui.available_height();
|
||||||
init_text_styles(ctx, width);
|
// Detect processes or update
|
||||||
ui.add_sized([width, height/2.0], Label::new("Are you sure you want to quit?"));
|
if self.p2pool || self.xmrig {
|
||||||
|
ui.add_sized([width, height/6.0], Label::new("Are you sure you want to quit?"));
|
||||||
|
if self.p2pool { ui.add_sized([width, height/6.0], Label::new("P2Pool is online...!")); }
|
||||||
|
if self.xmrig { ui.add_sized([width, height/6.0], Label::new("XMRig is online...!")); }
|
||||||
|
// Else, just quit
|
||||||
|
} else {
|
||||||
|
if self.state.gupax.save_before_quit {
|
||||||
|
info!("Saving before quit...");
|
||||||
|
match self.state.save() {
|
||||||
|
Err(err) => { error!("{}", err); exit(1); },
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
info!("No processes or update in progress ... goodbye!");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
egui::TopBottomPanel::bottom("quit").show(ctx, |ui| {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() {
|
if ui.add_sized([width, height/8.0], egui::Button::new("Yes")).clicked() {
|
||||||
|
if self.state.gupax.save_before_quit {
|
||||||
|
info!("Saving before quit...");
|
||||||
|
match self.state.save() {
|
||||||
|
Err(err) => { error!("{}", err); exit(1); },
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
info!("Quit confirmation = yes ... goodbye!");
|
info!("Quit confirmation = yes ... goodbye!");
|
||||||
self.quit_confirm = true;
|
self.quit_confirm = true;
|
||||||
frame.close();
|
exit(0);
|
||||||
} else if ui.add_sized([width, height/10.0], egui::Button::new("No")).clicked() {
|
} else if ui.add_sized([width, height/8.0], egui::Button::new("No")).clicked() {
|
||||||
self.quit = false;
|
self.quit = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// If ping was pressed, start thread
|
||||||
if self.ping {
|
if self.ping {
|
||||||
self.ping = false;
|
self.ping = false;
|
||||||
self.ping_prog = Arc::new(Mutex::new(true));
|
self.pinging = Arc::new(Mutex::new(true));
|
||||||
let node_clone = Arc::clone(&self.node);
|
let node_clone = Arc::clone(&self.node);
|
||||||
let prog_clone = Arc::clone(&self.ping_prog);
|
let pinging_clone = Arc::clone(&self.pinging);
|
||||||
thread::spawn(move|| {
|
thread::spawn(move|| {
|
||||||
let result = NodeStruct::ping();
|
let result = NodeStruct::ping();
|
||||||
*node_clone.lock().unwrap() = result.node;
|
*node_clone.lock().unwrap() = result.nodes;
|
||||||
*prog_clone.lock().unwrap() = false;
|
*pinging_clone.lock().unwrap() = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// if *self.ping_prog.lock().unwrap() {
|
// If ping-ING, display stats
|
||||||
|
// if *self.pinging.lock().unwrap() {
|
||||||
// egui::CentralPanel::default().show(ctx, |ui| {
|
// egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
// let width = ui.available_width();
|
// let width = ui.available_width();
|
||||||
// let width = width - 10.0;
|
// let width = width - 10.0;
|
||||||
// let height = ui.available_height();
|
// let height = ui.available_height();
|
||||||
// init_text_styles(ctx, width);
|
// init_text_styles(ctx, width);
|
||||||
// ui.add_sized([width, height/2.0], Label::new(format!("In progress: {}", *self.ping_prog.lock().unwrap())));
|
// ui.add_sized([width, height/2.0], Label::new(format!("In progress: {}", *self.pinging.lock().unwrap())));
|
||||||
// ui.group(|ui| {
|
// ui.group(|ui| {
|
||||||
// if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() {
|
// if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() {
|
||||||
// info!("Quit confirmation = yes ... goodbye!");
|
// info!("Quit confirmation = yes ... goodbye!");
|
||||||
|
@ -324,8 +410,8 @@ impl eframe::App for App {
|
||||||
let width = (ui.available_width() - 90.0) / 5.0;
|
let width = (ui.available_width() - 90.0) / 5.0;
|
||||||
let height = ui.available_height() / 10.0;
|
let height = ui.available_height() / 10.0;
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
ui.style_mut().override_text_style = Some(Name("Tab".into()));
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
ui.style_mut().override_text_style = Some(Name("Tab".into()));
|
||||||
ui.style_mut().visuals.widgets.inactive.fg_stroke.color = Color32::from_rgb(100, 100, 100);
|
ui.style_mut().visuals.widgets.inactive.fg_stroke.color = Color32::from_rgb(100, 100, 100);
|
||||||
ui.style_mut().visuals.selection.bg_fill = Color32::from_rgb(255, 120, 120);
|
ui.style_mut().visuals.selection.bg_fill = Color32::from_rgb(255, 120, 120);
|
||||||
ui.style_mut().visuals.selection.stroke = Stroke {
|
ui.style_mut().visuals.selection.stroke = Stroke {
|
||||||
|
@ -346,7 +432,6 @@ impl eframe::App for App {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
|
||||||
let height = height / 2.0;
|
let height = height / 2.0;
|
||||||
// Bottom: app info + state/process buttons
|
// Bottom: app info + state/process buttons
|
||||||
egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
||||||
|
@ -359,9 +444,6 @@ impl eframe::App for App {
|
||||||
ui.add_sized([width, height], Label::new(self.os));
|
ui.add_sized([width, height], Label::new(self.os));
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.add_sized([width/1.5, height], Label::new("P2Pool"));
|
ui.add_sized([width/1.5, height], Label::new("P2Pool"));
|
||||||
// TODO
|
|
||||||
// self.p2pool + self.xmrig
|
|
||||||
// This is for process online/offline status
|
|
||||||
if self.p2pool == true {
|
if self.p2pool == true {
|
||||||
ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(100, 230, 100))));
|
ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(100, 230, 100))));
|
||||||
} else {
|
} else {
|
||||||
|
@ -428,10 +510,6 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Central: tab contents
|
|
||||||
// Docs say to add central last, don't think it matters here but whatever:
|
|
||||||
// [https://docs.rs/egui/latest/egui/containers/panel/struct.TopBottomPanel.html]
|
|
||||||
// egui::TopBottomPanel::bottom("2").show(ctx, |ui| {
|
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
|
||||||
match self.tab {
|
match self.tab {
|
||||||
Tab::About => {
|
Tab::About => {
|
||||||
|
@ -451,8 +529,6 @@ impl eframe::App for App {
|
||||||
Xmrig::show(&mut self.state.xmrig, ctx, ui);
|
Xmrig::show(&mut self.state.xmrig, ctx, ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// });
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
89
src/node.rs
89
src/node.rs
|
@ -41,6 +41,11 @@ pub const SUPPORTXMR: &'static str = "node.supportxmr.com:18081";
|
||||||
pub const SUPPORTXMR_IR: &'static str = "node.supportxmr.ir:18081";
|
pub const SUPPORTXMR_IR: &'static str = "node.supportxmr.ir:18081";
|
||||||
pub const XMRVSBEAST: &'static str = "p2pmd.xmrvsbeast.com:18081";
|
pub const XMRVSBEAST: &'static str = "p2pmd.xmrvsbeast.com:18081";
|
||||||
|
|
||||||
|
pub const NODE_IPS: [&'static str; 12] = [
|
||||||
|
C3POOL,CAKE,CAKE_EU,CAKE_UK,CAKE_US,MONERUJO,RINO,
|
||||||
|
SELSTA,SETH,SUPPORTXMR,SUPPORTXMR_IR,XMRVSBEAST,
|
||||||
|
];
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NodeStruct {
|
pub struct NodeStruct {
|
||||||
c3pool: Data, cake: Data, cake_eu: Data, cake_uk: Data, cake_us: Data, monerujo: Data,
|
c3pool: Data, cake: Data, cake_eu: Data, cake_uk: Data, cake_us: Data, monerujo: Data,
|
||||||
|
@ -52,7 +57,7 @@ pub struct Data {
|
||||||
pub ms: u128,
|
pub ms: u128,
|
||||||
pub color: Color32,
|
pub color: Color32,
|
||||||
pub id: NodeEnum,
|
pub id: NodeEnum,
|
||||||
pub ip: String,
|
pub ip: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy,Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
#[derive(Copy,Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
||||||
|
@ -69,39 +74,31 @@ impl std::fmt::Display for NodeEnum {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PingResult {
|
pub struct PingResult {
|
||||||
pub node: NodeStruct,
|
pub nodes: NodeStruct,
|
||||||
pub fastest: NodeEnum,
|
pub fastest: NodeEnum,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::NodeEnum::*;
|
||||||
impl NodeStruct {
|
impl NodeStruct {
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
use crate::NodeEnum::*;
|
|
||||||
let ms = 0;
|
let ms = 0;
|
||||||
let color = Color32::GRAY;
|
let color = Color32::GRAY;
|
||||||
Self {
|
Self {
|
||||||
c3pool: Data { ms, color, id: C3pool, ip: C3POOL.to_string(), },
|
c3pool: Data { ms, color, id: C3pool, ip: C3POOL, },
|
||||||
cake: Data { ms, color, id: Cake, ip: CAKE.to_string(), },
|
cake: Data { ms, color, id: Cake, ip: CAKE, },
|
||||||
cake_eu: Data { ms, color, id: CakeEu, ip: CAKE_EU.to_string(), },
|
cake_eu: Data { ms, color, id: CakeEu, ip: CAKE_EU, },
|
||||||
cake_uk: Data { ms, color, id: CakeUk, ip: CAKE_UK.to_string(), },
|
cake_uk: Data { ms, color, id: CakeUk, ip: CAKE_UK, },
|
||||||
cake_us: Data { ms, color, id: CakeUs, ip: CAKE_US.to_string(), },
|
cake_us: Data { ms, color, id: CakeUs, ip: CAKE_US, },
|
||||||
monerujo: Data { ms, color, id: Monerujo, ip: MONERUJO.to_string(), },
|
monerujo: Data { ms, color, id: Monerujo, ip: MONERUJO, },
|
||||||
rino: Data { ms, color, id: Rino, ip: RINO.to_string(), },
|
rino: Data { ms, color, id: Rino, ip: RINO, },
|
||||||
selsta: Data { ms, color, id: Selsta, ip: SELSTA.to_string(), },
|
selsta: Data { ms, color, id: Selsta, ip: SELSTA, },
|
||||||
seth: Data { ms, color, id: Seth, ip: SETH.to_string(), },
|
seth: Data { ms, color, id: Seth, ip: SETH, },
|
||||||
supportxmr: Data { ms, color, id: SupportXmr, ip: SUPPORTXMR.to_string(), },
|
supportxmr: Data { ms, color, id: SupportXmr, ip: SUPPORTXMR, },
|
||||||
supportxmr_ir: Data { ms, color, id: SupportXmrIr, ip: SUPPORTXMR_IR.to_string(), },
|
supportxmr_ir: Data { ms, color, id: SupportXmrIr, ip: SUPPORTXMR_IR, },
|
||||||
xmrvsbeast: Data { ms, color, id: XmrVsBeast, ip: XMRVSBEAST.to_string(), },
|
xmrvsbeast: Data { ms, color, id: XmrVsBeast, ip: XMRVSBEAST, },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return array of all IPs
|
|
||||||
fn array() -> [&'static str; 12] {
|
|
||||||
[
|
|
||||||
C3POOL,CAKE,CAKE_EU,CAKE_UK,CAKE_US,MONERUJO,RINO,
|
|
||||||
SELSTA,SETH,SUPPORTXMR,SUPPORTXMR_IR,XMRVSBEAST,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is for pinging the community nodes to
|
// This is for pinging the community nodes to
|
||||||
// find the fastest/slowest one for the user.
|
// find the fastest/slowest one for the user.
|
||||||
// The process:
|
// The process:
|
||||||
|
@ -123,9 +120,8 @@ impl NodeStruct {
|
||||||
// timeout = BLACK
|
// timeout = BLACK
|
||||||
// default = GRAY
|
// default = GRAY
|
||||||
pub fn ping() -> PingResult {
|
pub fn ping() -> PingResult {
|
||||||
use crate::NodeEnum::*;
|
|
||||||
info!("Starting community node pings...");
|
info!("Starting community node pings...");
|
||||||
let mut node = NodeStruct::default();
|
let mut nodes = NodeStruct::default();
|
||||||
let mut get_info = HashMap::new();
|
let mut get_info = HashMap::new();
|
||||||
get_info.insert("jsonrpc", "2.0");
|
get_info.insert("jsonrpc", "2.0");
|
||||||
get_info.insert("id", "0");
|
get_info.insert("id", "0");
|
||||||
|
@ -134,7 +130,7 @@ impl NodeStruct {
|
||||||
let fastest = false;
|
let fastest = false;
|
||||||
let timeout_sec = Duration::from_millis(5000);
|
let timeout_sec = Duration::from_millis(5000);
|
||||||
|
|
||||||
for ip in Self::array().iter() {
|
for ip in NODE_IPS.iter() {
|
||||||
let id = match *ip {
|
let id = match *ip {
|
||||||
C3POOL => C3pool,
|
C3POOL => C3pool,
|
||||||
CAKE => Cake,
|
CAKE => Cake,
|
||||||
|
@ -182,18 +178,18 @@ impl NodeStruct {
|
||||||
color = Color32::LIGHT_GREEN
|
color = Color32::LIGHT_GREEN
|
||||||
}
|
}
|
||||||
match id {
|
match id {
|
||||||
C3pool => { node.c3pool.ms = ms; node.c3pool.color = color; },
|
C3pool => { nodes.c3pool.ms = ms; nodes.c3pool.color = color; },
|
||||||
Cake => { node.cake.ms = ms; node.cake.color = color; },
|
Cake => { nodes.cake.ms = ms; nodes.cake.color = color; },
|
||||||
CakeEu => { node.cake_eu.ms = ms; node.cake_eu.color = color; },
|
CakeEu => { nodes.cake_eu.ms = ms; nodes.cake_eu.color = color; },
|
||||||
CakeUk => { node.cake_uk.ms = ms; node.cake_uk.color = color; },
|
CakeUk => { nodes.cake_uk.ms = ms; nodes.cake_uk.color = color; },
|
||||||
CakeUs => { node.cake_us.ms = ms; node.cake_us.color = color; },
|
CakeUs => { nodes.cake_us.ms = ms; nodes.cake_us.color = color; },
|
||||||
Monerujo => { node.monerujo.ms = ms; node.monerujo.color = color; },
|
Monerujo => { nodes.monerujo.ms = ms; nodes.monerujo.color = color; },
|
||||||
Rino => { node.rino.ms = ms; node.rino.color = color; },
|
Rino => { nodes.rino.ms = ms; nodes.rino.color = color; },
|
||||||
Selsta => { node.selsta.ms = ms; node.selsta.color = color; },
|
Selsta => { nodes.selsta.ms = ms; nodes.selsta.color = color; },
|
||||||
Seth => { node.seth.ms = ms; node.seth.color = color; },
|
Seth => { nodes.seth.ms = ms; nodes.seth.color = color; },
|
||||||
SupportXmr => { node.supportxmr.ms = ms; node.supportxmr.color = color; },
|
SupportXmr => { nodes.supportxmr.ms = ms; nodes.supportxmr.color = color; },
|
||||||
SupportXmrIr => { node.supportxmr_ir.ms = ms; node.supportxmr_ir.color = color; },
|
SupportXmrIr => { nodes.supportxmr_ir.ms = ms; nodes.supportxmr_ir.color = color; },
|
||||||
XmrVsBeast => { node.xmrvsbeast.ms = ms; node.xmrvsbeast.color = color; },
|
XmrVsBeast => { nodes.xmrvsbeast.ms = ms; nodes.xmrvsbeast.color = color; },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut best_ms: u128 = vec[0].0;
|
let mut best_ms: u128 = vec[0].0;
|
||||||
|
@ -208,22 +204,7 @@ impl NodeStruct {
|
||||||
// The values don't update if not printed beforehand,
|
// The values don't update if not printed beforehand,
|
||||||
// so the match below on [fastest] gets funky.
|
// so the match below on [fastest] gets funky.
|
||||||
info!("Fastest node ... {:#?} @ {:#?}ms", fastest, best_ms);
|
info!("Fastest node ... {:#?} @ {:#?}ms", fastest, best_ms);
|
||||||
let ip = match fastest {
|
|
||||||
C3pool => C3POOL,
|
|
||||||
Cake => CAKE,
|
|
||||||
CakeEu => CAKE_EU,
|
|
||||||
CakeUk => CAKE_UK,
|
|
||||||
CakeUs => CAKE_US,
|
|
||||||
Monerujo => MONERUJO,
|
|
||||||
Rino => RINO,
|
|
||||||
Selsta => SELSTA,
|
|
||||||
Seth => SETH,
|
|
||||||
SupportXmr => SUPPORTXMR,
|
|
||||||
SupportXmrIr => SUPPORTXMR_IR,
|
|
||||||
XmrVsBeast => XMRVSBEAST,
|
|
||||||
};
|
|
||||||
info!("Using IP ... {}", ip);
|
|
||||||
info!("Community node ping ... OK");
|
info!("Community node ping ... OK");
|
||||||
PingResult { node, fastest, }
|
PingResult { nodes, fastest, }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
36
src/state.rs
36
src/state.rs
|
@ -33,6 +33,7 @@ use std::fmt::Display;
|
||||||
use std::path::{Path,PathBuf};
|
use std::path::{Path,PathBuf};
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use serde_derive::{Serialize,Deserialize};
|
use serde_derive::{Serialize,Deserialize};
|
||||||
|
use crate::constants::HORIZONTAL;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Impl
|
//---------------------------------------------------------------------------------------------------- Impl
|
||||||
|
@ -43,6 +44,7 @@ impl State {
|
||||||
gupax: Gupax {
|
gupax: Gupax {
|
||||||
auto_update: true,
|
auto_update: true,
|
||||||
ask_before_quit: true,
|
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(),
|
||||||
},
|
},
|
||||||
|
@ -107,14 +109,14 @@ impl State {
|
||||||
Ok(string)
|
Ok(string)
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("TOML not found, attempting to create default");
|
warn!("TOML not found, attempting to create default");
|
||||||
let default = match toml::ser::to_string(&State::default()) {
|
let default = match toml::ser::to_string(&State::default()) {
|
||||||
Ok(o) => { info!("TOML serialization ... OK"); o },
|
Ok(o) => { info!("TOML serialization ... OK"); o },
|
||||||
Err(e) => { error!("Couldn't serialize default TOML file: {}", e); return Err(TomlError::Serialize(e)) },
|
Err(e) => { error!("Couldn't serialize default TOML file: {}", e); return Err(TomlError::Serialize(e)) },
|
||||||
};
|
};
|
||||||
fs::write(&path, &default)?;
|
fs::write(&path, &default)?;
|
||||||
info!("TOML write ... OK");
|
info!("TOML write ... OK");
|
||||||
Ok(fs::read_to_string(default)?)
|
Ok(default)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +126,9 @@ impl State {
|
||||||
match toml::de::from_str(&string) {
|
match toml::de::from_str(&string) {
|
||||||
Ok(toml) => {
|
Ok(toml) => {
|
||||||
info!("TOML parse ... OK");
|
info!("TOML parse ... OK");
|
||||||
eprint!("{}", string);
|
info!("{}", HORIZONTAL);
|
||||||
|
for i in string.lines() { info!("{}", i); }
|
||||||
|
info!("{}", HORIZONTAL);
|
||||||
Ok(toml)
|
Ok(toml)
|
||||||
},
|
},
|
||||||
Err(err) => { error!("Couldn't parse TOML from string"); Err(TomlError::Deserialize(err)) },
|
Err(err) => { error!("Couldn't parse TOML from string"); Err(TomlError::Deserialize(err)) },
|
||||||
|
@ -133,22 +137,25 @@ impl State {
|
||||||
|
|
||||||
// Last three functions combined
|
// Last three functions combined
|
||||||
// get_path() -> read_or_create() -> parse()
|
// get_path() -> read_or_create() -> parse()
|
||||||
// pub fn get() -> Result<State, TomlError> {
|
pub fn get() -> Result<State, TomlError> {
|
||||||
// let path = Self::path();
|
Self::parse(Self::read_or_create(Self::get_path()?)?)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Overwrite disk Toml with memory State (save state)
|
// Save [State] onto disk file [gupax.toml]
|
||||||
pub fn overwrite(state: State, path: PathBuf) -> Result<(), TomlError> {
|
pub fn save(&self) -> Result<(), TomlError> {
|
||||||
|
let path = Self::get_path()?;
|
||||||
info!("Starting TOML overwrite...");
|
info!("Starting TOML overwrite...");
|
||||||
let string = match toml::ser::to_string(&state) {
|
let string = match toml::ser::to_string(&self) {
|
||||||
Ok(string) => {
|
Ok(string) => {
|
||||||
info!("TOML parse ... OK");
|
info!("TOML parse ... OK");
|
||||||
eprint!("{}", string);
|
info!("{}", HORIZONTAL);
|
||||||
|
for i in string.lines() { info!("{}", i); }
|
||||||
|
info!("{}", HORIZONTAL);
|
||||||
string
|
string
|
||||||
},
|
},
|
||||||
Err(err) => { error!("Couldn't parse TOML into string"); return Err(TomlError::Serialize(err)) },
|
Err(err) => { error!("Couldn't parse TOML into string"); return Err(TomlError::Serialize(err)) },
|
||||||
};
|
};
|
||||||
match fs::write(&path, string) {
|
match fs::write(path, string) {
|
||||||
Ok(_) => { info!("TOML overwrite ... OK"); Ok(()) },
|
Ok(_) => { info!("TOML overwrite ... OK"); Ok(()) },
|
||||||
Err(err) => { error!("Couldn't overwrite TOML file"); return Err(TomlError::Io(err)) },
|
Err(err) => { error!("Couldn't overwrite TOML file"); return Err(TomlError::Io(err)) },
|
||||||
}
|
}
|
||||||
|
@ -176,7 +183,7 @@ impl From<std::io::Error> for TomlError {
|
||||||
//---------------------------------------------------------------------------------------------------- Const
|
//---------------------------------------------------------------------------------------------------- Const
|
||||||
const FILENAME: &'static str = "gupax.toml";
|
const FILENAME: &'static str = "gupax.toml";
|
||||||
const ERROR: &'static str = "TOML Error";
|
const ERROR: &'static str = "TOML Error";
|
||||||
const PATH_ERROR: &'static str = "PATH for state directory could not be not found";
|
const PATH_ERROR: &'static str = "PATH for state directory could not be not found";
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
const DIRECTORY: &'static str = "Gupax";
|
const DIRECTORY: &'static str = "Gupax";
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -218,6 +225,7 @@ pub struct State {
|
||||||
pub struct Gupax {
|
pub struct Gupax {
|
||||||
pub auto_update: bool,
|
pub auto_update: bool,
|
||||||
pub ask_before_quit: bool,
|
pub ask_before_quit: bool,
|
||||||
|
pub save_before_quit: bool,
|
||||||
pub p2pool_path: String,
|
pub p2pool_path: String,
|
||||||
pub xmrig_path: String,
|
pub xmrig_path: String,
|
||||||
}
|
}
|
||||||
|
@ -234,6 +242,8 @@ pub struct P2pool {
|
||||||
pub rpc: u16,
|
pub rpc: u16,
|
||||||
pub zmq: u16,
|
pub zmq: u16,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
|
// pub config: String,
|
||||||
|
// pub args: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
||||||
|
@ -248,6 +258,8 @@ pub struct Xmrig {
|
||||||
pub priority: u8,
|
pub priority: u8,
|
||||||
pub pool: String,
|
pub pool: String,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
|
// pub config: String,
|
||||||
|
// pub args: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
||||||
|
|
Loading…
Reference in a new issue