2022-11-23 04:21:46 +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/>.
|
2022-11-28 17:05:09 +00:00
|
|
|
|
|
|
|
// This file handles all things related to child processes (P2Pool/XMRig).
|
|
|
|
// The main GUI thread will interface with the [Arc<Mutex<...>>] data found
|
|
|
|
// here, e.g: User clicks [Start P2Pool] -> Init p2pool thread here.
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- Import
|
|
|
|
use std::{
|
|
|
|
sync::{Arc,Mutex},
|
|
|
|
path::PathBuf,
|
|
|
|
process::Command,
|
|
|
|
thread,
|
|
|
|
};
|
|
|
|
use crate::constants::*;
|
|
|
|
use log::*;
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- [Process] Struct
|
|
|
|
// This holds all the state of a (child) process.
|
|
|
|
// The actual process thread runs in a 1 second loop, reading/writing to this struct.
|
|
|
|
// The main GUI thread will use this to display console text, online state, etc.
|
|
|
|
pub struct Process {
|
|
|
|
name: ProcessName, // P2Pool or XMRig?
|
|
|
|
online: bool, // Is the process alive?
|
|
|
|
args: String, // A single [String] containing the arguments
|
|
|
|
path: PathBuf, // The absolute path to the process binary
|
|
|
|
signal: ProcessSignal, // Did the user click [Stop/Restart]?
|
|
|
|
output: String, // This is the process's stdout + stderr
|
|
|
|
// STDIN Problem:
|
|
|
|
// - User can input many many commands in 1 second
|
|
|
|
// - The process loop only processes every 1 second
|
|
|
|
// - If there is only 1 [String] holding the user input,
|
|
|
|
// the user could overwrite their last input before
|
|
|
|
// the loop even has a chance to process their last command
|
|
|
|
// STDIN Solution:
|
|
|
|
// - When the user inputs something, push it to a [Vec]
|
|
|
|
// - In the process loop, loop over every [Vec] element and
|
|
|
|
// send each one individually to the process stdin
|
|
|
|
input: Vec<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- [Process] Impl
|
|
|
|
impl Process {
|
|
|
|
pub fn new(name: ProcessName, args: String, path: PathBuf) -> Self {
|
|
|
|
Self {
|
|
|
|
name,
|
|
|
|
online: false,
|
|
|
|
args,
|
|
|
|
path,
|
|
|
|
signal: ProcessSignal::None,
|
2022-11-29 22:33:24 +00:00
|
|
|
// P2Pool log level 1 produces a bit less than 100,000 lines a day.
|
|
|
|
// Assuming each line averages 80 UTF-8 scalars (80 bytes), then this
|
|
|
|
// initial buffer should last around a week (56MB) before resetting.
|
|
|
|
output: String::with_capacity(56_000_000),
|
2022-11-28 17:05:09 +00:00
|
|
|
input: vec![String::new()],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Borrow a [&str], return an owned split collection
|
|
|
|
pub fn parse_args(args: &str) -> Vec<String> {
|
|
|
|
args.split_whitespace().map(|s| s.to_owned()).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn spawn(process: &Arc<Mutex<Self>>, name: ProcessName) {
|
|
|
|
// Setup
|
|
|
|
let process = Arc::clone(process);
|
|
|
|
let args = Self::parse_args(&process.lock().unwrap().args);
|
|
|
|
info!("{} | Spawning initial thread", name);
|
|
|
|
info!("{} | Arguments: {:?}", name, args);
|
|
|
|
|
|
|
|
// Spawn thread
|
|
|
|
thread::spawn(move || {
|
|
|
|
// Create & spawn child
|
|
|
|
let mut child = Command::new(&process.lock().unwrap().path)
|
|
|
|
.args(args)
|
|
|
|
.stdout(std::process::Stdio::piped())
|
|
|
|
.spawn().unwrap();
|
|
|
|
|
|
|
|
// 1-second loop, reading and writing data to relevent struct
|
|
|
|
loop {
|
|
|
|
let process = process.lock().unwrap(); // Get lock
|
|
|
|
// If user sent a signal, handle it
|
|
|
|
match process.signal {
|
|
|
|
ProcessSignal::None => {},
|
|
|
|
_ => { child.kill(); break; },
|
|
|
|
};
|
|
|
|
// println!("{:?}", String::from_utf8(child.wait_with_output().unwrap().stdout).unwrap());
|
|
|
|
thread::sleep(SECOND);
|
|
|
|
}
|
|
|
|
|
|
|
|
// End of thread, must mean process is offline
|
|
|
|
process.lock().unwrap().online = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- [ProcessSignal] Enum
|
|
|
|
#[derive(Copy,Clone,Eq,PartialEq,Debug)]
|
|
|
|
pub enum ProcessSignal {
|
|
|
|
None,
|
|
|
|
Stop,
|
|
|
|
Restart,
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- [ProcessName] Enum
|
|
|
|
#[derive(Copy,Clone,Eq,PartialEq,Debug)]
|
|
|
|
pub enum ProcessName {
|
|
|
|
P2Pool,
|
|
|
|
XMRig,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for ProcessName {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "{:#?}", self)
|
|
|
|
}
|
|
|
|
}
|