mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-12-22 06:39:21 +00:00
add toml.rs/constants.rs, ask_before_quit screen
This commit is contained in:
parent
d315e5c7cb
commit
ab9b98a819
7 changed files with 453 additions and 46 deletions
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -133,6 +133,15 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.11.0"
|
||||
|
@ -346,6 +355,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
|
@ -427,6 +445,16 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cty"
|
||||
version = "0.2.2"
|
||||
|
@ -440,7 +468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"digest",
|
||||
"digest 0.9.0",
|
||||
"rand_core 0.5.1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
|
@ -490,6 +518,36 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
|
@ -950,15 +1008,21 @@ name = "gupax"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dirs",
|
||||
"eframe",
|
||||
"egui",
|
||||
"egui_extras",
|
||||
"env_logger",
|
||||
"hex-literal",
|
||||
"image",
|
||||
"log",
|
||||
"monero",
|
||||
"num_cpus",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sha2",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1699,6 +1763,17 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.7",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
|
@ -1820,6 +1895,17 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_library"
|
||||
version = "0.1.9"
|
||||
|
|
34
Cargo.toml
34
Cargo.toml
|
@ -4,27 +4,33 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
egui = "0.19.0"
|
||||
eframe = "0.19.0"
|
||||
egui_extras = { version = "0.19.0", features = ["image"] }
|
||||
image = { version = "0.24.4", features = ["png"] }
|
||||
num_cpus = "1.13.1"
|
||||
monero = "0.18.0"
|
||||
regex = "1.6.0"
|
||||
log = "0.4.17"
|
||||
env_logger = "0.9.1"
|
||||
dirs = "4.0.0"
|
||||
chrono = "0.4.22"
|
||||
eframe = "0.19.0"
|
||||
egui = "0.19.0"
|
||||
egui_extras = { version = "0.19.0", features = ["image"] }
|
||||
env_logger = "0.9.1"
|
||||
hex-literal = "0.3.4"
|
||||
image = { version = "0.24.4", features = ["png"] }
|
||||
log = "0.4.17"
|
||||
monero = "0.18.0"
|
||||
num_cpus = "1.13.1"
|
||||
regex = "1.6.0"
|
||||
serde = "1.0.145"
|
||||
serde_derive = "1.0.145"
|
||||
sha2 = "0.10.6"
|
||||
toml = "0.5.9"
|
||||
|
||||
[profile.optimized]
|
||||
inherits = "release"
|
||||
strip = "debuginfo"
|
||||
debug = false
|
||||
codegen-units = 1
|
||||
debug-assertions = false
|
||||
debug = false
|
||||
incremental = true
|
||||
inherits = "release"
|
||||
lto = true
|
||||
overflow-checks = false
|
||||
incremental = true
|
||||
codegen-units = 1
|
||||
rpath = false
|
||||
strip = "debuginfo"
|
||||
|
||||
[profile.optimized.package."*"]
|
||||
opt-level = 3
|
||||
|
|
15
build.sh
15
build.sh
|
@ -4,4 +4,17 @@ set -e
|
|||
|
||||
[[ $PWD = */gupax ]]
|
||||
|
||||
RUSTFLAGS="-C target-cpu=native" cargo build --profile optimized && du -hs target/optimized/gupax
|
||||
if [[ $1 = *all* ]]; then
|
||||
echo "=== building all ==="
|
||||
echo "=== windows ==="
|
||||
cargo build --profile optimized --target x86_64-pc-windows-gnu
|
||||
# echo "=== macos ==="
|
||||
# cargo build --profile optimized --target x86_64-apple-darwin
|
||||
echo "=== linux ==="
|
||||
cargo build --profile optimized
|
||||
du -hs target/x86_64-pc-windows-gnu/optimized/gupax target/x86_64-apple-darwin/optimized/gupax target/optimized/gupax
|
||||
else
|
||||
echo "=== building linux cpu optimized ==="
|
||||
RUSTFLAGS="-C target-cpu=native" cargo build --profile optimized
|
||||
du -hs target/optimized/gupax
|
||||
fi
|
||||
|
|
49
src/README.md
Normal file
49
src/README.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
# Gupax source files
|
||||
* [State](#State)
|
||||
* [Structure](#Structure)
|
||||
* [Bootstrap](#Bootstrap)
|
||||
|
||||
## Structure
|
||||
| File/Folder | Purpose |
|
||||
|----------------|---------|
|
||||
| `about.rs` | Struct/impl for `About` tab
|
||||
| `constants.rs` | General constants needed in Gupax
|
||||
| `gupax.rs` | Struct/impl for `Gupax` tab
|
||||
| `main.rs` | Struct/enum/impl for `App/Tab/State`, init functions, main function
|
||||
| `p2pool.rs` | Struct/impl for `P2Pool` tab
|
||||
| `status.rs` | Struct/impl for `Status` tab
|
||||
| `toml.rs` | Struct/impl for `gupax.toml`, the disk state
|
||||
| `xmrig.rs` | Struct/impl for `XMRig` tab
|
||||
|
||||
## Bootstrap
|
||||
This is how Gupax works internally when starting up, divided into 3 sections.
|
||||
|
||||
1. **INIT**
|
||||
- Initialize custom console logging with `log`, `env_logger` || *warn!*
|
||||
- Initialize misc data (structs, text styles, thread count, images, etc) || *panic!*
|
||||
- Check for admin privilege (for XMRig) || *warn!*
|
||||
- Attempt to read `gupax.toml` || *warn!*, *initialize config with default options*
|
||||
- If errors were found, pop-up window
|
||||
|
||||
2. **AUTO-UPDATE**
|
||||
- If `auto_update` == `true`, pop-up auto-updating window || *info!*, *skip auto-update*
|
||||
- Multi-threaded GitHub API check on Gupax -> P2Pool -> XMRig || *warn!*, *skip auto-update*
|
||||
- Multi-threaded download if current version != new version || *warn!*, *skip auto-update*
|
||||
- After download, atomically replace current binaries with new || *warn!*, *skip auto-update*
|
||||
- Update version metadata || *warn!*, *skip auto-update*
|
||||
|
||||
3. **MAIN**
|
||||
- All data must be initialized at this point, either via `gupax.toml` or default options || *panic!*
|
||||
- Start `App` frame || *panic!*
|
||||
- Write state to `gupax.toml` on user clicking `Save` (after checking input for correctness) || *warn!*
|
||||
- If `ask_before_quit` == `true`, check for running processes, unsaved state, and update connections before quitting
|
||||
- Kill processes, kill connections, exit
|
||||
|
||||
## State
|
||||
Internal state is saved in the "OS data folder" as `gupax.toml`, using the [TOML](https://github.com/toml-lang/toml) format. If the version can't be parsed (not in the `vX.X.X` or `vX.X` format), the auto-updater will be skipped. [If not found, a default `gupax.toml` file will be created with `Toml::default`.](https://github.com/hinto-janaiyo/gupax/blob/main/src/toml.rs)
|
||||
|
||||
| OS | Data Folder | Example |
|
||||
|----------|----------------------------------------- |-----------------------------------------------------------|
|
||||
| Windows | `{FOLDERID_LocalAppData}` | C:\Users\Alice\AppData\Roaming\Gupax\gupax.toml |
|
||||
| macOS | `$HOME`/Library/Application Support | /Users/Alice/Library/Application Support/Gupax/gupax.toml |
|
||||
| Linux | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share/gupax/gupax.toml |
|
|
@ -16,11 +16,17 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use std::net::{Ipv4Addr,SocketAddrV4};
|
||||
use sha2::{Sha256,Digest};
|
||||
use hex_literal::hex;
|
||||
use std::{io, fs};
|
||||
|
||||
// These are the versions bundled with Gupax.
|
||||
pub const P2POOL_VERSION: &'static str = "v2.4";
|
||||
pub const XMRIG_VERSION: &'static str = "v6.18.0";
|
||||
|
||||
// Compile-time constants
|
||||
pub const BYTES_ICON: &[u8] = include_bytes!("../images/png/icon.png");
|
||||
pub const BYTES_BANNER: &[u8] = include_bytes!("../images/png/banner.png");
|
||||
pub const P2POOL_BASE_ARGS: &'static str = "--host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --loglevel 3 --out-peers 10 --in-peers 10";
|
||||
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";
|
||||
|
||||
// OS specific
|
||||
|
|
80
src/main.rs
80
src/main.rs
|
@ -16,7 +16,7 @@
|
|||
// 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
|
||||
use eframe::egui;
|
||||
use eframe::{egui,NativeOptions};
|
||||
use egui::{Vec2,Pos2};
|
||||
use std::process::exit;
|
||||
use std::thread;
|
||||
|
@ -36,12 +36,13 @@ use std::io::Write;
|
|||
use std::time::Instant;
|
||||
|
||||
mod constants;
|
||||
mod toml;
|
||||
mod about;
|
||||
mod status;
|
||||
mod gupax;
|
||||
mod p2pool;
|
||||
mod xmrig;
|
||||
use {constants::*,about::*,status::*,gupax::*,p2pool::*,xmrig::*};
|
||||
use {constants::*,crate::toml::*,about::*,status::*,gupax::*,p2pool::*,xmrig::*};
|
||||
|
||||
// The state of the outer [App].
|
||||
// See the [State] struct for the
|
||||
|
@ -60,6 +61,8 @@ pub struct App {
|
|||
xmrig: bool,
|
||||
state: State,
|
||||
og: State,
|
||||
allowed_to_close: bool,
|
||||
show_confirmation_dialog: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -79,12 +82,12 @@ impl App {
|
|||
let resolution = cc.integration_info.window_info.size;
|
||||
init_text_styles(&cc.egui_ctx, resolution[0] as f32);
|
||||
let banner = match RetainedImage::from_image_bytes("banner.png", BYTES_BANNER) {
|
||||
Ok(banner) => { info!("Banner loading OK"); banner },
|
||||
Ok(banner) => { info!("Banner loading ... OK"); banner },
|
||||
Err(err) => { error!("{}", err); panic!("{}", err); },
|
||||
};
|
||||
let mut state = State::new();
|
||||
let mut og = State::new();
|
||||
info!("{:?}", resolution);
|
||||
info!("Frame resolution ... {:#?}", resolution);
|
||||
Self {
|
||||
version,
|
||||
name_version,
|
||||
|
@ -99,6 +102,8 @@ impl App {
|
|||
xmrig: false,
|
||||
state,
|
||||
og,
|
||||
allowed_to_close: false,
|
||||
show_confirmation_dialog: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,48 +174,58 @@ fn init_text_styles(ctx: &egui::Context, width: f32) {
|
|||
// style.spacing.button_padding = Vec2::new(scale/2.0, scale/2.0);
|
||||
ctx.set_style(style);
|
||||
ctx.set_pixels_per_point(1.0);
|
||||
ctx.request_repaint();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn init_logger() {
|
||||
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" },
|
||||
Level::Warn => { style.set_color(Color::Yellow); level = "WARN " },
|
||||
Level::Info => { style.set_color(Color::White); level = "INFO " },
|
||||
Level::Warn => { style.set_color(Color::Yellow); level = "WARN" },
|
||||
Level::Info => { style.set_color(Color::White); level = "INFO" },
|
||||
Level::Debug => { style.set_color(Color::Blue); level = "DEBUG" },
|
||||
Level::Trace => { style.set_color(Color::Magenta); level = "TRACE" },
|
||||
};
|
||||
writeln!(
|
||||
buf,
|
||||
"| {} | {} | {}:{} | {}",
|
||||
"[{}] [{}] [{}:{}] {}",
|
||||
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(),
|
||||
)
|
||||
}).filter_level(LevelFilter::Info).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().try_init();
|
||||
info!("test");
|
||||
warn!("test");
|
||||
error!("test");
|
||||
debug!("test");
|
||||
}).filter_level(LevelFilter::Info).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().init();
|
||||
info!("init_logger() ... OK");
|
||||
}
|
||||
|
||||
fn init_options() -> NativeOptions {
|
||||
let mut options = eframe::NativeOptions::default();
|
||||
options.min_window_size = Option::from(Vec2::new(1280.0, 720.0));
|
||||
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;
|
||||
let icon = image::load_from_memory(BYTES_ICON).expect("Failed to read ICON bytes").to_rgba8();
|
||||
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!("init_options() ... OK");
|
||||
options
|
||||
}
|
||||
|
||||
fn main() {
|
||||
init_logger();
|
||||
let options = init_options();
|
||||
let toml = Toml::get();
|
||||
info!("Printing gupax.toml...");
|
||||
eprintln!("{:#?}", toml);
|
||||
let now = Instant::now();
|
||||
eframe::run_native(
|
||||
"Gupax",
|
||||
|
@ -220,7 +235,29 @@ fn main() {
|
|||
}
|
||||
|
||||
impl eframe::App for App {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
fn on_close_event(&mut self) -> bool {
|
||||
self.show_confirmation_dialog = true;
|
||||
self.allowed_to_close
|
||||
}
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
if self.show_confirmation_dialog {
|
||||
// Show confirmation dialog:
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
let width = ui.available_width();
|
||||
let width = width - 10.0;
|
||||
let height = ui.available_height();
|
||||
init_text_styles(ctx, width);
|
||||
ui.add_sized([width, height/2.0], Label::new("Are you sure you want to quit?"));
|
||||
ui.group(|ui| {
|
||||
if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() {
|
||||
exit(0);
|
||||
} else if ui.add_sized([width, height/10.0], egui::Button::new("No")).clicked() {
|
||||
self.show_confirmation_dialog = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
return
|
||||
}
|
||||
// Top: Tabs
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
init_text_styles(ctx, ui.available_width());
|
||||
|
@ -355,16 +392,3 @@ impl eframe::App for App {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub trait View {
|
||||
fn ui(&mut self, ui: &mut egui::Ui);
|
||||
}
|
||||
|
||||
/// Something to view
|
||||
pub trait Demo {
|
||||
/// `&'static` so we can also use it as a key to store open/close state.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Show windows, etc
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool);
|
||||
}
|
||||
|
|
223
src/toml.rs
Normal file
223
src/toml.rs
Normal file
|
@ -0,0 +1,223 @@
|
|||
// 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/>.
|
||||
|
||||
// This handles reading/parsing the state file: [gupax.toml]
|
||||
// The TOML format is used. This struct hierarchy directly
|
||||
// translates into the TOML parser:
|
||||
// Toml/
|
||||
// ├─ Gupax/
|
||||
// │ ├─ ...
|
||||
// ├─ P2pool/
|
||||
// │ ├─ ...
|
||||
// ├─ Xmrig/
|
||||
// │ ├─ ...
|
||||
// ├─ Version/
|
||||
// ├─ ...
|
||||
|
||||
use std::{fs,env};
|
||||
use std::fmt::Display;
|
||||
use std::path::{Path,PathBuf};
|
||||
use serde_derive::{Serialize,Deserialize};
|
||||
use log::*;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Impl
|
||||
// Since [State] is already used in [main.rs] to represent
|
||||
// working state, [Toml] is used to disk state.
|
||||
impl Toml {
|
||||
pub fn default() -> Self {
|
||||
use crate::constants::{P2POOL_VERSION,XMRIG_VERSION};
|
||||
Self {
|
||||
gupax: Gupax {
|
||||
auto_update: true,
|
||||
ask_before_quit: true,
|
||||
p2pool_path: DEFAULT_P2POOL_PATH.to_string(),
|
||||
xmrig_path: DEFAULT_XMRIG_PATH.to_string(),
|
||||
},
|
||||
p2pool: P2pool {
|
||||
simple: true,
|
||||
mini: true,
|
||||
out_peers: 10,
|
||||
in_peers: 10,
|
||||
log_level: 3,
|
||||
monerod: "localhost".to_string(),
|
||||
rpc: 18081,
|
||||
zmq: 18083,
|
||||
address: "".to_string(),
|
||||
},
|
||||
xmrig: Xmrig {
|
||||
simple: true,
|
||||
tls: false,
|
||||
nicehash: false,
|
||||
keepalive: false,
|
||||
threads: 1,
|
||||
priority: 2,
|
||||
pool: "localhost:3333".to_string(),
|
||||
address: "".to_string(),
|
||||
},
|
||||
version: Version {
|
||||
p2pool: P2POOL_VERSION.to_string(),
|
||||
xmrig: XMRIG_VERSION.to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get() -> Result<Toml, TomlError> {
|
||||
// Get OS data folder
|
||||
// Linux | $XDG_DATA_HOME or $HOME/.local/share | /home/alice/.local/state
|
||||
// macOS | $HOME/Library/Application Support | /Users/Alice/Library/Application Support
|
||||
// Windows | {FOLDERID_RoamingAppData} | C:\Users\Alice\AppData\Roaming
|
||||
let mut path = match dirs::data_dir() {
|
||||
Some(mut path) => {
|
||||
path.push(DIRECTORY);
|
||||
info!("{}, OS data path ... OK", path.display());
|
||||
path
|
||||
},
|
||||
None => { error!("Couldn't get OS PATH for data"); return Err(TomlError::Path(PATH_ERROR.to_string())) },
|
||||
};
|
||||
|
||||
// Create directory
|
||||
fs::create_dir_all(&path)?;
|
||||
|
||||
// Attempt to read file, create default if not found
|
||||
path.push(FILENAME);
|
||||
let file = match fs::read_to_string(&path) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
error!("TOML not found, attempting to create default");
|
||||
let default = match toml::ser::to_string(&Toml::default()) {
|
||||
Ok(o) => { info!("TOML serialization ... OK"); o },
|
||||
Err(e) => { error!("Couldn't serialize default TOML file: {}", e); return Err(TomlError::Serialize(e)) },
|
||||
};
|
||||
fs::write(&path, default)?;
|
||||
info!("TOML write ... OK");
|
||||
fs::read_to_string(&path)?
|
||||
},
|
||||
};
|
||||
info!("TOML read ... OK");
|
||||
|
||||
// Attempt to parse, return Result
|
||||
match toml::from_str(&file) {
|
||||
Ok(file) => { info!("TOML parse ... OK"); Ok(file) },
|
||||
Err(err) => { error!("Couldn't parse TOML file"); Err(TomlError::Parse(err)) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TomlError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use TomlError::*;
|
||||
match self {
|
||||
Io(err) => write!(f, "{} | {}", ERROR, err),
|
||||
Path(err) => write!(f, "{} | {}", ERROR, err),
|
||||
Parse(err) => write!(f, "{} | {}", ERROR, err),
|
||||
Serialize(err) => write!(f, "{} | {}", ERROR, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for TomlError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
TomlError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let state = match Toml::get() {
|
||||
Ok(state) => { println!("OK"); state },
|
||||
Err(err) => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Const
|
||||
const FILENAME: &'static str = "gupax.toml";
|
||||
const ERROR: &'static str = "TOML Error";
|
||||
const PATH_ERROR: &'static str = "PATH for state directory could not be not found";
|
||||
#[cfg(target_os = "windows")]
|
||||
const DIRECTORY: &'static str = "Gupax";
|
||||
#[cfg(target_os = "macos")]
|
||||
const DIRECTORY: &'static str = "Gupax";
|
||||
#[cfg(target_os = "linux")]
|
||||
const DIRECTORY: &'static str = "gupax";
|
||||
#[cfg(target_os = "windows")]
|
||||
const DEFAULT_P2POOL_PATH: &'static str = r"P2Pool\p2pool.exe";
|
||||
#[cfg(target_os = "macos")]
|
||||
const DEFAULT_P2POOL_PATH: &'static str = "P2Pool/p2pool";
|
||||
#[cfg(target_os = "linux")]
|
||||
const DEFAULT_P2POOL_PATH: &'static str = "p2pool/p2pool";
|
||||
#[cfg(target_os = "windows")]
|
||||
const DEFAULT_XMRIG_PATH: &'static str = r"XMRig\xmrig.exe";
|
||||
#[cfg(target_os = "macos")]
|
||||
const DEFAULT_XMRIG_PATH: &'static str = "XMRig/xmrig";
|
||||
#[cfg(target_os = "linux")]
|
||||
const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig";
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Error Enum
|
||||
#[derive(Debug)]
|
||||
pub enum TomlError {
|
||||
Io(std::io::Error),
|
||||
Path(String),
|
||||
Parse(toml::de::Error),
|
||||
Serialize(toml::ser::Error),
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Structs
|
||||
#[derive(Debug,Deserialize,Serialize)]
|
||||
pub struct Toml {
|
||||
gupax: Gupax,
|
||||
p2pool: P2pool,
|
||||
xmrig: Xmrig,
|
||||
version: Version,
|
||||
}
|
||||
|
||||
#[derive(Debug,Deserialize,Serialize)]
|
||||
struct Gupax {
|
||||
auto_update: bool,
|
||||
ask_before_quit: bool,
|
||||
p2pool_path: String,
|
||||
xmrig_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug,Deserialize,Serialize)]
|
||||
struct P2pool {
|
||||
simple: bool,
|
||||
mini: bool,
|
||||
out_peers: u8,
|
||||
in_peers: u8,
|
||||
log_level: u8,
|
||||
monerod: String,
|
||||
rpc: u16,
|
||||
zmq: u16,
|
||||
address: String,
|
||||
}
|
||||
|
||||
#[derive(Debug,Deserialize,Serialize)]
|
||||
struct Xmrig {
|
||||
simple: bool,
|
||||
tls: bool,
|
||||
nicehash: bool,
|
||||
keepalive: bool,
|
||||
threads: u16,
|
||||
priority: u8,
|
||||
pool: String,
|
||||
address: String,
|
||||
}
|
||||
|
||||
#[derive(Debug,Deserialize,Serialize)]
|
||||
struct Version {
|
||||
p2pool: String,
|
||||
xmrig: String,
|
||||
}
|
Loading…
Reference in a new issue