mirror of
https://github.com/creating2morrow/neveko.git
synced 2024-12-22 19:49:24 +00:00
add i2p to installation manager
This commit is contained in:
parent
3c7b5f4da1
commit
1babfcd19c
6 changed files with 107 additions and 41 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,3 +12,4 @@ notes.txt
|
|||
*.zip
|
||||
*/monero-x86_64-linux-gnu-v0.18.2.2/**
|
||||
*/i2p-zero-linux.v1.20/**
|
||||
*.jar
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::{fs, env, process::Command};
|
||||
use log::{debug, error, info, warn};
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::{args, utils};
|
||||
use clap::Parser;
|
||||
|
@ -88,7 +87,15 @@ pub async fn start() {
|
|||
.expect("i2p-zero failed to start");
|
||||
debug!("{:?}", output.stdout);
|
||||
find_tunnels().await;
|
||||
{ tokio::spawn(async { check_connection(true).await }); }
|
||||
{
|
||||
tokio::spawn(async move {
|
||||
let tick: std::sync::mpsc::Receiver<()> = schedule_recv::periodic_ms(60000);
|
||||
loop {
|
||||
tick.recv().unwrap();
|
||||
check_connection().await;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tunnel() {
|
||||
|
@ -133,26 +140,9 @@ pub fn get_destination() -> String {
|
|||
utils::empty_string()
|
||||
}
|
||||
|
||||
pub async fn get_proxy_status() -> HttpProxyStatus {
|
||||
check_connection(false).await
|
||||
}
|
||||
|
||||
/// Ping i2pd tunnels local server for status
|
||||
async fn check_connection(bg: bool) -> HttpProxyStatus {
|
||||
pub async fn check_connection() -> HttpProxyStatus {
|
||||
let client: reqwest::Client = reqwest::Client::new();
|
||||
let host: &str = "http://localhost:7657/tunnels";
|
||||
if bg {
|
||||
let tick: std::sync::mpsc::Receiver<()> = schedule_recv::periodic_ms(60000);
|
||||
loop {
|
||||
tick.recv().unwrap();
|
||||
return process_connection_info(client, host).await;
|
||||
}
|
||||
} else {
|
||||
return process_connection_info(client, host).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_connection_info(client: Client, host: &str) -> HttpProxyStatus {
|
||||
match client.get(host).send().await {
|
||||
Ok(response) => {
|
||||
// do some parsing here to check the status
|
||||
|
|
|
@ -17,7 +17,11 @@ pub const NEVMES_JWT_SECRET_KEY: &str = "NEVMES_JWT_SECRET_KEY";
|
|||
|
||||
/// The latest monero release download
|
||||
pub const MONERO_RELEASE_VERSION: &str = "monero-linux-x64-v0.18.2.2.tar.bz2";
|
||||
pub const MONERO_RELEASE_HASH: &str = "186800de18f67cca8475ce392168aabeb5709a8f8058b0f7919d7c693786d56b";
|
||||
/// The latest i2p-zero release version
|
||||
pub const I2P_ZERO_RELEASE_VERSION: &str = "v1.20";
|
||||
|
||||
pub const I2P_ZERO_RELEASH_HASH: &str = "7e7216b281624ec464b55217284017576d109eaba7b35f7e4994ae2a78634de7";
|
||||
/// The latest i2pd release version
|
||||
pub const I2P_RELEASE_VERSION: &str = "2.2.1";
|
||||
pub const I2P_RELEASE_HASH: &str = "c9879b8f69ea13c758672c2fa083dc2e0abb289e0fc9a55af98f9f1795f82659";
|
||||
// DO NOT EDIT BELOW THIS LINE
|
||||
|
|
|
@ -5,6 +5,10 @@ use crate::{args, db, i2p, message, models, monero, gpg, utils, reqres };
|
|||
use log::{info, debug, error, warn};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Enum for selecting hash validation
|
||||
#[derive(PartialEq)]
|
||||
enum ExternalSoftware { I2P, I2PZero, XMR }
|
||||
|
||||
/// Handles the state for the installation manager popup
|
||||
pub struct Installations {
|
||||
pub xmr: bool,
|
||||
|
@ -416,9 +420,32 @@ pub fn stage_cleanup(f: String) {
|
|||
/// software on their own. Note that software pull is over
|
||||
///
|
||||
/// clearnet. TODO(c2m): trusted download locations over i2p.
|
||||
pub async fn install_software(installations: Installations) {
|
||||
pub async fn install_software(installations: Installations) -> bool {
|
||||
let mut valid_i2p_hash = true;
|
||||
let mut valid_i2p_zero_hash = true;
|
||||
let mut valid_xmr_hash = true;
|
||||
if installations.i2p {
|
||||
info!("installing i2p");
|
||||
let i2p_version = crate::I2P_RELEASE_VERSION;
|
||||
let i2p_jar = format!("i2pinstall_{}.jar", i2p_version);
|
||||
let link = format!("https://download.i2p2.no/releases/{}/{}", i2p_version, i2p_jar);
|
||||
let curl = std::process::Command::new("curl")
|
||||
.args(["-O#", &link])
|
||||
.status();
|
||||
match curl {
|
||||
Ok(curl_output) => {
|
||||
debug!("{:?}", curl_output);
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
let jar_output = std::process::Command::new("java")
|
||||
.args(["-jar", &i2p_jar])
|
||||
.spawn()
|
||||
.expect("i2p gui installation failed");
|
||||
debug!("{:?}", jar_output.stdout);
|
||||
},
|
||||
_=> error!("i2p download failed")
|
||||
}
|
||||
valid_i2p_hash = validate_installation_hash(ExternalSoftware::I2P, &i2p_jar);
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
if installations.i2p_zero {
|
||||
info!("installing i2p-zero");
|
||||
|
@ -434,13 +461,15 @@ pub async fn install_software(installations: Installations) {
|
|||
debug!("{:?}", curl_output);
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
let unzip_output = std::process::Command::new("unzip")
|
||||
.arg(i2p_zero_zip)
|
||||
.arg(&i2p_zero_zip)
|
||||
.spawn()
|
||||
.expect("i2p unzip failed");
|
||||
debug!("{:?}", unzip_output.stdout);
|
||||
},
|
||||
_=> error!("i2p-zero download failed")
|
||||
}
|
||||
valid_i2p_zero_hash = validate_installation_hash(ExternalSoftware::I2PZero, &i2p_zero_zip);
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
if installations.xmr {
|
||||
info!("installing monero");
|
||||
|
@ -460,5 +489,29 @@ pub async fn install_software(installations: Installations) {
|
|||
},
|
||||
_=> error!("monero download failed")
|
||||
}
|
||||
valid_xmr_hash = validate_installation_hash(ExternalSoftware::XMR, &String::from(crate::MONERO_RELEASE_VERSION));
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
valid_i2p_hash && valid_i2p_zero_hash && valid_xmr_hash
|
||||
}
|
||||
|
||||
/// Linux specific hash validation using the command `sha256sum`
|
||||
fn validate_installation_hash(sw: ExternalSoftware, filename: &String) -> bool {
|
||||
debug!("validating hash");
|
||||
let expected_hash = if sw == ExternalSoftware::I2P {
|
||||
String::from(crate::I2P_RELEASE_HASH)
|
||||
} else if sw == ExternalSoftware::I2PZero {
|
||||
String::from(crate::I2P_ZERO_RELEASH_HASH)
|
||||
} else {
|
||||
String::from(crate::MONERO_RELEASE_HASH)
|
||||
};
|
||||
let sha_output = std::process::Command::new("sha256sum")
|
||||
.arg(filename).output().expect("hash validation failed");
|
||||
let str_sha = String::from_utf8(sha_output.stdout).unwrap();
|
||||
let split1 = str_sha.split(" ");
|
||||
let mut v: Vec<String> = split1.map(|s| String::from(s)).collect();
|
||||
let actual_hash = v.remove(0);
|
||||
debug!("actual hash: {}", actual_hash);
|
||||
debug!("expected hash: {}", expected_hash);
|
||||
actual_hash == expected_hash
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@ use nevmes_core::*;
|
|||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{BLOCK_TIME_IN_SECS_EST, BYTES_IN_GB, START_CORE_TIMEOUT_SECS};
|
||||
|
||||
pub struct HomeApp {
|
||||
connections: utils::Connections,
|
||||
core_timeout_tx: Sender<bool>,
|
||||
core_timeout_rx: Receiver<bool>,
|
||||
has_install_failed: bool,
|
||||
installations: utils::Installations,
|
||||
installation_tx: Sender<bool>,
|
||||
installation_rx: Receiver<bool>,
|
||||
|
@ -50,6 +49,7 @@ pub struct HomeApp {
|
|||
impl Default for HomeApp {
|
||||
fn default() -> Self {
|
||||
let connections = Default::default();
|
||||
let has_install_failed = false;
|
||||
let installations = Default::default();
|
||||
let is_core_running = false;
|
||||
let is_editing_connections = false;
|
||||
|
@ -80,6 +80,7 @@ impl Default for HomeApp {
|
|||
connections,
|
||||
core_timeout_rx,
|
||||
core_timeout_tx,
|
||||
has_install_failed,
|
||||
installations,
|
||||
installation_rx,
|
||||
installation_tx,
|
||||
|
@ -139,6 +140,7 @@ impl eframe::App for HomeApp {
|
|||
}
|
||||
if let Ok(install) = self.installation_rx.try_recv() {
|
||||
self.is_installing = !install;
|
||||
if !install && self.is_loading { self.has_install_failed = true }
|
||||
self.is_loading = false;
|
||||
}
|
||||
if let Ok(timeout) = self.core_timeout_rx.try_recv() {
|
||||
|
@ -150,6 +152,20 @@ impl eframe::App for HomeApp {
|
|||
}
|
||||
}
|
||||
|
||||
// Installation Error window
|
||||
//-----------------------------------------------------------------------------------
|
||||
let mut has_install_failed = self.has_install_failed;
|
||||
egui::Window::new("Error")
|
||||
.open(&mut has_install_failed)
|
||||
.vscroll(false)
|
||||
.show(&ctx, |ui| {
|
||||
ui.heading("Installation Failure");
|
||||
if ui.button("Exit").clicked() {
|
||||
self.is_installing = false;
|
||||
self.is_loading = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Connection Manager window
|
||||
//-----------------------------------------------------------------------------------
|
||||
let mut is_editing_connections = self.is_editing_connections;
|
||||
|
@ -217,12 +233,12 @@ impl eframe::App for HomeApp {
|
|||
.open(&mut is_installing)
|
||||
.vscroll(true)
|
||||
.show(&ctx, |ui| {
|
||||
// let mut wants_i2p = self.installations.i2p;
|
||||
let mut wants_i2p = self.installations.i2p;
|
||||
let mut wants_i2p_zero = self.installations.i2p_zero;
|
||||
let mut wants_xmr = self.installations.xmr;
|
||||
// if ui.checkbox(&mut wants_i2p, "i2p").changed() {
|
||||
// self.installations.i2p = !self.installations.i2p;
|
||||
// }
|
||||
if ui.checkbox(&mut wants_i2p, "i2p").changed() {
|
||||
self.installations.i2p = !self.installations.i2p;
|
||||
}
|
||||
if ui.checkbox(&mut wants_i2p_zero, "i2p-zero").changed() {
|
||||
self.installations.i2p_zero = !self.installations.i2p_zero;
|
||||
}
|
||||
|
@ -231,11 +247,13 @@ impl eframe::App for HomeApp {
|
|||
}
|
||||
let install = &self.installations;
|
||||
if install.i2p || install.i2p_zero || install.xmr {
|
||||
if !self.is_loading {
|
||||
if ui.button("Install").clicked() {
|
||||
self.is_loading = true;
|
||||
install_software_req(self.installation_tx.clone(), ctx.clone(), &self.installations);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ui.button("Exit").clicked() {
|
||||
self.is_installing = false;
|
||||
self.is_loading = false;
|
||||
|
@ -280,10 +298,10 @@ impl eframe::App for HomeApp {
|
|||
let address = &self.s_xmr_address.result.address;
|
||||
let unlocked_balance = self.s_xmr_balance.result.unlocked_balance;
|
||||
let locked_balance = self.s_xmr_balance.result.balance - unlocked_balance;
|
||||
let unlock_time = self.s_xmr_balance.result.blocks_to_unlock * BLOCK_TIME_IN_SECS_EST;
|
||||
let unlock_time = self.s_xmr_balance.result.blocks_to_unlock * crate::BLOCK_TIME_IN_SECS_EST;
|
||||
let xmrd_info: &reqres::XmrDaemonGetInfoResult = &self.s_xmrd_get_info.result;
|
||||
let free_space = xmrd_info.free_space / BYTES_IN_GB;
|
||||
let db_size = xmrd_info.database_size / BYTES_IN_GB;
|
||||
let free_space = xmrd_info.free_space / crate::BYTES_IN_GB;
|
||||
let db_size = xmrd_info.database_size / crate::BYTES_IN_GB;
|
||||
ui.label(format!("- rpc version: {}\n- address: {}\n- balance: {} piconero(s)\n- locked balance: {} piconero(s)\n- unlock time (secs): {}\n- daemon info\n\t- net type: {}\n\t- current hash: {}\n\t- height: {}\n\t- synced: {}\n\t- blockchain size : ~{} GB\n\t- free space : ~{} GB\n\t- version: {}\n",
|
||||
self.s_xmr_rpc_ver.result.version, address, unlocked_balance, locked_balance,
|
||||
unlock_time, xmrd_info.nettype, xmrd_info.top_block_hash, xmrd_info.height, xmrd_info.synchronized,
|
||||
|
@ -352,7 +370,7 @@ fn send_balance_req(tx: Sender<reqres::XmrRpcBalanceResponse>, ctx: egui::Contex
|
|||
|
||||
fn send_i2p_status_req(tx: Sender<i2p::HttpProxyStatus>, ctx: egui::Context) {
|
||||
tokio::spawn(async move {
|
||||
let status = i2p::get_proxy_status().await;
|
||||
let status = i2p::check_connection().await;
|
||||
let _ = tx.send(status);
|
||||
ctx.request_repaint();
|
||||
});
|
||||
|
@ -373,7 +391,7 @@ fn send_reset_refresh(tx: Sender<bool>, ctx: egui::Context, init: bool) {
|
|||
fn start_core_timeout
|
||||
(tx: Sender<bool>, ctx: egui::Context) {
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(START_CORE_TIMEOUT_SECS)).await;
|
||||
tokio::time::sleep(std::time::Duration::from_secs(crate::START_CORE_TIMEOUT_SECS)).await;
|
||||
log::error!("start nevmes-core timeout");
|
||||
let _ = tx.send(true);
|
||||
ctx.request_repaint();
|
||||
|
@ -388,8 +406,8 @@ fn install_software_req
|
|||
xmr: installations.xmr,
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
utils::install_software(req_install).await;
|
||||
let _ = tx.send(true);
|
||||
let did_install = utils::install_software(req_install).await;
|
||||
let _ = tx.send(did_install);
|
||||
ctx.request_repaint();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ pub async fn get_version(_jwp: proof::PaymentProof) -> Custom<Json<reqres::XmrRp
|
|||
/// This also functions as a health check
|
||||
#[get("/status")]
|
||||
pub async fn get_i2p_status() -> Custom<Json<i2p::HttpProxyStatus>> {
|
||||
Custom(Status::Ok, Json(i2p::get_proxy_status().await))
|
||||
Custom(Status::Ok, Json(i2p::check_connection().await))
|
||||
}
|
||||
|
||||
/// Share your contact information
|
||||
|
|
Loading…
Reference in a new issue