diff --git a/crates/bin/pcli/src/lib.rs b/crates/bin/pcli/src/lib.rs new file mode 100644 index 0000000000..4ebc6867d6 --- /dev/null +++ b/crates/bin/pcli/src/lib.rs @@ -0,0 +1,80 @@ +#![deny(clippy::unwrap_used)] +#![allow(clippy::clone_on_copy)] + +use { + crate::{command::*, config::PcliConfig}, + anyhow::Result, + futures::StreamExt, + penumbra_proto::{ + box_grpc_svc::BoxGrpcService, custody::v1::custody_service_client::CustodyServiceClient, + view::v1::view_service_client::ViewServiceClient, + }, + penumbra_view::ViewClient, +}; + +pub mod command; +pub mod config; +pub mod opt; +pub mod warning; + +mod dex_utils; +mod network; +mod terminal; +mod transaction_view_ext; + +const CONFIG_FILE_NAME: &str = "config.toml"; +const VIEW_FILE_NAME: &str = "pcli-view.sqlite"; + +#[derive(Debug)] +pub struct App { + /// view will be `None` when a command indicates that it can be run offline via + /// `.offline()` and Some(_) otherwise. Assuming `.offline()` has been implemenented + /// correctly, this can be unwrapped safely. + pub view: Option>, + pub custody: CustodyServiceClient, + pub governance_custody: CustodyServiceClient, + pub config: PcliConfig, +} + +impl App { + pub fn view(&mut self) -> &mut impl ViewClient { + self.view.as_mut().expect("view service initialized") + } + + pub async fn sync(&mut self) -> Result<()> { + let mut status_stream = + ViewClient::status_stream(self.view.as_mut().expect("view service initialized")) + .await?; + + // Pull out the first message from the stream, which has the current state, and use + // it to set up a progress bar. + let initial_status = status_stream + .next() + .await + .transpose()? + .ok_or_else(|| anyhow::anyhow!("view service did not report sync status"))?; + + eprintln!( + "Scanning blocks from last sync height {} to latest height {}", + initial_status.full_sync_height, initial_status.latest_known_block_height, + ); + + use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; + let progress_bar = ProgressBar::with_draw_target( + initial_status.latest_known_block_height - initial_status.full_sync_height, + ProgressDrawTarget::stdout(), + ) + .with_style( + ProgressStyle::default_bar() + .template("[{elapsed}] {bar:50.cyan/blue} {pos:>7}/{len:7} {per_sec} ETA: {eta}"), + ); + progress_bar.set_position(0); + + while let Some(status) = status_stream.next().await.transpose()? { + progress_bar.set_position(status.full_sync_height - initial_status.full_sync_height); + } + progress_bar.finish(); + + Ok(()) + } +} diff --git a/crates/bin/pcli/src/main.rs b/crates/bin/pcli/src/main.rs index 151aa776cf..b308769aac 100644 --- a/crates/bin/pcli/src/main.rs +++ b/crates/bin/pcli/src/main.rs @@ -5,86 +5,14 @@ use std::fs; use anyhow::{Context, Result}; use clap::Parser; -use futures::StreamExt; -use penumbra_proto::{ - box_grpc_svc::BoxGrpcService, custody::v1::custody_service_client::CustodyServiceClient, - view::v1::view_service_client::ViewServiceClient, -}; -use penumbra_view::ViewClient; -use crate::{command::*, config::PcliConfig, opt::Opt}; - -mod command; -mod config; -mod dex_utils; -mod network; -mod opt; -mod terminal; -mod transaction_view_ext; -mod warning; - -const CONFIG_FILE_NAME: &str = "config.toml"; -const VIEW_FILE_NAME: &str = "pcli-view.sqlite"; - -#[derive(Debug)] -pub struct App { - /// view will be `None` when a command indicates that it can be run offline via - /// `.offline()` and Some(_) otherwise. Assuming `.offline()` has been implemenented - /// correctly, this can be unwrapped safely. - pub view: Option>, - pub custody: CustodyServiceClient, - pub governance_custody: CustodyServiceClient, - pub config: PcliConfig, -} - -impl App { - pub fn view(&mut self) -> &mut impl ViewClient { - self.view.as_mut().expect("view service initialized") - } - - async fn sync(&mut self) -> Result<()> { - let mut status_stream = - ViewClient::status_stream(self.view.as_mut().expect("view service initialized")) - .await?; - - // Pull out the first message from the stream, which has the current state, and use - // it to set up a progress bar. - let initial_status = status_stream - .next() - .await - .transpose()? - .ok_or_else(|| anyhow::anyhow!("view service did not report sync status"))?; - - eprintln!( - "Scanning blocks from last sync height {} to latest height {}", - initial_status.full_sync_height, initial_status.latest_known_block_height, - ); - - use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; - let progress_bar = ProgressBar::with_draw_target( - initial_status.latest_known_block_height - initial_status.full_sync_height, - ProgressDrawTarget::stdout(), - ) - .with_style( - ProgressStyle::default_bar() - .template("[{elapsed}] {bar:50.cyan/blue} {pos:>7}/{len:7} {per_sec} ETA: {eta}"), - ); - progress_bar.set_position(0); - - while let Some(status) = status_stream.next().await.transpose()? { - progress_bar.set_position(status.full_sync_height - initial_status.full_sync_height); - } - progress_bar.finish(); - - Ok(()) - } -} +use pcli::{command::*, opt::Opt}; #[tokio::main] async fn main() -> Result<()> { // Display a warning message to the user so they don't get upset when all their tokens are lost. if std::env::var("PCLI_UNLEASH_DANGER").is_err() { - warning::display(); + pcli::warning::display(); } let mut opt = Opt::parse();