Skip to content

Commit 4b3df90

Browse files
feat: use feature for console UI (#158)
* feat: use feature for console ui in dash spv * fmt * fix
1 parent c877c1a commit 4b3df90

File tree

4 files changed

+94
-48
lines changed

4 files changed

+94
-48
lines changed

dash-spv/Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ rand = "0.8"
4343
hex = "0.4"
4444
indexmap = "2.0"
4545

46-
# Terminal UI
47-
crossterm = "0.27"
46+
# Terminal UI (optional)
47+
crossterm = { version = "0.27", optional = true }
4848

4949
# DNS (trust-dns-resolver was renamed to hickory_resolver)
5050
hickory-resolver = "0.25"
@@ -61,6 +61,7 @@ hex = "0.4"
6161
[[bin]]
6262
name = "dash-spv"
6363
path = "src/main.rs"
64+
required-features = ["terminal-ui"]
6465

6566
[lib]
6667
name = "dash_spv"
@@ -69,3 +70,6 @@ path = "src/lib.rs"
6970
[features]
7071
# Gate incomplete mock-dependent tests to avoid "unexpected cfg" warnings.
7172
skip_mock_implementation_incomplete = []
73+
74+
# Terminal UI feature (off by default, for use by binary only)
75+
terminal-ui = ["dep:crossterm"]

dash-spv/src/client/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::sync::Arc;
1010
use std::time::{Duration, Instant, SystemTime};
1111
use tokio::sync::{mpsc, Mutex, RwLock};
1212

13+
#[cfg(feature = "terminal-ui")]
1314
use crate::terminal::TerminalUI;
1415
use std::collections::HashSet;
1516

@@ -77,6 +78,7 @@ pub struct DashSpvClient<W: WalletInterface, N: NetworkManager, S: StorageManage
7778
validation: ValidationManager,
7879
chainlock_manager: Arc<ChainLockManager>,
7980
running: Arc<RwLock<bool>>,
81+
#[cfg(feature = "terminal-ui")]
8082
terminal_ui: Option<Arc<TerminalUI>>,
8183
filter_processor: Option<FilterNotificationSender>,
8284
block_processor_tx: mpsc::UnboundedSender<BlockProcessingTask>,
@@ -241,6 +243,7 @@ impl<
241243
}
242244

243245
/// Helper to create a StatusDisplay instance.
246+
#[cfg(feature = "terminal-ui")]
244247
async fn create_status_display(&self) -> StatusDisplay<'_, S> {
245248
StatusDisplay::new(
246249
&self.state,
@@ -251,6 +254,12 @@ impl<
251254
)
252255
}
253256

257+
/// Helper to create a StatusDisplay instance (without terminal UI).
258+
#[cfg(not(feature = "terminal-ui"))]
259+
async fn create_status_display(&self) -> StatusDisplay<'_, S> {
260+
StatusDisplay::new(&self.state, &self.stats, self.storage.clone(), &None, &self.config)
261+
}
262+
254263
// UTXO mismatch checking removed - handled by external wallet
255264

256265
// Address mismatch checking removed - handled by external wallet
@@ -344,6 +353,7 @@ impl<
344353
validation,
345354
chainlock_manager,
346355
running: Arc::new(RwLock::new(false)),
356+
#[cfg(feature = "terminal-ui")]
347357
terminal_ui: None,
348358
filter_processor: None,
349359
block_processor_tx,
@@ -487,6 +497,7 @@ impl<
487497
}
488498

489499
// Update terminal UI after connection with initial data
500+
#[cfg(feature = "terminal-ui")]
490501
if let Some(ui) = &self.terminal_ui {
491502
// Get initial header count from storage
492503
let (header_height, filter_height) = {
@@ -511,12 +522,14 @@ impl<
511522
}
512523

513524
/// Enable terminal UI for status display.
525+
#[cfg(feature = "terminal-ui")]
514526
pub fn enable_terminal_ui(&mut self) {
515527
let ui = Arc::new(TerminalUI::new(true));
516528
self.terminal_ui = Some(ui);
517529
}
518530

519531
/// Get the terminal UI handle.
532+
#[cfg(feature = "terminal-ui")]
520533
pub fn get_terminal_ui(&self) -> Option<Arc<TerminalUI>> {
521534
self.terminal_ui.clone()
522535
}

dash-spv/src/client/status_display.rs

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use tokio::sync::{Mutex, RwLock};
66
use crate::client::ClientConfig;
77
use crate::error::Result;
88
use crate::storage::StorageManager;
9+
#[cfg(feature = "terminal-ui")]
910
use crate::terminal::TerminalUI;
1011
use crate::types::{ChainState, SpvStats, SyncProgress};
1112

@@ -14,12 +15,15 @@ pub struct StatusDisplay<'a, S: StorageManager> {
1415
state: &'a Arc<RwLock<ChainState>>,
1516
stats: &'a Arc<RwLock<SpvStats>>,
1617
storage: Arc<Mutex<S>>,
18+
#[cfg(feature = "terminal-ui")]
1719
terminal_ui: &'a Option<Arc<TerminalUI>>,
20+
#[allow(dead_code)]
1821
config: &'a ClientConfig,
1922
}
2023

2124
impl<'a, S: StorageManager + Send + Sync + 'static> StatusDisplay<'a, S> {
2225
/// Create a new status display manager.
26+
#[cfg(feature = "terminal-ui")]
2327
pub fn new(
2428
state: &'a Arc<RwLock<ChainState>>,
2529
stats: &'a Arc<RwLock<SpvStats>>,
@@ -36,6 +40,23 @@ impl<'a, S: StorageManager + Send + Sync + 'static> StatusDisplay<'a, S> {
3640
}
3741
}
3842

43+
/// Create a new status display manager (without terminal UI support).
44+
#[cfg(not(feature = "terminal-ui"))]
45+
pub fn new(
46+
state: &'a Arc<RwLock<ChainState>>,
47+
stats: &'a Arc<RwLock<SpvStats>>,
48+
storage: Arc<Mutex<S>>,
49+
_terminal_ui: &'a Option<()>,
50+
config: &'a ClientConfig,
51+
) -> Self {
52+
Self {
53+
state,
54+
stats,
55+
storage,
56+
config,
57+
}
58+
}
59+
3960
/// Calculate the header height based on the current state and storage.
4061
/// This handles both checkpoint sync and normal sync scenarios.
4162
async fn calculate_header_height_with_logging(
@@ -121,57 +142,64 @@ impl<'a, S: StorageManager + Send + Sync + 'static> StatusDisplay<'a, S> {
121142

122143
/// Update the status display.
123144
pub async fn update_status_display(&self) {
124-
if let Some(ui) = self.terminal_ui {
125-
// Get header height - when syncing from checkpoint, use the actual blockchain height
126-
let header_height = {
127-
let state = self.state.read().await;
128-
self.calculate_header_height_with_logging(&state, true).await
129-
};
130-
131-
// Get filter header height from storage
132-
let storage = self.storage.lock().await;
133-
let filter_height = storage.get_filter_tip_height().await.ok().flatten().unwrap_or(0);
134-
drop(storage);
135-
136-
// Get latest chainlock height from state
137-
let chainlock_height = {
138-
let state = self.state.read().await;
139-
state.last_chainlock_height
140-
};
141-
142-
// Get latest chainlock height from storage metadata (in case state wasn't updated)
143-
let stored_chainlock_height = {
145+
#[cfg(feature = "terminal-ui")]
146+
{
147+
if let Some(ui) = self.terminal_ui {
148+
// Get header height - when syncing from checkpoint, use the actual blockchain height
149+
let header_height = {
150+
let state = self.state.read().await;
151+
self.calculate_header_height_with_logging(&state, true).await
152+
};
153+
154+
// Get filter header height from storage
144155
let storage = self.storage.lock().await;
145-
if let Ok(Some(data)) = storage.load_metadata("latest_chainlock_height").await {
146-
if data.len() >= 4 {
147-
Some(u32::from_le_bytes([data[0], data[1], data[2], data[3]]))
156+
let filter_height =
157+
storage.get_filter_tip_height().await.ok().flatten().unwrap_or(0);
158+
drop(storage);
159+
160+
// Get latest chainlock height from state
161+
let chainlock_height = {
162+
let state = self.state.read().await;
163+
state.last_chainlock_height
164+
};
165+
166+
// Get latest chainlock height from storage metadata (in case state wasn't updated)
167+
let stored_chainlock_height = {
168+
let storage = self.storage.lock().await;
169+
if let Ok(Some(data)) = storage.load_metadata("latest_chainlock_height").await {
170+
if data.len() >= 4 {
171+
Some(u32::from_le_bytes([data[0], data[1], data[2], data[3]]))
172+
} else {
173+
None
174+
}
148175
} else {
149176
None
150177
}
151-
} else {
152-
None
153-
}
154-
};
155-
156-
// Use the higher of the two chainlock heights
157-
let latest_chainlock = match (chainlock_height, stored_chainlock_height) {
158-
(Some(a), Some(b)) => Some(a.max(b)),
159-
(Some(a), None) => Some(a),
160-
(None, Some(b)) => Some(b),
161-
(None, None) => None,
162-
};
178+
};
179+
180+
// Use the higher of the two chainlock heights
181+
let latest_chainlock = match (chainlock_height, stored_chainlock_height) {
182+
(Some(a), Some(b)) => Some(a.max(b)),
183+
(Some(a), None) => Some(a),
184+
(None, Some(b)) => Some(b),
185+
(None, None) => None,
186+
};
187+
188+
// Update terminal UI
189+
let _ = ui
190+
.update_status(|status| {
191+
status.headers = header_height;
192+
status.filter_headers = filter_height;
193+
status.chainlock_height = latest_chainlock;
194+
status.peer_count = 1; // TODO: Get actual peer count
195+
status.network = format!("{:?}", self.config.network);
196+
})
197+
.await;
198+
return;
199+
}
200+
}
163201

164-
// Update terminal UI
165-
let _ = ui
166-
.update_status(|status| {
167-
status.headers = header_height;
168-
status.filter_headers = filter_height;
169-
status.chainlock_height = latest_chainlock;
170-
status.peer_count = 1; // TODO: Get actual peer count
171-
status.network = format!("{:?}", self.config.network);
172-
})
173-
.await;
174-
} else {
202+
{
175203
// Fall back to simple logging if terminal UI is not enabled
176204
// Get header height - when syncing from checkpoint, use the actual blockchain height
177205
let header_height = {

dash-spv/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub mod mempool_filter;
6666
pub mod network;
6767
pub mod storage;
6868
pub mod sync;
69+
#[cfg(feature = "terminal-ui")]
6970
pub mod terminal;
7071
pub mod types;
7172
pub mod validation;

0 commit comments

Comments
 (0)