From 6475b57ea84673d266e5aab549f00ebcef33055d Mon Sep 17 00:00:00 2001 From: striderDM <51991544+StriderDM@users.noreply.github.com> Date: Fri, 3 Dec 2021 15:50:03 +0200 Subject: [PATCH] feat: base_node switching for console_wallet when status is offline This PR allows the console_wallet to periodically attempt to connect to another base_node in the list should it be found to be offline. --- .../tari_console_wallet/src/ui/app.rs | 1 + .../src/ui/components/base_node.rs | 7 ++-- .../src/ui/state/app_state.rs | 33 ++++++++++++++++--- .../mock_base_node_service.rs | 14 +++++--- .../wallet/src/base_node_service/monitor.rs | 10 ++++-- .../wallet/src/base_node_service/service.rs | 3 +- .../src/connectivity_service/service.rs | 6 ++++ 7 files changed, 59 insertions(+), 15 deletions(-) diff --git a/applications/tari_console_wallet/src/ui/app.rs b/applications/tari_console_wallet/src/ui/app.rs index 01ab0bf701..22b5ad5b07 100644 --- a/applications/tari_console_wallet/src/ui/app.rs +++ b/applications/tari_console_wallet/src/ui/app.rs @@ -153,6 +153,7 @@ impl App { pub fn on_tick(&mut self) { Handle::current().block_on(self.app_state.update_cache()); + Handle::current().block_on(self.app_state.check_connectivity()); self.tabs.on_tick(&mut self.app_state); } diff --git a/applications/tari_console_wallet/src/ui/components/base_node.rs b/applications/tari_console_wallet/src/ui/components/base_node.rs index cd5cb0a56f..ada76b6780 100644 --- a/applications/tari_console_wallet/src/ui/components/base_node.rs +++ b/applications/tari_console_wallet/src/ui/components/base_node.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::ui::{components::Component, state::AppState}; -use tari_wallet::connectivity_service::{OnlineStatus, WalletConnectivityInterface}; +use tari_wallet::connectivity_service::OnlineStatus; use tui::{ backend::Backend, layout::Rect, @@ -42,9 +42,9 @@ impl BaseNode { impl Component for BaseNode { fn draw(&mut self, f: &mut Frame, area: Rect, app_state: &AppState) where B: Backend { - let current_online_status = app_state.get_wallet_connectivity().get_connectivity_status(); + let base_node_state = app_state.get_base_node_state(); - let chain_info = match current_online_status { + let chain_info = match base_node_state.status { OnlineStatus::Connecting => Spans::from(vec![ Span::styled("Chain Tip:", Style::default().fg(Color::Magenta)), Span::raw(" "), @@ -56,7 +56,6 @@ impl Component for BaseNode { Span::styled("Offline", Style::default().fg(Color::Red)), ]), OnlineStatus::Online => { - let base_node_state = app_state.get_base_node_state(); if let Some(ref metadata) = base_node_state.chain_metadata { let tip = metadata.height_of_longest_chain(); diff --git a/applications/tari_console_wallet/src/ui/state/app_state.rs b/applications/tari_console_wallet/src/ui/state/app_state.rs index 3d8665fe07..158a550be5 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -78,6 +78,7 @@ use crate::{ utils::db::{CUSTOM_BASE_NODE_ADDRESS_KEY, CUSTOM_BASE_NODE_PUBLIC_KEY_KEY}, wallet_modes::PeerConfig, }; +use tari_wallet::connectivity_service::{OnlineStatus, WalletConnectivityInterface}; const LOG_TARGET: &str = "wallet::console_wallet::app_state"; @@ -86,6 +87,7 @@ pub struct AppState { inner: Arc>, cached_data: AppStateData, cache_update_cooldown: Option, + connectivity_check_cooldown: Option, completed_tx_filter: TransactionFilter, node_config: GlobalConfig, config: AppStateConfig, @@ -112,6 +114,7 @@ impl AppState { inner: inner.clone(), cached_data, cache_update_cooldown: None, + connectivity_check_cooldown: Some(Instant::now()), completed_tx_filter: TransactionFilter::ABANDONED_COINBASES, node_config: node_config.clone(), config: AppStateConfig::default(), @@ -181,6 +184,30 @@ impl AppState { } } + pub async fn check_connectivity(&mut self) { + let update = match self.connectivity_check_cooldown { + Some(last_update) => last_update.elapsed() > self.config.connectivity_check_interval, + None => { + self.connectivity_check_cooldown = Some(Instant::now()); + false + }, + }; + + if update && self.wallet_connectivity.get_connectivity_status() == OnlineStatus::Offline { + let current = self.get_selected_base_node(); + let list = self.get_base_node_list().clone(); + let mut index: usize = list.iter().position(|(_, p)| p == current).unwrap_or_default(); + if index == list.len() { + index = 0; + } else { + index += 1; + } + let (_, next) = &list[index]; + let _ = self.set_base_node_peer(next.clone()).await.unwrap_or_default(); + self.connectivity_check_cooldown = Some(Instant::now()) + } + } + pub async fn upsert_contact(&mut self, alias: String, public_key_or_emoji_id: String) -> Result<(), UiError> { let mut inner = self.inner.write().await; @@ -380,10 +407,6 @@ impl AppState { &self.cached_data.base_node_state } - pub fn get_wallet_connectivity(&self) -> WalletConnectivityHandle { - self.wallet_connectivity.clone() - } - pub fn get_selected_base_node(&self) -> &Peer { &self.cached_data.base_node_selected } @@ -1052,12 +1075,14 @@ bitflags! { #[derive(Clone)] struct AppStateConfig { pub cache_update_cooldown: Duration, + pub connectivity_check_interval: Duration, } impl Default for AppStateConfig { fn default() -> Self { Self { cache_update_cooldown: Duration::from_secs(2), + connectivity_check_interval: Duration::from_secs(5), } } } diff --git a/base_layer/wallet/src/base_node_service/mock_base_node_service.rs b/base_layer/wallet/src/base_node_service/mock_base_node_service.rs index e7de7a9d6e..65c456bcf9 100644 --- a/base_layer/wallet/src/base_node_service/mock_base_node_service.rs +++ b/base_layer/wallet/src/base_node_service/mock_base_node_service.rs @@ -20,10 +20,13 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use crate::base_node_service::{ - error::BaseNodeServiceError, - handle::{BaseNodeServiceRequest, BaseNodeServiceResponse}, - service::BaseNodeState, +use crate::{ + base_node_service::{ + error::BaseNodeServiceError, + handle::{BaseNodeServiceRequest, BaseNodeServiceResponse}, + service::BaseNodeState, + }, + connectivity_service::OnlineStatus, }; use futures::StreamExt; use tari_common_types::chain_metadata::ChainMetadata; @@ -85,11 +88,13 @@ impl MockBaseNodeService { }, None => (None, None), }; + self.state = BaseNodeState { chain_metadata, is_synced, updated: None, latency: None, + status: self.state.status, } } @@ -100,6 +105,7 @@ impl MockBaseNodeService { is_synced: Some(true), updated: None, latency: None, + status: OnlineStatus::default(), } } diff --git a/base_layer/wallet/src/base_node_service/monitor.rs b/base_layer/wallet/src/base_node_service/monitor.rs index a79d04428f..f2d00f36f6 100644 --- a/base_layer/wallet/src/base_node_service/monitor.rs +++ b/base_layer/wallet/src/base_node_service/monitor.rs @@ -25,7 +25,7 @@ use crate::{ handle::{BaseNodeEvent, BaseNodeEventSender}, service::BaseNodeState, }, - connectivity_service::WalletConnectivityInterface, + connectivity_service::{OnlineStatus, WalletConnectivityInterface}, error::WalletStorageError, storage::database::{WalletBackend, WalletDatabase}, }; @@ -93,6 +93,7 @@ where is_synced: None, updated: None, latency: None, + status: OnlineStatus::Offline, }) .await; continue; @@ -125,11 +126,15 @@ where timer.elapsed().as_millis() ); - let base_node_id = match self.wallet_connectivity.get_current_base_node_id() { + let mut connectivity = self.wallet_connectivity.clone(); + + let base_node_id = match connectivity.get_current_base_node_id() { Some(n) => n, None => continue, }; + let status = connectivity.get_connectivity_status(); + let timer = Instant::now(); let tip_info = match interrupt(base_node_watch.changed(), client.get_tip_info()).await { Some(tip_info) => tip_info?, @@ -171,6 +176,7 @@ where is_synced: Some(is_synced), updated: Some(Utc::now().naive_utc()), latency: Some(latency), + status, }) .await; diff --git a/base_layer/wallet/src/base_node_service/service.rs b/base_layer/wallet/src/base_node_service/service.rs index c00af91d47..083bf7c7f6 100644 --- a/base_layer/wallet/src/base_node_service/service.rs +++ b/base_layer/wallet/src/base_node_service/service.rs @@ -27,7 +27,7 @@ use super::{ }; use crate::{ base_node_service::monitor::BaseNodeMonitor, - connectivity_service::WalletConnectivityHandle, + connectivity_service::{OnlineStatus, WalletConnectivityHandle}, storage::database::{WalletBackend, WalletDatabase}, }; use chrono::NaiveDateTime; @@ -48,6 +48,7 @@ pub struct BaseNodeState { pub is_synced: Option, pub updated: Option, pub latency: Option, + pub status: OnlineStatus, } /// The base node service is responsible for handling requests to be sent to the connected base node. diff --git a/base_layer/wallet/src/connectivity_service/service.rs b/base_layer/wallet/src/connectivity_service/service.rs index d558389747..c24b26f12d 100644 --- a/base_layer/wallet/src/connectivity_service/service.rs +++ b/base_layer/wallet/src/connectivity_service/service.rs @@ -50,6 +50,12 @@ pub enum OnlineStatus { Offline, } +impl Default for OnlineStatus { + fn default() -> Self { + OnlineStatus::Connecting + } +} + pub struct WalletConnectivityService { config: BaseNodeServiceConfig, request_receiver: mpsc::Receiver,