2022-12-28 21:04:26 +00:00
|
|
|
// Gupax - GUI Uniting P2Pool And XMRig
|
|
|
|
//
|
2023-02-26 16:45:58 +00:00
|
|
|
// Copyright (c) 2022-2023 hinto-janai
|
2022-12-28 21:04:26 +00:00
|
|
|
//
|
|
|
|
// 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/>.
|
|
|
|
|
|
|
|
// Some regexes used throughout Gupax.
|
|
|
|
|
2023-05-11 20:01:17 +00:00
|
|
|
use once_cell::sync::Lazy;
|
2024-02-26 07:01:53 +00:00
|
|
|
use regex::Regex;
|
2023-04-19 14:01:11 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- Lazy
|
2024-02-27 04:08:14 +00:00
|
|
|
pub static REGEXES: Lazy<Regexes> = Lazy::new(Regexes::new);
|
|
|
|
pub static P2POOL_REGEX: Lazy<P2poolRegex> = Lazy::new(P2poolRegex::new);
|
|
|
|
pub static XMRIG_REGEX: Lazy<XmrigRegex> = Lazy::new(XmrigRegex::new);
|
2022-12-28 21:04:26 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- [Regexes] struct
|
|
|
|
// General purpose Regexes, mostly used in the GUI.
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Regexes {
|
2024-02-26 07:01:53 +00:00
|
|
|
pub name: Regex,
|
|
|
|
pub address: Regex,
|
|
|
|
pub ipv4: Regex,
|
|
|
|
pub domain: Regex,
|
|
|
|
pub port: Regex,
|
2022-12-28 21:04:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Regexes {
|
2024-02-26 07:01:53 +00:00
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
|
|
|
fn new() -> Self {
|
|
|
|
Self {
|
2022-12-28 21:04:26 +00:00
|
|
|
name: Regex::new("^[A-Za-z0-9-_.]+( [A-Za-z0-9-_.]+)*$").unwrap(),
|
|
|
|
address: Regex::new("^4[A-Za-z1-9]+$").unwrap(), // This still needs to check for (l, I, o, 0)
|
|
|
|
ipv4: Regex::new(r#"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$"#).unwrap(),
|
2023-11-28 13:58:21 +00:00
|
|
|
domain: Regex::new(r#"^[A-Za-z0-9-.]+[A-Za-z0-9-]+$"#).unwrap(),
|
2022-12-28 21:04:26 +00:00
|
|
|
port: Regex::new(r#"^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$"#).unwrap(),
|
|
|
|
}
|
2024-02-26 07:01:53 +00:00
|
|
|
}
|
2022-12-28 21:04:26 +00:00
|
|
|
|
2024-02-26 07:01:53 +00:00
|
|
|
#[inline]
|
|
|
|
// Check if a Monero address is correct.
|
|
|
|
// This actually only checks for length & Base58, and doesn't do any checksum validation
|
|
|
|
// (the last few bytes of a Monero address are a Keccak hash checksum) so some invalid addresses can trick this function.
|
|
|
|
pub fn addr_ok(address: &str) -> bool {
|
|
|
|
address.len() == 95
|
|
|
|
&& REGEXES.address.is_match(address)
|
|
|
|
&& !address.contains('0')
|
|
|
|
&& !address.contains('O')
|
|
|
|
&& !address.contains('l')
|
|
|
|
}
|
2022-12-28 21:04:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- [P2poolRegex]
|
|
|
|
// Meant for parsing the output of P2Pool and finding payouts and total XMR found.
|
|
|
|
// Why Regex instead of the standard library?
|
|
|
|
// 1. I'm already using Regex
|
|
|
|
// 2. It's insanely faster
|
|
|
|
//
|
|
|
|
// The following STDLIB implementation takes [0.003~] seconds to find all matches given a [String] with 30k lines:
|
|
|
|
// let mut n = 0;
|
|
|
|
// for line in P2POOL_OUTPUT.lines() {
|
|
|
|
// if line.contains("payout of [0-9].[0-9]+ XMR") { n += 1; }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// This regex function takes [0.0003~] seconds (10x faster):
|
|
|
|
// let regex = Regex::new("payout of [0-9].[0-9]+ XMR").unwrap();
|
|
|
|
// let n = regex.find_iter(P2POOL_OUTPUT).count();
|
|
|
|
//
|
|
|
|
// Both are nominally fast enough where it doesn't matter too much but meh, why not use regex.
|
2024-02-26 07:01:53 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2022-12-28 21:04:26 +00:00
|
|
|
pub struct P2poolRegex {
|
2024-02-26 07:01:53 +00:00
|
|
|
pub date: Regex,
|
|
|
|
pub payout: Regex,
|
|
|
|
pub payout_float: Regex,
|
|
|
|
pub block: Regex,
|
|
|
|
pub block_int: Regex,
|
|
|
|
pub block_comma: Regex,
|
|
|
|
pub synchronized: Regex,
|
|
|
|
pub next_height_1: Regex,
|
2022-12-28 21:04:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl P2poolRegex {
|
2024-02-26 07:01:53 +00:00
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
|
|
|
fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
date: Regex::new("[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+").unwrap(),
|
|
|
|
payout: Regex::new("payout of [0-9].[0-9]+ XMR").unwrap(), // Assumes 12 digits after the dot.
|
|
|
|
payout_float: Regex::new("[0-9].[0-9]{12}").unwrap(), // Assumes 12 digits after the dot.
|
|
|
|
block: Regex::new("block [0-9]{7}").unwrap(), // Monero blocks will be 7 digits for... the next 10,379 years
|
|
|
|
block_int: Regex::new("[0-9]{7}").unwrap(),
|
|
|
|
block_comma: Regex::new("[0-9],[0-9]{3},[0-9]{3}").unwrap(),
|
|
|
|
synchronized: Regex::new("SYNCHRONIZED").unwrap(),
|
|
|
|
next_height_1: Regex::new("next height = 1").unwrap(),
|
|
|
|
}
|
|
|
|
}
|
2023-04-19 14:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- XMRig regex.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct XmrigRegex {
|
2024-02-26 07:01:53 +00:00
|
|
|
pub not_mining: Regex,
|
|
|
|
pub new_job: Regex,
|
2023-04-19 14:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl XmrigRegex {
|
2024-02-26 07:01:53 +00:00
|
|
|
fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
not_mining: Regex::new("no active pools, stop mining").unwrap(),
|
|
|
|
new_job: Regex::new("new job").unwrap(),
|
|
|
|
}
|
|
|
|
}
|
2022-12-29 03:46:52 +00:00
|
|
|
}
|
2024-03-23 15:41:29 +00:00
|
|
|
|
|
|
|
// count the lines without consuming.
|
|
|
|
pub fn num_lines(s: &str) -> usize {
|
|
|
|
static LINE_BREAKS: Lazy<Regex> = Lazy::new(|| Regex::new(r"\r?\n").unwrap());
|
|
|
|
LINE_BREAKS.captures_iter(s).count() + 1
|
|
|
|
}
|
2024-03-03 07:31:22 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- TEST
|
2022-12-29 03:46:52 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2024-02-26 07:01:53 +00:00
|
|
|
use super::*;
|
2023-04-19 15:31:36 +00:00
|
|
|
|
2024-02-26 07:01:53 +00:00
|
|
|
#[test]
|
|
|
|
fn build_regexes() {
|
|
|
|
let r = Regexes::new();
|
|
|
|
assert!(Regex::is_match(&r.name, "_this_ is... a n-a-m-e."));
|
|
|
|
assert!(Regex::is_match(&r.address, "44hintoFpuo3ugKfcqJvh5BmrsTRpnTasJmetKC4VXCt6QDtbHVuixdTtsm6Ptp7Y8haXnJ6j8Gj2dra8CKy5ewz7Vi9CYW"));
|
|
|
|
assert!(Regex::is_match(&r.ipv4, "192.168.1.2"));
|
|
|
|
assert!(Regex::is_match(&r.ipv4, "127.0.0.1"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "sub.domain.com"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "sub.domain.longtld"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "sub.sub.domain.longtld"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "my.node.com"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "my.node.longtld"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "my.monero-node123.net"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "www.my-node.org"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "www.my-monero-node123.io"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "www.my-monero-node123.longtld"));
|
|
|
|
assert!(Regex::is_match(&r.domain, "www.my-monero-node123.org"));
|
|
|
|
for i in 1..=65535 {
|
|
|
|
assert!(Regex::is_match(&r.port, &i.to_string()));
|
|
|
|
}
|
|
|
|
assert!(!Regex::is_match(&r.port, "0"));
|
|
|
|
assert!(!Regex::is_match(&r.port, "65536"));
|
|
|
|
}
|
2022-12-29 03:46:52 +00:00
|
|
|
|
2024-02-26 07:01:53 +00:00
|
|
|
#[test]
|
|
|
|
fn build_p2pool_regex() {
|
|
|
|
let r = P2poolRegex::new();
|
|
|
|
let text = "NOTICE 2022-11-11 11:11:11.1111 P2Pool You received a payout of 0.111111111111 XMR in block 1111111";
|
|
|
|
let text2 = "2022-11-11 11:11:11.1111 | 0.111111111111 XMR | Block 1,111,111";
|
|
|
|
let text3 = "NOTICE 2020-12-11 12:35:41.3150 SideChain SYNCHRONIZED";
|
|
|
|
assert_eq!(
|
|
|
|
r.payout.find(text).unwrap().as_str(),
|
|
|
|
"payout of 0.111111111111 XMR"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
r.payout_float.find(text).unwrap().as_str(),
|
|
|
|
"0.111111111111"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
r.date.find(text).unwrap().as_str(),
|
|
|
|
"2022-11-11 11:11:11.1111"
|
|
|
|
);
|
|
|
|
assert_eq!(r.block.find(text).unwrap().as_str(), "block 1111111");
|
|
|
|
assert_eq!(r.block_int.find(text).unwrap().as_str(), "1111111");
|
|
|
|
assert_eq!(r.block_comma.find(text2).unwrap().as_str(), "1,111,111");
|
|
|
|
assert_eq!(r.synchronized.find(text3).unwrap().as_str(), "SYNCHRONIZED");
|
|
|
|
}
|
2023-04-19 15:31:36 +00:00
|
|
|
|
2024-02-26 07:01:53 +00:00
|
|
|
#[test]
|
|
|
|
fn build_xmrig_regex() {
|
|
|
|
let r = XmrigRegex::new();
|
|
|
|
let text = "[2022-02-12 12:49:30.311] net no active pools, stop mining";
|
|
|
|
let text2 = "[2022-02-12 12:49:30.311] net new job from 192.168.2.1:3333 diff 402K algo rx/0 height 2241142 (11 tx)";
|
|
|
|
assert_eq!(
|
|
|
|
r.not_mining.find(text).unwrap().as_str(),
|
|
|
|
"no active pools, stop mining"
|
|
|
|
);
|
|
|
|
assert_eq!(r.new_job.find(text2).unwrap().as_str(), "new job");
|
|
|
|
}
|
2022-12-28 21:04:26 +00:00
|
|
|
}
|