From fb44f2d3cdae9ac6e46fe7a9067485ad23736dec Mon Sep 17 00:00:00 2001 From: Binarybaron Date: Thu, 14 Nov 2024 19:19:52 +0100 Subject: [PATCH] feat(gui): Display progress of monero-wallet-rpc download --- .../components/alert/DaemonStatusAlert.tsx | 32 ++++++++++++++++--- src-gui/src/utils/conversionUtils.ts | 9 ++++-- swap/src/cli/api.rs | 12 +++++-- swap/src/cli/api/tauri_bindings.rs | 9 ++++++ swap/src/monero/wallet_rpc.rs | 27 +++++++++++++++- 5 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src-gui/src/renderer/components/alert/DaemonStatusAlert.tsx b/src-gui/src/renderer/components/alert/DaemonStatusAlert.tsx index 35d82a1ff..c99b4692d 100644 --- a/src-gui/src/renderer/components/alert/DaemonStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/DaemonStatusAlert.tsx @@ -1,12 +1,22 @@ -import { Button } from "@material-ui/core"; +import { Box, Button, LinearProgress, makeStyles } from "@material-ui/core"; import { Alert } from "@material-ui/lab"; import { TauriContextInitializationProgress } from "models/tauriModel"; import { useNavigate } from "react-router-dom"; import { useAppSelector } from "store/hooks"; import { exhaustiveGuard } from "utils/typescriptUtils"; import { LoadingSpinnerAlert } from "./LoadingSpinnerAlert"; +import { bytesToMb } from "utils/conversionUtils"; + +const useStyles = makeStyles((theme) => ({ + innerAlert: { + display: "flex", + flexDirection: "column", + gap: theme.spacing(2), + }, +})); export default function DaemonStatusAlert() { + const classes = useStyles(); const contextStatus = useAppSelector((s) => s.rpc.status); const navigate = useNavigate(); @@ -16,20 +26,32 @@ export default function DaemonStatusAlert() { switch (contextStatus.type) { case "Initializing": - switch (contextStatus.content) { - case TauriContextInitializationProgress.OpeningBitcoinWallet: + switch (contextStatus.content.type) { + case "OpeningBitcoinWallet": return ( Connecting to the Bitcoin network ); - case TauriContextInitializationProgress.OpeningMoneroWallet: + case "DownloadingMoneroWalletRpc": + return ( + + + + Downloading and verifying the Monero wallet RPC ( + {bytesToMb(contextStatus.content.content.size).toFixed(2)} MB) + + + + + ); + case "OpeningMoneroWallet": return ( Connecting to the Monero network ); - case TauriContextInitializationProgress.OpeningDatabase: + case "OpeningDatabase": return ( Opening the local database diff --git a/src-gui/src/utils/conversionUtils.ts b/src-gui/src/utils/conversionUtils.ts index 776a1a3a7..3648ad125 100644 --- a/src-gui/src/utils/conversionUtils.ts +++ b/src-gui/src/utils/conversionUtils.ts @@ -30,9 +30,8 @@ export function isBtcAddressValid(address: string, testnet: boolean) { } export function getBitcoinTxExplorerUrl(txid: string, testnet: boolean) { - return `https://mempool.space/${ - testnet ? "/testnet" : "" - }/tx/${txid}`; + return `https://mempool.space/${testnet ? "/testnet" : "" + }/tx/${txid}`; } export function getMoneroTxExplorerUrl(txid: string, stagenet: boolean) { @@ -67,3 +66,7 @@ export function rendezvousSellerToProviderStatus( testnet: isTestnet(), }; } + +export function bytesToMb(bytes: number): number { + return bytes / (1024 * 1024); +} diff --git a/swap/src/cli/api.rs b/swap/src/cli/api.rs index 6218fb98f..4ac4a573a 100644 --- a/swap/src/cli/api.rs +++ b/swap/src/cli/api.rs @@ -336,8 +336,13 @@ impl ContextBuilder { let (monero_wallet, monero_rpc_process) = { if let Some(monero) = self.monero { let monero_daemon_address = monero.apply_defaults(self.is_testnet); - let (wlt, prc) = - init_monero_wallet(data_dir.clone(), monero_daemon_address, env_config).await?; + let (wlt, prc) = init_monero_wallet( + data_dir.clone(), + monero_daemon_address, + env_config, + self.tauri_handle.clone(), + ) + .await?; (Some(Arc::new(wlt)), Some(Arc::new(SyncMutex::new(prc)))) } else { (None, None) @@ -473,12 +478,13 @@ async fn init_monero_wallet( data_dir: PathBuf, monero_daemon_address: String, env_config: EnvConfig, + tauri_handle: Option, ) -> Result<(monero::Wallet, monero::WalletRpcProcess)> { let network = env_config.monero_network; const MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-monitoring-wallet"; - let monero_wallet_rpc = monero::WalletRpc::new(data_dir.join("monero")).await?; + let monero_wallet_rpc = monero::WalletRpc::new(data_dir.join("monero"), tauri_handle).await?; tracing::debug!( address = monero_daemon_address, diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 28fd20511..576a3ee54 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -110,8 +110,17 @@ impl TauriEmitter for Option { #[typeshare] #[derive(Display, Clone, Serialize)] +#[serde(tag = "type", content = "content")] pub enum TauriContextInitializationProgress { OpeningBitcoinWallet, + DownloadingMoneroWalletRpc { + // Progress of the download in percent (0-100) + #[typeshare(serialized_as = "number")] + progress: u64, + // Size of the download file in bytes + #[typeshare(serialized_as = "number")] + size: u64, + }, OpeningMoneroWallet, OpeningDatabase, } diff --git a/swap/src/monero/wallet_rpc.rs b/swap/src/monero/wallet_rpc.rs index 7c4179004..05e1633ca 100644 --- a/swap/src/monero/wallet_rpc.rs +++ b/swap/src/monero/wallet_rpc.rs @@ -21,6 +21,10 @@ use tokio::process::{Child, Command}; use tokio_util::codec::{BytesCodec, FramedRead}; use tokio_util::io::StreamReader; +use crate::cli::api::tauri_bindings::{ + TauriContextInitializationProgress, TauriContextStatusEvent, TauriEmitter, TauriHandle, +}; + // See: https://www.moneroworld.com/#nodes, https://monero.fail // We don't need any testnet nodes because we don't support testnet at all const MONERO_DAEMONS: Lazy<[MoneroDaemon; 16]> = Lazy::new(|| { @@ -201,7 +205,10 @@ pub struct WalletRpc { } impl WalletRpc { - pub async fn new(working_dir: impl AsRef) -> Result { + pub async fn new( + working_dir: impl AsRef, + tauri_handle: Option, + ) -> Result { let working_dir = working_dir.as_ref(); if !working_dir.exists() { @@ -255,6 +262,14 @@ impl WalletRpc { "Downloading monero-wallet-rpc", ); + // Emit a tauri event to update the progress + tauri_handle.emit_context_init_progress_event(TauriContextStatusEvent::Initializing( + TauriContextInitializationProgress::DownloadingMoneroWalletRpc { + progress: 0, + size: content_length, + }, + )); + let mut hasher = Sha256::new(); let byte_stream = response @@ -292,6 +307,16 @@ impl WalletRpc { "Downloading monero-wallet-rpc", ); notified = percent; + + // Emit a tauri event to update the progress + tauri_handle.emit_context_init_progress_event( + TauriContextStatusEvent::Initializing( + TauriContextInitializationProgress::DownloadingMoneroWalletRpc { + progress: percent, + size: content_length, + }, + ), + ); } file.write_all(&bytes).await?; }