diff --git a/src/context/connection_status.rs b/src/context/connection_status.rs index df5d429e2..836559b75 100644 --- a/src/context/connection_status.rs +++ b/src/context/connection_status.rs @@ -7,7 +7,7 @@ use crate::components::core_zmq_listener::ZMQConnectionEvent; use crate::spv::{CoreBackendMode, SpvStatus}; use dash_sdk::dpp::dashcore::{ChainLock, Network}; use std::sync::Mutex; -use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU16, Ordering}; use std::time::{Duration, Instant}; const REFRESH_CONNECTED: Duration = Duration::from_secs(10); @@ -25,6 +25,8 @@ pub struct ConnectionStatus { disable_zmq: AtomicBool, overall_connected: AtomicBool, last_update: Mutex, + dapi_total_endpoints: AtomicU16, + dapi_available_endpoints: AtomicU16, } impl ConnectionStatus { @@ -37,6 +39,8 @@ impl ConnectionStatus { disable_zmq: AtomicBool::new(false), overall_connected: AtomicBool::new(false), last_update: Mutex::new(Instant::now()), + dapi_total_endpoints: AtomicU16::new(0), + dapi_available_endpoints: AtomicU16::new(0), } } @@ -107,6 +111,37 @@ impl ConnectionStatus { self.disable_zmq.store(disable, Ordering::Relaxed); } + pub fn dapi_total_endpoints(&self) -> u16 { + self.dapi_total_endpoints.load(Ordering::Relaxed) + } + + pub fn dapi_available_endpoints(&self) -> u16 { + self.dapi_available_endpoints.load(Ordering::Relaxed) + } + + pub fn dapi_available(&self) -> bool { + self.dapi_available_endpoints.load(Ordering::Relaxed) > 0 + } + + pub fn set_dapi_status(&self, total: u16, available: u16) { + self.dapi_total_endpoints.store(total, Ordering::Relaxed); + self.dapi_available_endpoints + .store(available, Ordering::Relaxed); + } + + /// Returns the DAPI status label suitable for display. + pub fn dapi_status_label(&self) -> String { + let total = self.dapi_total_endpoints(); + let available = self.dapi_available_endpoints(); + if total == 0 { + "No endpoints configured".to_string() + } else if available > 0 { + format!("Available ({available}/{total} endpoints)") + } else { + format!("All {total} endpoints banned") + } + } + pub fn spv_connected(status: SpvStatus) -> bool { status.is_active() } @@ -119,9 +154,12 @@ impl ConnectionStatus { let backend_mode = self.backend_mode(); let disable_zmq = self.disable_zmq(); let spv_status = self.spv_status(); + let dapi_available = self.dapi_available(); let connected = match backend_mode { - CoreBackendMode::Rpc => self.rpc_online() && (disable_zmq || self.zmq_connected()), - CoreBackendMode::Spv => Self::spv_connected(spv_status), + CoreBackendMode::Rpc => { + self.rpc_online() && (disable_zmq || self.zmq_connected()) && dapi_available + } + CoreBackendMode::Spv => Self::spv_connected(spv_status) && dapi_available, }; self.overall_connected.store(connected, Ordering::Relaxed); } @@ -130,6 +168,7 @@ impl ConnectionStatus { let backend_mode = self.backend_mode(); let disable_zmq = self.disable_zmq(); let spv_status = self.spv_status(); + let dapi_status = format!("DAPI: {}", self.dapi_status_label()); match backend_mode { CoreBackendMode::Rpc => { let rpc_status = if self.rpc_online() { @@ -146,21 +185,25 @@ impl ConnectionStatus { }; if self.overall_connected() { - format!("Connected to Dash Core Wallet\n{rpc_status}\n{zmq_status}") + format!( + "Connected to Dash Core Wallet\n{rpc_status}\n{zmq_status}\n{dapi_status}" + ) } else if self.rpc_online() { - format!("Dash Core connection incomplete\n{rpc_status}\n{zmq_status}") + format!( + "Dash Core connection incomplete\n{rpc_status}\n{zmq_status}\n{dapi_status}" + ) } else { format!( - "Disconnected from Dash Core Wallet. Click to start it.\n{rpc_status}\n{zmq_status}" + "Disconnected from Dash Core Wallet. Click to start it.\n{rpc_status}\n{zmq_status}\n{dapi_status}" ) } } CoreBackendMode::Spv => { let spv_label = format!("SPV: {:?}", spv_status); if self.overall_connected() { - format!("SPV connected\n{spv_label}") + format!("SPV connected\n{spv_label}\n{dapi_status}") } else { - format!("SPV disconnected\n{spv_label}") + format!("SPV disconnected\n{spv_label}\n{dapi_status}") } } } @@ -274,6 +317,22 @@ impl ConnectionStatus { } } + // Update DAPI endpoint status + if let Ok(sdk) = app_context.sdk.read() { + let address_list = sdk.address_list(); + let total = address_list.len() as u16; + // get_live_address() returns Option<&Uri>, so count it as 1 if available, 0 if not + // TODO: once Dash Platform SDK supports rust-dashcore v0.42, + // update platform and use get_live_addresses() which returns all available addresses + //for more accurate status + let available = if address_list.get_live_address().is_some() { + 1 + } else { + 0 + }; + self.set_dapi_status(total, available); + } + self.refresh_overall(); } } diff --git a/src/ui/network_chooser_screen.rs b/src/ui/network_chooser_screen.rs index da3e07fd7..e723d496b 100644 --- a/src/ui/network_chooser_screen.rs +++ b/src/ui/network_chooser_screen.rs @@ -37,6 +37,27 @@ enum DatabaseClearMessage { Error(String), } +/// Renders DAPI endpoint status with appropriate color coding. +fn add_dapi_status_label( + ui: &mut Ui, + dapi_total: u16, + dapi_available: bool, + dapi_label: &str, + dark_mode: bool, +) { + ui.label("DAPI:"); + if dapi_total == 0 { + ui.colored_label(DashColors::text_secondary(dark_mode), dapi_label); + } else { + let color = if dapi_available { + DashColors::SUCCESS + } else { + DashColors::ERROR + }; + ui.colored_label(color, dapi_label); + } +} + pub struct NetworkChooserScreen { pub mainnet_app_context: Arc, pub testnet_app_context: Option>, @@ -469,6 +490,9 @@ impl NetworkChooserScreen { None }; let overall_connected = status.overall_connected(); + let dapi_total = status.dapi_total_endpoints(); + let dapi_available = status.dapi_available(); + let dapi_label = status.dapi_status_label(); // Button on the left with status ui.horizontal(|ui| { @@ -617,6 +641,9 @@ impl NetworkChooserScreen { let zmq_label = if zmq_connected { "Connected" } else { "Disconnected" }; ui.colored_label(zmq_color, zmq_label); } + + ui.label(","); + add_dapi_status_label(ui, dapi_total, dapi_available, &dapi_label, dark_mode); }); } @@ -649,6 +676,10 @@ impl NetworkChooserScreen { ui.colored_label(color, label); } }); + + ui.horizontal(|ui| { + add_dapi_status_label(ui, dapi_total, dapi_available, &dapi_label, dark_mode); + }); } if current_backend_mode == CoreBackendMode::Spv { @@ -661,6 +692,10 @@ impl NetworkChooserScreen { }; ui.colored_label(color, spv_status.to_string()); }); + + ui.horizontal(|ui| { + add_dapi_status_label(ui, dapi_total, dapi_available, &dapi_label, dark_mode); + }); } }); });