From 42de4ccdad4556095f474cf8e88952ddcc780c1b Mon Sep 17 00:00:00 2001 From: Duddino Date: Mon, 7 Oct 2024 17:03:28 +0200 Subject: [PATCH] Wait for pivxd before creating explorer --- src-tauri/Cargo.lock | 10 +++++++++ src-tauri/Cargo.toml | 2 +- src-tauri/src/address_index/pivx_rpc/mod.rs | 5 ++++- src-tauri/src/binary/mod.rs | 21 ++++++++++++++---- src-tauri/src/binary/test.rs | 3 +++ src-tauri/src/error.rs | 3 +++ src-tauri/src/explorer/mod.rs | 12 +++-------- src-tauri/src/pivx/mod.rs | 24 +++++++++++++++++++++ 8 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 9e87bce..344aac8 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3213,6 +3213,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -3819,6 +3828,7 @@ dependencies = [ "mio", "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.52.0", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 7160a9e..07ad693 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -25,7 +25,7 @@ sha256 = "1.5.0" futures = "0.3.30" rusqlite = "0.32.1" jsonrpsee = { version = "0.24.4", features = ["client-core"] } -tokio = "1.40.0" +tokio = { version = "1.40.0", features = ["process"] } base64 = "0.22.1" hex = "0.4.3" bs58 = "0.5.1" diff --git a/src-tauri/src/address_index/pivx_rpc/mod.rs b/src-tauri/src/address_index/pivx_rpc/mod.rs index 9fcac4c..06e71d9 100644 --- a/src-tauri/src/address_index/pivx_rpc/mod.rs +++ b/src-tauri/src/address_index/pivx_rpc/mod.rs @@ -1,6 +1,7 @@ pub mod json_rpc; mod test; +use crate::binary::Binary; use crate::error::PIVXErrors; use super::block_source::{BlockSource, BlockSourceType, IndexedBlockSource, PinnedStream}; @@ -21,6 +22,7 @@ use std::task::{Context, Poll}; #[derive(Clone)] pub struct PIVXRpc { client: HttpClient, + _pivx: Arc, } type BlockStreamFuture = Pin> + Send>>; @@ -90,7 +92,7 @@ impl Stream for BlockStream { } impl PIVXRpc { - pub async fn new(url: &str) -> crate::error::Result { + pub async fn new(url: &str, pivx: Binary) -> crate::error::Result { let mut headers = HeaderMap::new(); let credentials = format!("{}:{}", crate::RPC_USERNAME, crate::RPC_PASSWORD); headers.insert( @@ -101,6 +103,7 @@ impl PIVXRpc { ); Ok(PIVXRpc { client: HttpClient::builder().set_headers(headers).build(url)?, + _pivx: Arc::new(pivx), }) } diff --git a/src-tauri/src/binary/mod.rs b/src-tauri/src/binary/mod.rs index d7581ad..e42b5f2 100644 --- a/src-tauri/src/binary/mod.rs +++ b/src-tauri/src/binary/mod.rs @@ -5,7 +5,8 @@ use crate::error::PIVXErrors; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; -use std::process::{Child, Command, Stdio}; +use std::process::Stdio; +use tokio::process::{Child, Command}; pub trait BinaryDefinition { fn get_url(&self) -> &str; @@ -14,6 +15,7 @@ pub trait BinaryDefinition { fn decompress_archive(&self, dir: &Path) -> Result<(), PIVXErrors>; fn get_binary_path(&self, base_dir: &Path) -> PathBuf; fn get_binary_args(&self, base_dir: &Path) -> Result, PIVXErrors>; + async fn wait_for_load(&self, handle: &mut Child) -> crate::error::Result<()>; } pub struct Binary { @@ -23,8 +25,8 @@ pub struct Binary { impl Drop for Binary { fn drop(&mut self) { // This sends SIGKILL so this should be refactored to send SIGTERM - self.handle.kill().expect("Failed to kill pivxd"); - self.handle.wait().expect("Failed to wait"); + // self.handle.kill().expect("Failed to kill pivxd"); + // self.handle.wait().expect("Failed to wait"); } } @@ -79,7 +81,8 @@ impl Binary { } let handle = Command::new(path) .args(binary_definition.get_binary_args(&data_dir)?) - .stdout(Stdio::null()) + .stdout(Stdio::piped()) + .kill_on_drop(true) .spawn() .map_err(|_| PIVXErrors::PivxdNotFound)?; Ok(Binary { handle }) @@ -96,4 +99,14 @@ impl Binary { } Self::new_by_path(&binary_path.to_string_lossy(), binary_definition) } + + /** + * Resolves when binary finishes to load + */ + pub async fn wait_for_load( + &mut self, + binary_definition: &T, + ) -> crate::error::Result<()> { + binary_definition.wait_for_load(&mut self.handle).await + } } diff --git a/src-tauri/src/binary/test.rs b/src-tauri/src/binary/test.rs index f648f2d..5a52bee 100644 --- a/src-tauri/src/binary/test.rs +++ b/src-tauri/src/binary/test.rs @@ -23,6 +23,9 @@ impl BinaryDefinition for TestBinary { fn get_binary_args(&self, _: &Path) -> Result, PIVXErrors> { unimplemented!() } + async fn wait_for_load(&self, _handle: &mut Child) -> crate::error::Result<()> { + Ok(()) + } } mod pivx_fetch { use super::*; diff --git a/src-tauri/src/error.rs b/src-tauri/src/error.rs index e10299a..f9488f6 100644 --- a/src-tauri/src/error.rs +++ b/src-tauri/src/error.rs @@ -42,6 +42,9 @@ pub enum PIVXErrors { #[error("Failed to fetch sapling params")] FetchParamsFailed, + + #[error("PIVXD was stopped before loading was finished")] + PivxdStopped, } pub type Result = std::result::Result; diff --git a/src-tauri/src/explorer/mod.rs b/src-tauri/src/explorer/mod.rs index 46b1447..1061639 100644 --- a/src-tauri/src/explorer/mod.rs +++ b/src-tauri/src/explorer/mod.rs @@ -11,13 +11,7 @@ use crate::binary::Binary; use crate::{PIVXDefinition, RPC_PORT}; use global_function_macro::generate_global_functions; -//#[derive(Deserialize, Serialize)] type TxHexWithBlockCount = (String, u64, u64); -/*struct TxHexWithBlockCount { - hex: String, - time: u64, - height: u64, -}*/ #[derive(Clone)] pub struct Explorer @@ -48,10 +42,11 @@ async fn get_explorer() -> &'static DefaultExplorer { EXPLORER .get_or_init(|| async { let pivx_definition = PIVXDefinition; - let pivx = Binary::new_by_fetching(&pivx_definition) + let mut pivx = Binary::new_by_fetching(&pivx_definition) .await .expect("Failed to run PIVX"); - let pivx_rpc = PIVXRpc::new(&format!("http://127.0.0.1:{}", RPC_PORT)) + pivx.wait_for_load(&pivx_definition).await.unwrap(); + let pivx_rpc = PIVXRpc::new(&format!("http://127.0.0.1:{}", RPC_PORT), pivx) .await .unwrap(); // FIXME: refactor this to accept HOME @@ -61,7 +56,6 @@ async fn get_explorer() -> &'static DefaultExplorer { .unwrap(), pivx_rpc.clone(), ); - std::mem::forget(pivx); let explorer = Explorer::new(address_index, pivx_rpc); // Cloning is very cheap, it's just a Pathbuf and some Arcs diff --git a/src-tauri/src/pivx/mod.rs b/src-tauri/src/pivx/mod.rs index cf691d0..47a8506 100644 --- a/src-tauri/src/pivx/mod.rs +++ b/src-tauri/src/pivx/mod.rs @@ -7,6 +7,7 @@ use std::fs::File; use std::path::{Path, PathBuf}; use std::process::Command; use tar::Archive; +use tokio::io::{AsyncBufReadExt, BufReader}; use crate::binary::BinaryDefinition; @@ -83,4 +84,27 @@ impl BinaryDefinition for PIVXDefinition { ); Ok(args.split(" ").map(|s| s.to_string()).collect::>()) } + + async fn wait_for_load(&self, handle: &mut tokio::process::Child) -> crate::error::Result<()> { + let stdout = handle.stdout.take(); + match stdout { + Some(stdout) => { + let mut reader = BufReader::new(stdout); + let mut line = String::new(); + loop { + let read_bytes = reader.read_line(&mut line).await?; + if read_bytes == 0 { + return Err(PIVXErrors::PivxdStopped); + } + if line.contains("asking peer for sporks") { + break; + } + } + } + None => eprintln!( + "Warning: couldn't wait for load because no stdout is attached to the handle." + ), + } + Ok(()) + } }