2022-10-14 21:13:38 +00:00
|
|
|
// Gupax - GUI Uniting P2Pool And XMRig
|
|
|
|
//
|
2023-02-26 16:44:25 +00:00
|
|
|
// Copyright (c) 2022 hinto-janai
|
2022-10-14 21:13:38 +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/>.
|
|
|
|
|
2022-11-23 04:21:46 +00:00
|
|
|
use crate::{
|
|
|
|
constants::*,
|
2022-12-29 03:03:45 +00:00
|
|
|
macros::*,
|
2022-11-23 04:21:46 +00:00
|
|
|
};
|
update: save [Version] to state, use runtime [og: State]
[og: State] is now completely wrapped in an [Arc<Mutex>] so that
when the update is done, it can [.lock()] the CURRENT runtime
settings of the user and save to [gupax.toml] instead of using an
old copy that was given to it at the beginning of the thread.
In practice, this means users can change settings around during
an update and the update finishing and saving to disk won't be
using their old settings, but the current ones. Wrapping all of
[og: State] within in [Arc<Mutex>] might be overkill compared to
message channels but [State] really is just a few [bool]'s, [u*],
and small [String]'s, so it's not much data.
To bypass a deadlock when comparing [og == state] every frame,
[og]'s struct fields get cloned every frame into separate
variables, then it gets compared. This is also pretty stupid, but
again, the data being cloned is so tiny that it doesn't seem to
slow anything down.
2022-11-02 17:58:44 +00:00
|
|
|
use serde::{Serialize,Deserialize};
|
2022-12-17 03:39:34 +00:00
|
|
|
use rand::{thread_rng, Rng};
|
2022-10-14 21:13:38 +00:00
|
|
|
use std::time::{Instant,Duration};
|
2022-11-11 02:20:31 +00:00
|
|
|
use std::sync::{Arc,Mutex};
|
2022-10-14 21:13:38 +00:00
|
|
|
use egui::Color32;
|
|
|
|
use log::*;
|
2022-11-21 01:21:47 +00:00
|
|
|
use hyper::{
|
|
|
|
client::HttpConnector,
|
|
|
|
Client,Body,Request,
|
|
|
|
};
|
2022-11-18 03:45:57 +00:00
|
|
|
|
2022-11-11 02:20:31 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Node list
|
2023-02-26 16:44:25 +00:00
|
|
|
// Remote Monero Nodes with ZMQ enabled, sourced from: [https://github.com/hinto-janai/monero-nodes]
|
2023-01-29 01:57:12 +00:00
|
|
|
// The format is an array of tuples consisting of: (IP, LOCATION, RPC_PORT, ZMQ_PORT)
|
|
|
|
|
2023-01-31 14:25:05 +00:00
|
|
|
pub const REMOTE_NODES: [(&str, &str, &str, &str); 22] = [
|
|
|
|
("monero.10z.com.ar", "AR - Buenos Aires F.D.", "18089", "18084"),
|
|
|
|
("escom.sadovo.com", "BG - Plovdiv", "18089", "18084"),
|
|
|
|
("monero2.10z.com.ar", "BR - São Paulo", "18089", "18083"),
|
|
|
|
("monero1.heitechsoft.com", "CA - Ontario", "18081", "18084"),
|
|
|
|
("node.monerodevs.org", "CA - Quebec", "18089", "18084"),
|
|
|
|
("de.poiuty.com", "DE - Berlin", "18081", "18084"),
|
|
|
|
("m1.poiuty.com", "DE - Berlin", "18081", "18084"),
|
|
|
|
("p2pmd.xmrvsbeast.com", "DE - Hesse", "18081", "18083"),
|
|
|
|
("fbx.tranbert.com", "FR - Île-de-France", "18089", "18084"),
|
|
|
|
("reynald.ro", "FR - Île-de-France", "18089", "18084"),
|
|
|
|
("node2.monerodevs.org", "FR - Occitanie", "18089", "18084"),
|
|
|
|
("monero.homeqloud.com", "GR - East Macedonia and Thrace", "18089", "18083"),
|
|
|
|
("home.allantaylor.kiwi", "NZ - Canterbury", "18089", "18083"),
|
|
|
|
("ru.poiuty.com", "RU - Kuzbass", "18081", "18084"),
|
|
|
|
("node-01-xmr.godevs.cloud", "SG - Singapore", "18089", "18083"),
|
|
|
|
("node-02-xmr.godevs.cloud", "SG - Singapore", "18089", "18083"),
|
|
|
|
("radishfields.hopto.org", "US - Colorado", "18081", "18084"),
|
|
|
|
("xmrbandwagon.hopto.org", "US - Colorado", "18081", "18084"),
|
|
|
|
("xmr.spotlightsound.com", "US - Kansas", "18081", "18084"),
|
|
|
|
("xmrnode.facspro.net", "US - Nebraska", "18089", "18084"),
|
|
|
|
("moneronode.ddns.net", "US - Pennsylvania", "18089", "18084"),
|
|
|
|
("node.richfowler.net", "US - Pennsylvania", "18089", "18084"),
|
2022-10-16 21:29:24 +00:00
|
|
|
];
|
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
pub const REMOTE_NODE_LENGTH: usize = REMOTE_NODES.len();
|
2023-01-31 14:25:05 +00:00
|
|
|
pub const REMOTE_NODE_MAX_CHARS: usize = 25; // node-01-xmr.godevs.cloud
|
2022-12-17 03:39:34 +00:00
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
pub struct RemoteNode {
|
|
|
|
pub ip: &'static str,
|
2023-01-26 03:34:51 +00:00
|
|
|
pub location: &'static str,
|
2023-01-26 01:35:19 +00:00
|
|
|
pub rpc: &'static str,
|
|
|
|
pub zmq: &'static str,
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
impl Default for RemoteNode {
|
2022-12-17 22:17:26 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
impl RemoteNode {
|
|
|
|
pub fn new() -> Self {
|
2023-01-29 01:57:12 +00:00
|
|
|
let (ip, location, rpc, zmq) = REMOTE_NODES[0];
|
2023-01-26 01:35:19 +00:00
|
|
|
Self {
|
|
|
|
ip,
|
2023-01-26 03:34:51 +00:00
|
|
|
location,
|
2023-01-26 01:35:19 +00:00
|
|
|
rpc,
|
|
|
|
zmq,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
pub fn check_exists(og_ip: &str) -> String {
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, _, _) in REMOTE_NODES {
|
2023-01-26 03:34:51 +00:00
|
|
|
if og_ip == ip {
|
|
|
|
info!("Found remote node in array: {}", ip);
|
|
|
|
return ip.to_string()
|
|
|
|
}
|
|
|
|
}
|
2023-01-29 01:57:12 +00:00
|
|
|
let ip = REMOTE_NODES[0].0.to_string();
|
2023-01-26 03:34:51 +00:00
|
|
|
warn!("[{}] remote node does not exist, returning default: {}", og_ip, ip);
|
|
|
|
ip
|
|
|
|
}
|
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
// Returns a default if IP is not found.
|
|
|
|
pub fn from_ip(from_ip: &str) -> Self {
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, location, rpc, zmq) in REMOTE_NODES {
|
2023-01-26 01:35:19 +00:00
|
|
|
if from_ip == ip {
|
2023-01-29 01:57:12 +00:00
|
|
|
return Self { ip, location, rpc, zmq }
|
2023-01-26 01:35:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a default if index is not found in the const array.
|
|
|
|
pub fn from_index(index: usize) -> Self {
|
|
|
|
if index > REMOTE_NODE_LENGTH {
|
|
|
|
Self::new()
|
|
|
|
} else {
|
2023-01-29 01:57:12 +00:00
|
|
|
let (ip, location, rpc, zmq) = REMOTE_NODES[index];
|
|
|
|
Self { ip, location, rpc, zmq }
|
2023-01-26 01:35:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-29 01:57:12 +00:00
|
|
|
pub fn from_tuple(t: (&'static str, &'static str, &'static str, &'static str)) -> Self {
|
|
|
|
let (ip, location, rpc, zmq) = (t.0, t.1, t.2, t.3);
|
|
|
|
Self { ip, location, rpc, zmq }
|
2022-12-17 22:17:26 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
pub fn get_ip_rpc_zmq(og_ip: &str) -> (&str, &str, &str) {
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, rpc, zmq) in REMOTE_NODES {
|
2023-01-26 03:34:51 +00:00
|
|
|
if og_ip == ip { return (ip, rpc, zmq) }
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
2023-01-29 01:57:12 +00:00
|
|
|
let (ip, _, rpc, zmq) = REMOTE_NODES[0];
|
2023-01-26 03:34:51 +00:00
|
|
|
(ip, rpc, zmq)
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return a random node (that isn't the one already selected).
|
2023-01-26 03:34:51 +00:00
|
|
|
pub fn get_random(current_ip: &str) -> String {
|
|
|
|
let mut rng = thread_rng().gen_range(0..REMOTE_NODE_LENGTH);
|
2023-01-29 01:57:12 +00:00
|
|
|
let mut node = REMOTE_NODES[rng].0;
|
2023-01-26 03:34:51 +00:00
|
|
|
while current_ip == node {
|
|
|
|
rng = thread_rng().gen_range(0..REMOTE_NODE_LENGTH);
|
2023-01-29 01:57:12 +00:00
|
|
|
node = REMOTE_NODES[rng].0;
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
2023-01-26 03:34:51 +00:00
|
|
|
node.to_string()
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
// Return the node [-1] of this one
|
|
|
|
pub fn get_last(current_ip: &str) -> String {
|
|
|
|
let mut found = false;
|
|
|
|
let mut last = current_ip;
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, _, _) in REMOTE_NODES {
|
2023-01-26 03:34:51 +00:00
|
|
|
if found { return ip.to_string() }
|
|
|
|
if current_ip == ip { found = true; } else { last = ip; }
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
2023-01-26 03:34:51 +00:00
|
|
|
last.to_string()
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
// Return the node [+1] of this one
|
|
|
|
pub fn get_next(current_ip: &str) -> String {
|
|
|
|
let mut found = false;
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, _, _) in REMOTE_NODES {
|
2023-01-26 03:34:51 +00:00
|
|
|
if found { return ip.to_string() }
|
|
|
|
if current_ip == ip { found = true; }
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
2023-01-26 03:34:51 +00:00
|
|
|
current_ip.to_string()
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This returns relative to the ping.
|
2023-01-26 03:34:51 +00:00
|
|
|
pub fn get_last_from_ping(current_ip: &str, nodes: &Vec<NodeData>) -> String {
|
2022-12-17 03:39:34 +00:00
|
|
|
let mut found = false;
|
2023-01-26 03:34:51 +00:00
|
|
|
let mut last = current_ip;
|
2022-12-17 03:39:34 +00:00
|
|
|
for data in nodes {
|
2023-01-26 03:34:51 +00:00
|
|
|
if found { return last.to_string() }
|
|
|
|
if current_ip == data.ip { found = true; } else { last = data.ip; }
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
2023-01-26 03:34:51 +00:00
|
|
|
last.to_string()
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
pub fn get_next_from_ping(current_ip: &str, nodes: &Vec<NodeData>) -> String {
|
2022-12-17 03:39:34 +00:00
|
|
|
let mut found = false;
|
|
|
|
for data in nodes {
|
2023-01-26 03:34:51 +00:00
|
|
|
if found { return data.ip.to_string() }
|
|
|
|
if current_ip == data.ip { found = true; }
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
2023-01-26 03:34:51 +00:00
|
|
|
current_ip.to_string()
|
2022-12-17 03:39:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
impl std::fmt::Display for RemoteNode {
|
2022-11-11 02:20:31 +00:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
2023-01-26 01:35:19 +00:00
|
|
|
write!(f, "{:#?}", self.ip)
|
2022-11-11 02:20:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Formatting
|
|
|
|
// 5000 = 4 max length
|
|
|
|
pub fn format_ms(ms: u128) -> String {
|
|
|
|
match ms.to_string().len() {
|
|
|
|
1 => format!("{}ms ", ms),
|
|
|
|
2 => format!("{}ms ", ms),
|
|
|
|
3 => format!("{}ms ", ms),
|
|
|
|
_ => format!("{}ms", ms),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// format_ip_location(monero1.heitechsoft.com) -> "monero1.heitechsoft.com | XX - LOCATION"
|
|
|
|
// [extra_space] controls whether extra space is appended so the list aligns.
|
|
|
|
pub fn format_ip_location(og_ip: &str, extra_space: bool) -> String {
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, location, _, _) in REMOTE_NODES {
|
2023-01-26 03:34:51 +00:00
|
|
|
if og_ip == ip {
|
|
|
|
let ip = if extra_space { format_ip(ip) } else { ip.to_string() };
|
|
|
|
return format!("{} | {}", ip, location)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"??? | ???".to_string()
|
|
|
|
}
|
|
|
|
|
2023-01-31 14:25:05 +00:00
|
|
|
// node-01-xmr.godevs.cloud = 25 max length
|
2023-01-26 03:34:51 +00:00
|
|
|
pub fn format_ip(ip: &str) -> String {
|
|
|
|
match ip.len() {
|
2023-01-31 14:25:05 +00:00
|
|
|
1 => format!("{} ", ip),
|
|
|
|
2 => format!("{} ", ip),
|
|
|
|
3 => format!("{} ", ip),
|
|
|
|
4 => format!("{} ", ip),
|
|
|
|
5 => format!("{} ", ip),
|
|
|
|
6 => format!("{} ", ip),
|
|
|
|
7 => format!("{} ", ip),
|
|
|
|
8 => format!("{} ", ip),
|
|
|
|
9 => format!("{} ", ip),
|
|
|
|
10 => format!("{} ", ip),
|
|
|
|
11 => format!("{} ", ip),
|
|
|
|
12 => format!("{} ", ip),
|
|
|
|
13 => format!("{} ", ip),
|
|
|
|
14 => format!("{} ", ip),
|
|
|
|
15 => format!("{} ", ip),
|
|
|
|
16 => format!("{} ", ip),
|
|
|
|
17 => format!("{} ", ip),
|
|
|
|
18 => format!("{} ", ip),
|
|
|
|
19 => format!("{} ", ip),
|
|
|
|
20 => format!("{} ", ip),
|
|
|
|
21 => format!("{} ", ip),
|
|
|
|
22 => format!("{} ", ip),
|
|
|
|
23 => format!("{} ", ip),
|
|
|
|
24 => format!("{} ", ip),
|
2023-01-26 03:34:51 +00:00
|
|
|
_ => format!("{}", ip),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-11 02:20:31 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Node data
|
2022-11-18 19:25:13 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2022-11-11 02:20:31 +00:00
|
|
|
pub struct NodeData {
|
2022-10-16 21:29:24 +00:00
|
|
|
pub ip: &'static str,
|
2022-11-11 02:20:31 +00:00
|
|
|
pub ms: u128,
|
|
|
|
pub color: Color32,
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
2022-11-11 02:20:31 +00:00
|
|
|
impl NodeData {
|
|
|
|
pub fn new_vec() -> Vec<Self> {
|
|
|
|
let mut vec = Vec::new();
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, _, _) in REMOTE_NODES {
|
2022-11-11 02:20:31 +00:00
|
|
|
vec.push(Self {
|
|
|
|
ip,
|
|
|
|
ms: 0,
|
|
|
|
color: Color32::LIGHT_GRAY,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
vec
|
|
|
|
}
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
2022-11-20 19:20:25 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Ping data
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Ping {
|
|
|
|
pub nodes: Vec<NodeData>,
|
2023-01-26 01:35:19 +00:00
|
|
|
pub fastest: &'static str,
|
2022-11-20 19:20:25 +00:00
|
|
|
pub pinging: bool,
|
|
|
|
pub msg: String,
|
|
|
|
pub prog: f32,
|
|
|
|
pub pinged: bool,
|
|
|
|
pub auto_selected: bool,
|
|
|
|
}
|
2022-11-18 03:45:57 +00:00
|
|
|
|
2022-12-14 03:41:05 +00:00
|
|
|
impl Default for Ping {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-20 19:20:25 +00:00
|
|
|
impl Ping {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
nodes: NodeData::new_vec(),
|
2023-01-29 01:57:12 +00:00
|
|
|
fastest: REMOTE_NODES[0].0,
|
2022-11-20 19:20:25 +00:00
|
|
|
pinging: false,
|
|
|
|
msg: "No ping in progress".to_string(),
|
|
|
|
prog: 0.0,
|
|
|
|
pinged: false,
|
|
|
|
auto_selected: true,
|
|
|
|
}
|
|
|
|
}
|
2022-11-18 03:45:57 +00:00
|
|
|
|
2022-11-20 19:20:25 +00:00
|
|
|
//---------------------------------------------------------------------------------------------------- Main Ping function
|
2022-11-21 01:21:47 +00:00
|
|
|
// Intermediate function for spawning thread
|
2022-12-10 02:00:33 +00:00
|
|
|
pub fn spawn_thread(ping: &Arc<Mutex<Self>>) {
|
2022-12-12 19:34:17 +00:00
|
|
|
info!("Spawning ping thread...");
|
2022-11-24 04:03:56 +00:00
|
|
|
let ping = Arc::clone(ping);
|
2022-11-20 19:20:25 +00:00
|
|
|
std::thread::spawn(move|| {
|
2022-12-12 19:34:17 +00:00
|
|
|
let now = Instant::now();
|
|
|
|
match Self::ping(&ping) {
|
|
|
|
Ok(msg) => {
|
2022-11-22 01:10:47 +00:00
|
|
|
info!("Ping ... OK");
|
2022-12-29 03:03:45 +00:00
|
|
|
lock!(ping).msg = msg;
|
|
|
|
lock!(ping).pinged = true;
|
|
|
|
lock!(ping).auto_selected = false;
|
|
|
|
lock!(ping).prog = 100.0;
|
2022-11-22 01:10:47 +00:00
|
|
|
},
|
2022-11-20 19:20:25 +00:00
|
|
|
Err(err) => {
|
|
|
|
error!("Ping ... FAIL ... {}", err);
|
2022-12-29 03:03:45 +00:00
|
|
|
lock!(ping).pinged = false;
|
|
|
|
lock!(ping).msg = err.to_string();
|
2022-11-20 19:20:25 +00:00
|
|
|
},
|
2022-12-10 02:00:33 +00:00
|
|
|
}
|
2022-12-12 19:34:17 +00:00
|
|
|
info!("Ping ... Took [{}] seconds...", now.elapsed().as_secs_f32());
|
2022-12-29 03:03:45 +00:00
|
|
|
lock!(ping).pinging = false;
|
2022-11-20 19:20:25 +00:00
|
|
|
});
|
2022-11-18 03:45:57 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 01:35:19 +00:00
|
|
|
// This is for pinging the remote nodes to
|
2022-11-20 19:20:25 +00:00
|
|
|
// find the fastest/slowest one for the user.
|
|
|
|
// The process:
|
|
|
|
// - Send [get_info] JSON-RPC request over HTTP to all IPs
|
|
|
|
// - Measure each request in milliseconds
|
|
|
|
// - Timeout on requests over 5 seconds
|
|
|
|
// - Add data to appropriate struct
|
|
|
|
// - Sorting fastest to lowest is automatic (fastest nodes return ... the fastest)
|
|
|
|
//
|
|
|
|
// This used to be done 3x linearly but after testing, sending a single
|
|
|
|
// JSON-RPC call to all IPs asynchronously resulted in the same data.
|
|
|
|
//
|
2023-01-26 03:34:51 +00:00
|
|
|
// <300ms = GREEN
|
|
|
|
// >300ms = YELLOW
|
2023-01-23 22:05:34 +00:00
|
|
|
// >500ms = RED
|
2022-11-20 19:20:25 +00:00
|
|
|
// timeout = BLACK
|
|
|
|
// default = GRAY
|
|
|
|
#[tokio::main]
|
2022-12-12 19:34:17 +00:00
|
|
|
pub async fn ping(ping: &Arc<Mutex<Self>>) -> Result<String, anyhow::Error> {
|
2022-11-20 19:20:25 +00:00
|
|
|
// Start ping
|
2022-12-14 03:41:05 +00:00
|
|
|
let ping = Arc::clone(ping);
|
2022-12-29 03:03:45 +00:00
|
|
|
lock!(ping).pinging = true;
|
|
|
|
lock!(ping).prog = 0.0;
|
2023-01-26 01:35:19 +00:00
|
|
|
let percent = (100.0 / (REMOTE_NODE_LENGTH as f32)).floor();
|
2022-11-20 19:20:25 +00:00
|
|
|
|
|
|
|
// Create HTTP client
|
2022-11-24 04:03:56 +00:00
|
|
|
let info = "Creating HTTP Client".to_string();
|
2022-12-29 03:03:45 +00:00
|
|
|
lock!(ping).msg = info;
|
2022-11-21 01:21:47 +00:00
|
|
|
let client: Client<HttpConnector> = Client::builder()
|
|
|
|
.build(HttpConnector::new());
|
2022-11-20 19:20:25 +00:00
|
|
|
|
|
|
|
// Random User Agent
|
|
|
|
let rand_user_agent = crate::Pkg::get_user_agent();
|
|
|
|
// Handle vector
|
2023-01-26 01:35:19 +00:00
|
|
|
let mut handles = Vec::with_capacity(REMOTE_NODE_LENGTH);
|
|
|
|
let node_vec = arc_mut!(Vec::with_capacity(REMOTE_NODE_LENGTH));
|
2022-11-20 19:20:25 +00:00
|
|
|
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, rpc, zmq) in REMOTE_NODES {
|
2022-11-20 19:20:25 +00:00
|
|
|
let client = client.clone();
|
|
|
|
let ping = Arc::clone(&ping);
|
|
|
|
let node_vec = Arc::clone(&node_vec);
|
2022-11-21 01:21:47 +00:00
|
|
|
let request = Request::builder()
|
2022-11-20 19:20:25 +00:00
|
|
|
.method("POST")
|
2023-01-26 03:34:51 +00:00
|
|
|
.uri("http://".to_string() + ip + ":" + rpc + "/json_rpc")
|
2022-11-20 19:20:25 +00:00
|
|
|
.header("User-Agent", rand_user_agent)
|
|
|
|
.body(hyper::Body::from(r#"{"jsonrpc":"2.0","id":"0","method":"get_info"}"#))
|
|
|
|
.unwrap();
|
2023-01-26 03:34:51 +00:00
|
|
|
let handle = tokio::task::spawn(async move { Self::response(client, request, ip, ping, percent, node_vec).await; });
|
2022-11-20 19:20:25 +00:00
|
|
|
handles.push(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
for handle in handles {
|
2022-12-17 15:09:50 +00:00
|
|
|
handle.await?;
|
2022-11-20 19:20:25 +00:00
|
|
|
}
|
|
|
|
|
2022-12-29 03:03:45 +00:00
|
|
|
let node_vec = std::mem::take(&mut *lock!(node_vec));
|
2023-01-26 01:35:19 +00:00
|
|
|
let fastest_info = format!("Fastest node: {}ms ... {}", node_vec[0].ms, node_vec[0].ip);
|
2022-12-12 19:34:17 +00:00
|
|
|
|
2022-12-14 03:41:05 +00:00
|
|
|
let info = "Cleaning up connections".to_string();
|
2022-12-12 19:34:17 +00:00
|
|
|
info!("Ping | {}...", info);
|
2022-12-29 03:03:45 +00:00
|
|
|
let mut ping = lock!(ping);
|
2023-01-26 01:35:19 +00:00
|
|
|
ping.fastest = node_vec[0].ip;
|
2022-11-20 19:20:25 +00:00
|
|
|
ping.nodes = node_vec;
|
|
|
|
ping.msg = info;
|
|
|
|
drop(ping);
|
2022-12-12 19:34:17 +00:00
|
|
|
Ok(fastest_info)
|
2022-11-18 03:45:57 +00:00
|
|
|
}
|
|
|
|
|
2023-01-26 03:34:51 +00:00
|
|
|
async fn response(client: Client<HttpConnector>, request: Request<Body>, ip: &'static str, ping: Arc<Mutex<Self>>, percent: f32, node_vec: Arc<Mutex<Vec<NodeData>>>) {
|
2022-11-20 19:20:25 +00:00
|
|
|
let ms;
|
|
|
|
let info;
|
2022-12-14 03:41:05 +00:00
|
|
|
let now = Instant::now();
|
2022-11-20 19:20:25 +00:00
|
|
|
match tokio::time::timeout(Duration::from_secs(5), client.request(request)).await {
|
|
|
|
Ok(_) => {
|
|
|
|
ms = now.elapsed().as_millis();
|
2023-01-26 01:35:19 +00:00
|
|
|
info = format!("{}ms ... {}", ms, ip);
|
2022-11-20 19:20:25 +00:00
|
|
|
info!("Ping | {}", info)
|
|
|
|
},
|
cargo/tor/p2pool: clean deps, warn macos arti, fix node overflow
Cargo: Cleanup unused dependencies, enable some build optimizations
Tor: Arti doesn't seem to work on macOS
Even a bare Arti+Hyper request doesn't seem to work, so it's
probably not something to do with Gupax. A lot of issues only
seem to popup in a VM (OpenGL, TLS) even though on bare metal
Gupax runs fine, so Tor might work fine on real macOS but I don't
have real macOS to test it. VM macOS can't create a circuit, so,
disable by default and add a warning that it's unstable.
P2Pool: Let selected_index start at 0, and only +1 when printing
to the user, this makes the overflow math when adding/deleting a
lot more simple because selected_index will match the actual index
of the node vector
2022-11-21 22:16:31 +00:00
|
|
|
Err(_) => {
|
2022-11-20 19:20:25 +00:00
|
|
|
ms = 5000;
|
2023-01-26 01:35:19 +00:00
|
|
|
info = format!("{}ms ... {}", ms, ip);
|
2022-11-20 19:20:25 +00:00
|
|
|
warn!("Ping | {}", info)
|
|
|
|
},
|
|
|
|
};
|
|
|
|
let color;
|
2023-01-26 03:34:51 +00:00
|
|
|
if ms < 300 {
|
2022-11-23 04:21:46 +00:00
|
|
|
color = GREEN;
|
2023-01-23 22:05:34 +00:00
|
|
|
} else if ms < 500 {
|
2022-11-23 04:21:46 +00:00
|
|
|
color = YELLOW;
|
2022-11-20 19:20:25 +00:00
|
|
|
} else if ms < 5000 {
|
2022-11-23 04:21:46 +00:00
|
|
|
color = RED;
|
2022-11-20 19:20:25 +00:00
|
|
|
} else {
|
2022-11-23 04:21:46 +00:00
|
|
|
color = BLACK;
|
2022-11-20 19:20:25 +00:00
|
|
|
}
|
2022-12-29 03:03:45 +00:00
|
|
|
let mut ping = lock!(ping);
|
2022-11-18 19:25:13 +00:00
|
|
|
ping.msg = info;
|
2022-11-20 19:20:25 +00:00
|
|
|
ping.prog += percent;
|
2022-11-18 19:25:13 +00:00
|
|
|
drop(ping);
|
2023-01-26 01:35:19 +00:00
|
|
|
lock!(node_vec).push(NodeData { ip, ms, color, });
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-17 22:17:26 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------- TESTS
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
#[test]
|
|
|
|
fn validate_node_ips() {
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, location, rpc, zmq) in crate::REMOTE_NODES {
|
2022-12-17 22:17:26 +00:00
|
|
|
assert!(ip.len() < 255);
|
|
|
|
assert!(ip.is_ascii());
|
2023-01-29 01:57:12 +00:00
|
|
|
assert!(!location.is_empty());
|
|
|
|
assert!(!ip.is_empty());
|
|
|
|
assert!(rpc == "18081" || rpc == "18089");
|
|
|
|
assert!(zmq == "18083" || zmq == "18084");
|
2022-12-17 22:17:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn spacing() {
|
2023-01-29 01:57:12 +00:00
|
|
|
for (ip, _, _, _) in crate::REMOTE_NODES {
|
2023-01-26 01:35:19 +00:00
|
|
|
assert!(crate::format_ip(ip).len() <= crate::REMOTE_NODE_MAX_CHARS);
|
2022-12-17 22:17:26 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-29 01:57:12 +00:00
|
|
|
|
|
|
|
// This one pings the IPs defined in [REMOTE_NODES] and fully serializes the JSON data to make sure they work.
|
|
|
|
// This will only be ran with be ran with [cargo test -- --ignored].
|
|
|
|
#[tokio::test]
|
|
|
|
#[ignore]
|
|
|
|
async fn full_ping() {
|
|
|
|
use hyper::{
|
|
|
|
client::HttpConnector,
|
|
|
|
Client,Body,Request,
|
|
|
|
};
|
|
|
|
use crate::{REMOTE_NODES,REMOTE_NODE_LENGTH};
|
|
|
|
use serde::{Serialize,Deserialize};
|
|
|
|
|
|
|
|
#[derive(Deserialize,Serialize)]
|
|
|
|
struct GetInfo {
|
|
|
|
id: String,
|
|
|
|
jsonrpc: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create HTTP client
|
|
|
|
let client: Client<HttpConnector> = Client::builder().build(HttpConnector::new());
|
|
|
|
|
|
|
|
// Random User Agent
|
|
|
|
let rand_user_agent = crate::Pkg::get_user_agent();
|
|
|
|
|
|
|
|
let mut n = 1;
|
|
|
|
for (ip, _, rpc, zmq) in REMOTE_NODES {
|
|
|
|
println!("[{}/{}] {} | {} | {}", n, REMOTE_NODE_LENGTH, ip, rpc, zmq);
|
|
|
|
let client = client.clone();
|
2023-02-12 16:40:08 +00:00
|
|
|
// Try 5 times before failure
|
|
|
|
let mut i = 1;
|
|
|
|
let mut response = loop {
|
|
|
|
let request = Request::builder()
|
|
|
|
.method("POST")
|
|
|
|
.uri("http://".to_string() + ip + ":" + rpc + "/json_rpc")
|
|
|
|
.header("User-Agent", rand_user_agent)
|
|
|
|
.body(hyper::Body::from(r#"{"jsonrpc":"2.0","id":"0","method":"get_info"}"#))
|
|
|
|
.unwrap();
|
|
|
|
match client.request(request).await {
|
|
|
|
Ok(response) => break response,
|
|
|
|
Err(e) => {
|
|
|
|
println!("{:#?}", e);
|
|
|
|
if i > 5 { panic!("Node failure: {}:{}:{}", ip, rpc, zmq); }
|
|
|
|
std::thread::sleep(std::time::Duration::from_secs(3));
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-01-29 01:57:12 +00:00
|
|
|
let body = hyper::body::to_bytes(response.body_mut()).await.unwrap();
|
|
|
|
let getinfo: GetInfo = serde_json::from_slice(&body).unwrap();
|
|
|
|
assert!(getinfo.id == "0");
|
|
|
|
assert!(getinfo.jsonrpc == "2.0");
|
|
|
|
n += 1;
|
|
|
|
}
|
|
|
|
}
|
2022-12-17 22:17:26 +00:00
|
|
|
}
|