2022-10-01 16:58:22 +00:00
|
|
|
// Gupax - GUI Uniting P2Pool And XMRig
|
|
|
|
//
|
|
|
|
// Copyright (c) 2022 hinto-janaiyo
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
2022-10-15 19:15:27 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- Imports
|
|
|
|
// egui/eframe
|
2022-10-17 02:28:41 +00:00
|
|
|
use egui::Ui;
|
2022-10-15 19:15:27 +00:00
|
|
|
use egui::TextStyle::*;
|
2022-10-01 16:58:22 +00:00
|
|
|
use egui::color::Color32;
|
|
|
|
use egui::FontFamily::Proportional;
|
2022-10-15 19:15:27 +00:00
|
|
|
use egui::{FontId,Label,RichText,Stroke,Vec2,Pos2};
|
2022-10-17 00:36:58 +00:00
|
|
|
use egui::special_emojis::GITHUB;
|
2022-10-01 16:58:22 +00:00
|
|
|
use egui_extras::RetainedImage;
|
2022-10-15 19:15:27 +00:00
|
|
|
use eframe::{egui,NativeOptions};
|
|
|
|
|
|
|
|
// Logging
|
2022-10-01 16:58:22 +00:00
|
|
|
use log::*;
|
2022-10-15 19:15:27 +00:00
|
|
|
use env_logger::{Builder,WriteStyle};
|
|
|
|
|
|
|
|
// std
|
2022-10-01 16:58:22 +00:00
|
|
|
use std::io::Write;
|
2022-10-15 19:15:27 +00:00
|
|
|
use std::process::exit;
|
2022-10-14 21:13:38 +00:00
|
|
|
use std::sync::{Arc,Mutex};
|
2022-10-16 21:29:24 +00:00
|
|
|
use std::{thread,env};
|
2022-10-15 19:15:27 +00:00
|
|
|
use std::time::Instant;
|
2022-10-16 21:29:24 +00:00
|
|
|
use std::path::PathBuf;
|
2022-10-01 16:58:22 +00:00
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
// Modules
|
2022-10-18 19:26:21 +00:00
|
|
|
mod ferris;
|
2022-10-01 16:58:22 +00:00
|
|
|
mod constants;
|
2022-10-14 21:13:38 +00:00
|
|
|
mod node;
|
2022-10-15 19:15:27 +00:00
|
|
|
mod state;
|
2022-10-01 16:58:22 +00:00
|
|
|
mod about;
|
|
|
|
mod status;
|
|
|
|
mod gupax;
|
|
|
|
mod p2pool;
|
|
|
|
mod xmrig;
|
2022-10-25 02:58:42 +00:00
|
|
|
mod update;
|
|
|
|
use {ferris::*,constants::*,node::*,state::*,about::*,status::*,gupax::*,p2pool::*,xmrig::*,update::*};
|
2022-10-01 16:58:22 +00:00
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Struct + Impl
|
|
|
|
// The state of the outer main [App].
|
|
|
|
// See the [State] struct in [state.rs] for the
|
|
|
|
// actual inner state of the tab settings.
|
2022-10-01 16:58:22 +00:00
|
|
|
pub struct App {
|
2022-10-15 19:15:27 +00:00
|
|
|
// Misc state
|
|
|
|
tab: Tab, // What tab are we on?
|
2022-10-16 21:29:24 +00:00
|
|
|
quit: bool, // Was the quit button clicked?
|
|
|
|
quit_confirm: bool, // Was the quit confirmed?
|
|
|
|
ping: bool, // Was the ping button clicked?
|
|
|
|
pinging: Arc<Mutex<bool>>, // Is a ping in progress?
|
2022-10-15 19:15:27 +00:00
|
|
|
node: Arc<Mutex<NodeStruct>>, // Data on community nodes
|
2022-10-17 02:28:41 +00:00
|
|
|
width: f32, // Top-level width
|
|
|
|
height: f32, // Top-level height
|
2022-10-25 02:58:42 +00:00
|
|
|
// State
|
|
|
|
og: State, // og = Old state to compare against
|
|
|
|
state: State, // state = Working state (current settings)
|
2022-10-27 03:15:56 +00:00
|
|
|
update: Update, // State for update data [update.rs]
|
2022-10-25 02:58:42 +00:00
|
|
|
diff: bool, // Instead of comparing [og == state] every frame, this bool indicates changes
|
2022-10-16 21:29:24 +00:00
|
|
|
// 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?
|
|
|
|
// State from [--flags]
|
|
|
|
startup: bool,
|
|
|
|
reset: bool,
|
2022-10-15 19:15:27 +00:00
|
|
|
// Static stuff
|
2022-10-16 21:29:24 +00:00
|
|
|
now: Instant, // Internal timer
|
2022-10-19 18:35:32 +00:00
|
|
|
exe: String, // Path for [Gupax] binary
|
|
|
|
tmp: String, // Tmp folder for updates, random every update
|
2022-10-16 21:29:24 +00:00
|
|
|
resolution: Vec2, // Frame resolution
|
|
|
|
os: &'static str, // OS
|
|
|
|
version: String, // Gupax version
|
|
|
|
name_version: String, // [Gupax vX.X.X]
|
|
|
|
banner: RetainedImage, // Gupax banner image
|
2022-10-01 16:58:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl App {
|
2022-10-16 21:29:24 +00:00
|
|
|
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);
|
2022-10-01 16:58:22 +00:00
|
|
|
Self {
|
2022-10-16 21:29:24 +00:00
|
|
|
resolution,
|
|
|
|
..app
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 00:36:58 +00:00
|
|
|
fn new() -> Self {
|
2022-10-16 21:29:24 +00:00
|
|
|
let app = Self {
|
2022-10-15 19:15:27 +00:00
|
|
|
tab: Tab::default(),
|
|
|
|
quit: false,
|
|
|
|
quit_confirm: false,
|
2022-10-14 21:13:38 +00:00
|
|
|
ping: false,
|
2022-10-16 21:29:24 +00:00
|
|
|
pinging: Arc::new(Mutex::new(false)),
|
2022-10-17 02:28:41 +00:00
|
|
|
width: 1280.0,
|
|
|
|
height: 720.0,
|
2022-10-15 19:15:27 +00:00
|
|
|
node: Arc::new(Mutex::new(NodeStruct::default())),
|
|
|
|
og: State::default(),
|
|
|
|
state: State::default(),
|
2022-10-27 03:15:56 +00:00
|
|
|
update: Update::new(PathBuf::new(), PathBuf::new(), true),
|
2022-10-15 19:15:27 +00:00
|
|
|
diff: false,
|
2022-10-16 21:29:24 +00:00
|
|
|
p2pool: false,
|
|
|
|
xmrig: false,
|
|
|
|
startup: true,
|
|
|
|
reset: false,
|
2022-10-15 19:15:27 +00:00
|
|
|
now: Instant::now(),
|
2022-10-19 18:35:32 +00:00
|
|
|
exe: "".to_string(),
|
|
|
|
tmp: "".to_string(),
|
2022-10-16 21:29:24 +00:00
|
|
|
resolution: Vec2::new(1280.0, 720.0),
|
2022-10-15 19:15:27 +00:00
|
|
|
os: OS,
|
2022-10-17 00:36:58 +00:00
|
|
|
version: format!("{}", GUPAX_VERSION),
|
|
|
|
name_version: format!("Gupax {}", GUPAX_VERSION),
|
2022-10-15 19:15:27 +00:00
|
|
|
banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).expect("oops"),
|
2022-10-16 21:29:24 +00:00
|
|
|
};
|
2022-10-17 00:36:58 +00:00
|
|
|
// Apply arg state
|
|
|
|
let mut app = parse_args(app);
|
2022-10-25 02:58:42 +00:00
|
|
|
// Get exe path + random tmp folder
|
2022-10-19 18:35:32 +00:00
|
|
|
app.exe = match get_exe_dir() {
|
|
|
|
Ok(exe) => exe,
|
|
|
|
Err(err) => { panic_app(err.to_string()); exit(1); },
|
|
|
|
};
|
|
|
|
app.tmp = get_rand_tmp(&app.exe);
|
2022-10-17 00:36:58 +00:00
|
|
|
// Read disk state if no [--reset] arg
|
|
|
|
if app.reset == false {
|
|
|
|
app.og = match State::get() {
|
|
|
|
Ok(toml) => toml,
|
2022-10-19 18:35:32 +00:00
|
|
|
Err(err) => { panic_app(err.to_string()); exit(1); },
|
2022-10-17 00:36:58 +00:00
|
|
|
};
|
|
|
|
}
|
2022-10-27 03:15:56 +00:00
|
|
|
app.state = app.og.clone();
|
|
|
|
// Handle max threads
|
2022-10-17 00:36:58 +00:00
|
|
|
app.og.xmrig.max_threads = num_cpus::get();
|
|
|
|
if app.og.xmrig.current_threads > app.og.xmrig.max_threads { app.og.xmrig.current_threads = app.og.xmrig.max_threads; }
|
2022-10-27 03:15:56 +00:00
|
|
|
// Apply TOML values to [Update]
|
|
|
|
app.update = Update::new(app.og.gupax.absolute_p2pool_path.clone(), app.og.gupax.absolute_xmrig_path.clone(), app.og.gupax.update_via_tor);
|
2022-10-17 00:36:58 +00:00
|
|
|
app
|
2022-10-01 16:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Enum + Impl
|
2022-10-01 16:58:22 +00:00
|
|
|
// The tabs inside [App].
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
enum Tab {
|
|
|
|
About,
|
|
|
|
Status,
|
|
|
|
Gupax,
|
|
|
|
P2pool,
|
|
|
|
Xmrig,
|
|
|
|
}
|
2022-10-15 19:15:27 +00:00
|
|
|
|
2022-10-01 16:58:22 +00:00
|
|
|
impl Default for Tab {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::About
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Init functions
|
2022-10-01 16:58:22 +00:00
|
|
|
fn init_text_styles(ctx: &egui::Context, width: f32) {
|
|
|
|
let scale = width / 26.666;
|
|
|
|
let mut style = (*ctx.style()).clone();
|
|
|
|
style.text_styles = [
|
|
|
|
// (Small, FontId::new(10.0, Proportional)),
|
|
|
|
// (Body, FontId::new(25.0, Proportional)),
|
|
|
|
// (Button, FontId::new(25.0, Proportional)),
|
|
|
|
// (Monospace, FontId::new(25.0, Proportional)),
|
|
|
|
// (Heading, FontId::new(30.0, Proportional)),
|
|
|
|
// (Name("Tab".into()), FontId::new(50.0, Proportional)),
|
|
|
|
// (Name("Bottom".into()), FontId::new(25.0, Proportional)),
|
|
|
|
(Small, FontId::new(scale/3.0, Proportional)),
|
|
|
|
(Body, FontId::new(scale/2.0, Proportional)),
|
|
|
|
(Button, FontId::new(scale/2.0, Proportional)),
|
|
|
|
(Monospace, FontId::new(scale/2.0, Proportional)),
|
|
|
|
(Heading, FontId::new(scale/1.5, Proportional)),
|
|
|
|
(Name("Tab".into()), FontId::new(scale*1.2, Proportional)),
|
|
|
|
(Name("Bottom".into()), FontId::new(scale/2.0, Proportional)),
|
|
|
|
].into();
|
|
|
|
// style.spacing.slider_width = scale;
|
|
|
|
// style.spacing.text_edit_width = scale;
|
|
|
|
// style.spacing.button_padding = Vec2::new(scale/2.0, scale/2.0);
|
|
|
|
ctx.set_style(style);
|
|
|
|
ctx.set_pixels_per_point(1.0);
|
2022-10-13 12:57:50 +00:00
|
|
|
ctx.request_repaint();
|
2022-10-01 16:58:22 +00:00
|
|
|
}
|
|
|
|
|
2022-10-13 12:57:50 +00:00
|
|
|
fn init_logger() {
|
2022-10-27 03:15:56 +00:00
|
|
|
// #[cfg(debug_assertions)]
|
2022-10-16 21:29:24 +00:00
|
|
|
let filter = LevelFilter::Info;
|
2022-10-27 03:15:56 +00:00
|
|
|
// #[cfg(not(debug_assertions))]
|
|
|
|
// let filter = LevelFilter::Warn;
|
2022-10-01 16:58:22 +00:00
|
|
|
use env_logger::fmt::Color;
|
|
|
|
Builder::new().format(|buf, record| {
|
|
|
|
let level;
|
|
|
|
let mut style = buf.style();
|
|
|
|
match record.level() {
|
|
|
|
Level::Error => { style.set_color(Color::Red); level = "ERROR" },
|
2022-10-13 12:57:50 +00:00
|
|
|
Level::Warn => { style.set_color(Color::Yellow); level = "WARN" },
|
|
|
|
Level::Info => { style.set_color(Color::White); level = "INFO" },
|
2022-10-01 16:58:22 +00:00
|
|
|
Level::Debug => { style.set_color(Color::Blue); level = "DEBUG" },
|
|
|
|
Level::Trace => { style.set_color(Color::Magenta); level = "TRACE" },
|
|
|
|
};
|
|
|
|
writeln!(
|
|
|
|
buf,
|
2022-10-13 12:57:50 +00:00
|
|
|
"[{}] [{}] [{}:{}] {}",
|
2022-10-01 16:58:22 +00:00
|
|
|
style.set_bold(true).value(level),
|
|
|
|
buf.style().set_dimmed(true).value(chrono::Local::now().format("%F %T%.3f")),
|
|
|
|
buf.style().set_dimmed(true).value(record.file().unwrap_or("???")),
|
|
|
|
buf.style().set_dimmed(true).value(record.line().unwrap_or(0)),
|
|
|
|
record.args(),
|
|
|
|
)
|
2022-10-16 21:29:24 +00:00
|
|
|
}).filter_level(filter).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().init();
|
2022-10-13 12:57:50 +00:00
|
|
|
info!("init_logger() ... OK");
|
|
|
|
}
|
2022-10-01 16:58:22 +00:00
|
|
|
|
2022-10-13 12:57:50 +00:00
|
|
|
fn init_options() -> NativeOptions {
|
2022-10-01 16:58:22 +00:00
|
|
|
let mut options = eframe::NativeOptions::default();
|
2022-10-27 03:15:56 +00:00
|
|
|
options.min_window_size = Option::from(Vec2::new(854.0, 480.0));
|
2022-10-01 16:58:22 +00:00
|
|
|
options.max_window_size = Option::from(Vec2::new(3180.0, 2160.0));
|
|
|
|
options.initial_window_size = Option::from(Vec2::new(1280.0, 720.0));
|
|
|
|
options.follow_system_theme = false;
|
|
|
|
options.default_theme = eframe::Theme::Dark;
|
2022-10-13 12:57:50 +00:00
|
|
|
let icon = image::load_from_memory(BYTES_ICON).expect("Failed to read icon bytes").to_rgba8();
|
2022-10-01 16:58:22 +00:00
|
|
|
let (icon_width, icon_height) = icon.dimensions();
|
|
|
|
options.icon_data = Some(eframe::IconData {
|
|
|
|
rgba: icon.into_raw(),
|
|
|
|
width: icon_width,
|
|
|
|
height: icon_height,
|
|
|
|
});
|
2022-10-13 12:57:50 +00:00
|
|
|
info!("init_options() ... OK");
|
|
|
|
options
|
|
|
|
}
|
|
|
|
|
2022-10-16 21:29:24 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Misc functions
|
|
|
|
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" => {
|
2022-10-17 00:36:58 +00:00
|
|
|
println!("Gupax | {}\nP2Pool | {}\nXMRig | {}\n\nOS: [{}], Commit: [{}]\n\n{}", GUPAX_VERSION, P2POOL_VERSION, XMRIG_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT);
|
2022-10-16 21:29:24 +00:00
|
|
|
exit(0);
|
|
|
|
},
|
2022-10-18 19:26:21 +00:00
|
|
|
"-f"|"--ferris" => { println!("{}", FERRIS); exit(0); },
|
2022-10-16 21:29:24 +00:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2022-10-25 02:58:42 +00:00
|
|
|
// Get absolute [Gupax] binary path
|
|
|
|
pub fn get_exe() -> Result<String, std::io::Error> {
|
2022-10-19 18:35:32 +00:00
|
|
|
match std::env::current_exe() {
|
2022-10-25 02:58:42 +00:00
|
|
|
Ok(mut path) => { Ok(path.display().to_string()) },
|
2022-10-19 18:35:32 +00:00
|
|
|
Err(err) => { error!("Couldn't get exe basepath PATH"); return Err(err) },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-25 02:58:42 +00:00
|
|
|
// Get absolute [Gupax] directory path
|
|
|
|
pub fn get_exe_dir() -> Result<String, std::io::Error> {
|
|
|
|
match std::env::current_exe() {
|
|
|
|
Ok(mut path) => { path.pop(); Ok(path.display().to_string()) },
|
|
|
|
Err(err) => { error!("Couldn't get exe basepath PATH"); return Err(err) },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_rand_tmp(path: &String) -> String {
|
2022-10-19 18:35:32 +00:00
|
|
|
use rand::{thread_rng, Rng};
|
|
|
|
use rand::distributions::Alphanumeric;
|
|
|
|
let rand: String = thread_rng()
|
|
|
|
.sample_iter(&Alphanumeric)
|
|
|
|
.take(10)
|
|
|
|
.map(char::from)
|
|
|
|
.collect();
|
|
|
|
let path = path.to_string() + "/gupax_tmp_" + &rand;
|
|
|
|
info!("Generated rand_tmp ... {}", path);
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
|
|
|
fn panic_app(error: String) {
|
|
|
|
error!("{}", error);
|
|
|
|
let options = Panic::options();
|
|
|
|
eframe::run_native("Gupax", options, Box::new(|cc| Box::new(Panic::new(cc, error))),);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- [App] frame for [Panic] situations
|
2022-10-14 21:13:38 +00:00
|
|
|
struct Panic { error_msg: String, }
|
|
|
|
impl Panic {
|
|
|
|
fn options() -> NativeOptions {
|
|
|
|
let mut options = eframe::NativeOptions::default();
|
|
|
|
let frame = Option::from(Vec2::new(1280.0, 720.0));
|
|
|
|
options.min_window_size = frame;
|
|
|
|
options.max_window_size = frame;
|
|
|
|
options.initial_window_size = frame;
|
|
|
|
options.follow_system_theme = false;
|
|
|
|
options.default_theme = eframe::Theme::Dark;
|
|
|
|
let icon = image::load_from_memory(BYTES_ICON).expect("Failed to read icon bytes").to_rgba8();
|
|
|
|
let (icon_width, icon_height) = icon.dimensions();
|
|
|
|
options.icon_data = Some(eframe::IconData {
|
|
|
|
rgba: icon.into_raw(),
|
|
|
|
width: icon_width,
|
|
|
|
height: icon_height,
|
|
|
|
});
|
|
|
|
info!("Panic::options() ... OK");
|
|
|
|
options
|
|
|
|
}
|
|
|
|
fn new(cc: &eframe::CreationContext<'_>, error_msg: String) -> Self {
|
|
|
|
let resolution = cc.integration_info.window_info.size;
|
|
|
|
init_text_styles(&cc.egui_ctx, resolution[0] as f32);
|
|
|
|
Self { error_msg }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl eframe::App for Panic {
|
|
|
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
|
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
|
|
|
let width = ui.available_width();
|
|
|
|
let height = ui.available_height();
|
|
|
|
init_text_styles(ctx, width);
|
|
|
|
ui.add_sized([width, height/8.0], Label::new("Gupax has encountered a fatal error:"));
|
|
|
|
ui.add_sized([width, height/8.0], Label::new(&self.error_msg));
|
|
|
|
ui.add_sized([width, height/3.0], Label::new("Please report to: https://github.com/hinto-janaiyo/gupax/issues"));
|
|
|
|
ui.add_sized([width, height/3.0], egui::Button::new("Quit")).clicked() && exit(1)
|
|
|
|
});
|
|
|
|
}
|
2022-10-01 16:58:22 +00:00
|
|
|
}
|
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Main [App] frame
|
|
|
|
fn main() {
|
|
|
|
init_logger();
|
|
|
|
let options = init_options();
|
2022-10-27 03:15:56 +00:00
|
|
|
let app = App::new();
|
2022-10-16 21:29:24 +00:00
|
|
|
eframe::run_native("Gupax", options, Box::new(|cc| Box::new(App::cc(cc, app))),);
|
2022-10-15 19:15:27 +00:00
|
|
|
}
|
|
|
|
|
2022-10-01 16:58:22 +00:00
|
|
|
impl eframe::App for App {
|
2022-10-13 12:57:50 +00:00
|
|
|
fn on_close_event(&mut self) -> bool {
|
2022-10-15 19:15:27 +00:00
|
|
|
self.quit = true;
|
2022-10-17 00:36:58 +00:00
|
|
|
if self.og.gupax.ask_before_quit {
|
|
|
|
self.quit_confirm
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
2022-10-13 12:57:50 +00:00
|
|
|
}
|
2022-10-15 19:15:27 +00:00
|
|
|
|
2022-10-13 12:57:50 +00:00
|
|
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
2022-10-25 02:58:42 +00:00
|
|
|
// *-------*
|
|
|
|
// | DEBUG |
|
|
|
|
// *-------*
|
2022-10-27 03:15:56 +00:00
|
|
|
|
2022-10-17 02:28:41 +00:00
|
|
|
// This sets the top level Ui dimensions.
|
|
|
|
// Used as a reference for other uis.
|
|
|
|
egui::CentralPanel::default().show(ctx, |ui| { self.width = ui.available_width(); self.height = ui.available_height(); });
|
|
|
|
// This sets fonts globally depending on the width.
|
|
|
|
init_text_styles(ctx, self.width);
|
|
|
|
|
2022-10-14 21:13:38 +00:00
|
|
|
// Close confirmation.
|
2022-10-15 19:15:27 +00:00
|
|
|
if self.quit {
|
2022-10-18 19:26:21 +00:00
|
|
|
// If [ask_before_quit == true]
|
|
|
|
if self.state.gupax.ask_before_quit {
|
|
|
|
egui::TopBottomPanel::bottom("quit").show(ctx, |ui| {
|
|
|
|
let width = self.width;
|
|
|
|
let height = self.height/8.0;
|
|
|
|
ui.group(|ui| {
|
|
|
|
if ui.add_sized([width, height], egui::Button::new("Yes")).clicked() {
|
|
|
|
if self.state.gupax.save_before_quit {
|
|
|
|
if self.diff {
|
|
|
|
info!("Saving before quit...");
|
|
|
|
match self.state.save() {
|
|
|
|
Err(err) => { error!("{}", err); exit(1); },
|
|
|
|
_ => (),
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
info!("No changed detected, not saving...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
info!("Quit confirmation = yes ... goodbye!");
|
|
|
|
exit(0);
|
|
|
|
} else if ui.add_sized([width, height], egui::Button::new("No")).clicked() {
|
|
|
|
self.quit = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
|
|
|
let width = self.width;
|
|
|
|
let height = ui.available_height();
|
|
|
|
let ten = height/10.0;
|
|
|
|
// Detect processes or update
|
|
|
|
ui.add_space(ten);
|
|
|
|
// || self.update.updating
|
|
|
|
if self.p2pool || self.xmrig {
|
|
|
|
ui.add_sized([width, height/4.0], Label::new("Are you sure you want to quit?"));
|
|
|
|
// if self.update.updating { ui.add_sized([width, ten], Label::new("Update is in progress...!")); }
|
|
|
|
if self.p2pool { ui.add_sized([width, ten], Label::new("P2Pool is online...!")); }
|
|
|
|
if self.xmrig { ui.add_sized([width, ten], Label::new("XMRig is online...!")); }
|
|
|
|
// Else, just quit
|
|
|
|
} else {
|
2022-10-17 02:28:41 +00:00
|
|
|
if self.state.gupax.save_before_quit {
|
2022-10-18 19:26:21 +00:00
|
|
|
if self.diff {
|
|
|
|
info!("Saving before quit...");
|
|
|
|
match self.state.save() {
|
|
|
|
Err(err) => { error!("{}", err); exit(1); },
|
|
|
|
_ => (),
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
info!("No changed detected, not saving...");
|
|
|
|
}
|
2022-10-17 02:28:41 +00:00
|
|
|
}
|
2022-10-18 19:26:21 +00:00
|
|
|
info!("No processes or update in progress ... goodbye!");
|
2022-10-17 02:28:41 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
});
|
2022-10-18 19:26:21 +00:00
|
|
|
// Else, quit (save if [save_before_quit == true]
|
|
|
|
} else {
|
|
|
|
if self.state.gupax.save_before_quit {
|
|
|
|
if self.diff {
|
2022-10-16 21:29:24 +00:00
|
|
|
info!("Saving before quit...");
|
|
|
|
match self.state.save() {
|
|
|
|
Err(err) => { error!("{}", err); exit(1); },
|
|
|
|
_ => (),
|
|
|
|
};
|
2022-10-18 19:26:21 +00:00
|
|
|
} else {
|
|
|
|
info!("No changed detected, not saving...");
|
2022-10-13 12:57:50 +00:00
|
|
|
}
|
2022-10-16 21:29:24 +00:00
|
|
|
}
|
2022-10-18 19:26:21 +00:00
|
|
|
info!("Quit confirmation = yes ... goodbye!");
|
|
|
|
exit(0);
|
|
|
|
}
|
2022-10-13 12:57:50 +00:00
|
|
|
return
|
|
|
|
}
|
2022-10-14 21:13:38 +00:00
|
|
|
|
2022-10-01 16:58:22 +00:00
|
|
|
// Top: Tabs
|
2022-10-17 02:28:41 +00:00
|
|
|
egui::TopBottomPanel::top("top").show(ctx, |ui| {
|
|
|
|
let width = (self.width - 95.0)/5.0;
|
|
|
|
let height = self.height/10.0;
|
|
|
|
ui.group(|ui| {
|
|
|
|
ui.add_space(4.0);
|
|
|
|
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.selection.bg_fill = Color32::from_rgb(255, 120, 120);
|
|
|
|
ui.style_mut().visuals.selection.stroke = Stroke {
|
|
|
|
width: 5.0,
|
|
|
|
color: Color32::from_rgb(255, 255, 255),
|
|
|
|
};
|
|
|
|
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::About, "About")).clicked() { self.tab = Tab::About; }
|
|
|
|
ui.separator();
|
|
|
|
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::Status, "Status")).clicked() { self.tab = Tab::Status; }
|
|
|
|
ui.separator();
|
|
|
|
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::Gupax, "Gupax")).clicked() { self.tab = Tab::Gupax; }
|
|
|
|
ui.separator();
|
|
|
|
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::P2pool, "P2Pool")).clicked() { self.tab = Tab::P2pool; }
|
|
|
|
ui.separator();
|
|
|
|
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::Xmrig, "XMRig")).clicked() { self.tab = Tab::Xmrig; }
|
|
|
|
});
|
|
|
|
ui.add_space(4.0);
|
2022-10-01 16:58:22 +00:00
|
|
|
});
|
2022-10-17 02:28:41 +00:00
|
|
|
});
|
2022-10-01 16:58:22 +00:00
|
|
|
|
|
|
|
// Bottom: app info + state/process buttons
|
|
|
|
egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
2022-10-17 02:28:41 +00:00
|
|
|
let width = self.width/8.0;
|
|
|
|
let height = self.height/15.0;
|
2022-10-01 16:58:22 +00:00
|
|
|
ui.style_mut().override_text_style = Some(Name("Bottom".into()));
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.group(|ui| {
|
2022-10-17 00:36:58 +00:00
|
|
|
ui.add_sized([width, height], Label::new(&*self.name_version));
|
2022-10-01 16:58:22 +00:00
|
|
|
ui.separator();
|
|
|
|
ui.add_sized([width, height], Label::new(self.os));
|
|
|
|
ui.separator();
|
|
|
|
ui.add_sized([width/1.5, height], Label::new("P2Pool"));
|
2022-10-17 00:36:58 +00:00
|
|
|
if self.p2pool {
|
2022-10-01 16:58:22 +00:00
|
|
|
ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(100, 230, 100))));
|
|
|
|
} else {
|
|
|
|
ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(230, 50, 50))));
|
|
|
|
}
|
|
|
|
ui.separator();
|
|
|
|
ui.add_sized([width/1.5, height], Label::new("XMRig"));
|
2022-10-17 00:36:58 +00:00
|
|
|
if self.xmrig {
|
2022-10-01 16:58:22 +00:00
|
|
|
ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(100, 230, 100))));
|
|
|
|
} else {
|
|
|
|
ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(230, 50, 50))));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| {
|
|
|
|
ui.group(|ui| {
|
|
|
|
if self.state == self.og {
|
|
|
|
ui.set_enabled(false)
|
|
|
|
}
|
|
|
|
let width = width / 2.0;
|
2022-10-17 00:36:58 +00:00
|
|
|
if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { self.og = self.state.clone(); self.state.save(); }
|
2022-10-01 16:58:22 +00:00
|
|
|
if ui.add_sized([width, height], egui::Button::new("Reset")).on_hover_text("Reset changes").clicked() { self.state = self.og.clone(); }
|
|
|
|
});
|
|
|
|
|
|
|
|
let width = (ui.available_width() / 3.0) - 6.2;
|
|
|
|
match self.tab {
|
|
|
|
Tab::P2pool => {
|
|
|
|
ui.group(|ui| {
|
2022-10-17 00:36:58 +00:00
|
|
|
if self.p2pool {
|
2022-10-01 16:58:22 +00:00
|
|
|
if ui.add_sized([width, height], egui::Button::new("⟲")).on_hover_text("Restart P2Pool").clicked() { self.p2pool = false; }
|
|
|
|
if ui.add_sized([width, height], egui::Button::new("⏹")).on_hover_text("Stop P2Pool").clicked() { self.p2pool = false; }
|
|
|
|
ui.add_enabled_ui(false, |ui| {
|
|
|
|
ui.add_sized([width, height], egui::Button::new("⏺")).on_hover_text("Start P2Pool");
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
ui.add_enabled_ui(false, |ui| {
|
|
|
|
ui.add_sized([width, height], egui::Button::new("⟲")).on_hover_text("Restart P2Pool");
|
|
|
|
ui.add_sized([width, height], egui::Button::new("⏹")).on_hover_text("Stop P2Pool");
|
|
|
|
});
|
|
|
|
if ui.add_sized([width, height], egui::Button::new("⏺")).on_hover_text("Start P2Pool").clicked() { self.p2pool = true; }
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Tab::Xmrig => {
|
|
|
|
ui.group(|ui| {
|
2022-10-17 00:36:58 +00:00
|
|
|
if self.xmrig {
|
2022-10-01 16:58:22 +00:00
|
|
|
if ui.add_sized([width, height], egui::Button::new("⟲")).on_hover_text("Restart XMRig").clicked() { self.xmrig = false; }
|
|
|
|
if ui.add_sized([width, height], egui::Button::new("⏹")).on_hover_text("Stop XMRig").clicked() { self.xmrig = false; }
|
|
|
|
ui.add_enabled_ui(false, |ui| {
|
|
|
|
ui.add_sized([width, height], egui::Button::new("⏺")).on_hover_text("Start XMRig");
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
ui.add_enabled_ui(false, |ui| {
|
|
|
|
ui.add_sized([width, height], egui::Button::new("⟲")).on_hover_text("Restart XMRig");
|
|
|
|
ui.add_sized([width, height], egui::Button::new("⏹")).on_hover_text("Stop XMRig");
|
|
|
|
});
|
|
|
|
if ui.add_sized([width, height], egui::Button::new("⏺")).on_hover_text("Start XMRig").clicked() { self.xmrig = true; }
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-10-17 02:28:41 +00:00
|
|
|
// If ping was pressed, start thread
|
|
|
|
if self.ping {
|
|
|
|
self.ping = false;
|
|
|
|
self.pinging = Arc::new(Mutex::new(true));
|
|
|
|
let node_clone = Arc::clone(&self.node);
|
|
|
|
let pinging_clone = Arc::clone(&self.pinging);
|
|
|
|
thread::spawn(move|| {
|
|
|
|
let result = NodeStruct::ping();
|
|
|
|
*node_clone.lock().unwrap() = result.nodes;
|
|
|
|
*pinging_clone.lock().unwrap() = false;
|
|
|
|
});
|
|
|
|
}
|
2022-10-17 00:36:58 +00:00
|
|
|
|
2022-10-27 03:15:56 +00:00
|
|
|
// Middle panel, contents of the [Tab]
|
2022-10-17 02:28:41 +00:00
|
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
2022-10-27 03:15:56 +00:00
|
|
|
// This sets the Ui dimensions after Top/Bottom are filled
|
|
|
|
self.width = ui.available_width();
|
|
|
|
self.height = ui.available_height();
|
2022-10-17 02:28:41 +00:00
|
|
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Body);
|
2022-10-27 03:15:56 +00:00
|
|
|
match self.tab {
|
|
|
|
Tab::About => {
|
2022-10-27 15:52:18 +00:00
|
|
|
info!("");
|
2022-10-17 02:28:41 +00:00
|
|
|
ui.add_space(10.0);
|
|
|
|
ui.vertical_centered(|ui| {
|
2022-10-27 03:15:56 +00:00
|
|
|
// Display [Gupax] banner at max, 1/4 the available length
|
|
|
|
self.banner.show_max_size(ui, Vec2::new(self.width, self.height/4.0));
|
|
|
|
ui.label("Gupax is a cross-platform GUI for mining");
|
2022-10-17 02:28:41 +00:00
|
|
|
ui.hyperlink_to("[Monero]", "https://www.github.com/monero-project/monero");
|
|
|
|
ui.label("on the decentralized");
|
|
|
|
ui.hyperlink_to("[P2Pool]", "https://www.github.com/SChernykh/p2pool");
|
|
|
|
ui.label("using the dedicated");
|
|
|
|
ui.hyperlink_to("[XMRig]", "https://www.github.com/xmrig/xmrig");
|
|
|
|
ui.label("miner for max hashrate");
|
2022-10-17 00:36:58 +00:00
|
|
|
|
2022-10-27 03:15:56 +00:00
|
|
|
ui.add_space(ui.available_height()/2.0);
|
2022-10-17 02:28:41 +00:00
|
|
|
ui.hyperlink_to("Powered by egui", "https://github.com/emilk/egui");
|
|
|
|
ui.hyperlink_to(format!("{} {}", GITHUB, "Gupax made by hinto-janaiyo"), "https://www.github.com/hinto-janaiyo/gupax");
|
|
|
|
ui.label("egui is licensed under MIT & Apache-2.0");
|
|
|
|
ui.label("Gupax, P2Pool, and XMRig are licensed under GPLv3");
|
|
|
|
});
|
2022-10-27 03:15:56 +00:00
|
|
|
}
|
|
|
|
Tab::Status => {
|
|
|
|
Status::show(self, self.width, self.height, ctx, ui);
|
|
|
|
}
|
|
|
|
Tab::Gupax => {
|
|
|
|
Gupax::show(&mut self.state.gupax, self.width, self.height, &mut self.update, self.og.version.clone(), ctx, ui);
|
|
|
|
}
|
|
|
|
Tab::P2pool => {
|
|
|
|
P2pool::show(&mut self.state.p2pool, self.width, self.height, ctx, ui);
|
|
|
|
}
|
|
|
|
Tab::Xmrig => {
|
|
|
|
Xmrig::show(&mut self.state.xmrig, self.width, self.height, ctx, ui);
|
|
|
|
}
|
|
|
|
}
|
2022-10-01 16:58:22 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|