1#![deny(clippy::unwrap_used)]
2#![allow(clippy::clone_on_copy)]
3
4use {
5 crate::{command::*, config::PcliConfig},
6 anyhow::Result,
7 camino::Utf8PathBuf,
8 directories::ProjectDirs,
9 futures::StreamExt,
10 penumbra_sdk_proto::{
11 box_grpc_svc::BoxGrpcService, custody::v1::custody_service_client::CustodyServiceClient,
12 view::v1::view_service_client::ViewServiceClient,
13 },
14 penumbra_sdk_view::ViewClient,
15 std::path::PathBuf,
16};
17
18pub mod command;
19pub mod config;
20pub mod opt;
21pub mod warning;
22
23mod dex_utils;
24mod network;
25mod terminal;
26mod transaction_view_ext;
27
28const CONFIG_FILE_NAME: &str = "config.toml";
29const VIEW_FILE_NAME: &str = "pcli-view.sqlite";
30
31#[derive(Debug)]
32pub struct App {
33 pub view: Option<ViewServiceClient<BoxGrpcService>>,
37 pub custody: CustodyServiceClient<BoxGrpcService>,
38 pub governance_custody: CustodyServiceClient<BoxGrpcService>,
39 pub config: PcliConfig,
40 pub save_transaction_here_instead: Option<PathBuf>,
42}
43
44impl App {
45 pub fn view(&mut self) -> &mut impl ViewClient {
46 self.view.as_mut().expect("view service initialized")
47 }
48
49 pub async fn sync(&mut self) -> Result<()> {
50 let mut status_stream =
51 ViewClient::status_stream(self.view.as_mut().expect("view service initialized"))
52 .await?;
53
54 let initial_status = status_stream
57 .next()
58 .await
59 .transpose()?
60 .ok_or_else(|| anyhow::anyhow!("view service did not report sync status"))?;
61
62 eprintln!(
63 "Scanning blocks from last sync height {} to latest height {}",
64 initial_status.full_sync_height, initial_status.latest_known_block_height,
65 );
66
67 use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
68 let progress_bar = ProgressBar::with_draw_target(
69 initial_status.latest_known_block_height - initial_status.full_sync_height,
70 ProgressDrawTarget::stdout(),
71 )
72 .with_style(
73 ProgressStyle::default_bar()
74 .template("[{elapsed}] {bar:50.cyan/blue} {pos:>7}/{len:7} {per_sec} ETA: {eta}"),
75 );
76 progress_bar.set_position(0);
77
78 while let Some(status) = status_stream.next().await.transpose()? {
79 progress_bar.set_position(status.full_sync_height - initial_status.full_sync_height);
80 }
81 progress_bar.finish();
82
83 Ok(())
84 }
85}
86
87pub fn default_home() -> Utf8PathBuf {
88 let path = ProjectDirs::from("zone", "penumbra", "pcli")
89 .expect("Failed to get platform data dir")
90 .data_dir()
91 .to_path_buf();
92 Utf8PathBuf::from_path_buf(path).expect("Platform default data dir was not UTF-8")
93}