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 44ffe02de7..60ad6c115d 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -757,7 +757,7 @@ impl AppStateInner { let online_status = self .wallet .contacts_service - .get_contact_online_status(contact.last_seen) + .get_contact_online_status(contact.clone()) .await?; ui_contacts.push(UiContact::from(contact.clone()).with_online_status(format!("{}", online_status))); } diff --git a/base_layer/wallet/src/contacts_service/error.rs b/base_layer/wallet/src/contacts_service/error.rs index 7e870c2006..cf27a2af74 100644 --- a/base_layer/wallet/src/contacts_service/error.rs +++ b/base_layer/wallet/src/contacts_service/error.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use diesel::result::Error as DieselError; +use tari_comms::connectivity::ConnectivityError; use tari_p2p::services::liveness::error::LivenessError; use tari_service_framework::reply_channel::TransportChannelError; use thiserror::Error; @@ -40,6 +41,8 @@ pub enum ContactsServiceError { TransportChannelError(#[from] TransportChannelError), #[error("Livenessl error: `{0}`")] LivenessError(#[from] LivenessError), + #[error("ConnectivityError error: `{0}`")] + ConnectivityError(#[from] ConnectivityError), } #[derive(Debug, Error)] diff --git a/base_layer/wallet/src/contacts_service/handle.rs b/base_layer/wallet/src/contacts_service/handle.rs index 8763408941..45c7fe8cfd 100644 --- a/base_layer/wallet/src/contacts_service/handle.rs +++ b/base_layer/wallet/src/contacts_service/handle.rs @@ -128,7 +128,7 @@ pub enum ContactsServiceRequest { UpsertContact(Contact), RemoveContact(CommsPublicKey), GetContacts, - GetContactOnlineStatus(Option), + GetContactOnlineStatus(Contact), } #[derive(Debug)] @@ -212,11 +212,11 @@ impl ContactsServiceHandle { /// Determines the contact's online status based on their last seen time pub async fn get_contact_online_status( &mut self, - last_seen: Option, + contact: Contact, ) -> Result { match self .request_response_service - .call(ContactsServiceRequest::GetContactOnlineStatus(last_seen)) + .call(ContactsServiceRequest::GetContactOnlineStatus(contact)) .await?? { ContactsServiceResponse::OnlineStatus(status) => Ok(status), diff --git a/base_layer/wallet/src/contacts_service/service.rs b/base_layer/wallet/src/contacts_service/service.rs index 95470e8816..9bed181739 100644 --- a/base_layer/wallet/src/contacts_service/service.rs +++ b/base_layer/wallet/src/contacts_service/service.rs @@ -67,6 +67,7 @@ pub enum ContactOnlineStatus { Online, Offline, NeverSeen, + Banned(String), } impl Display for ContactOnlineStatus { @@ -75,6 +76,7 @@ impl Display for ContactOnlineStatus { ContactOnlineStatus::Online => write!(f, "Online"), ContactOnlineStatus::Offline => write!(f, "Offline"), ContactOnlineStatus::NeverSeen => write!(f, "NeverSeen"), + ContactOnlineStatus::Banned(reason) => write!(f, "Banned: {}", reason), } } } @@ -226,8 +228,8 @@ where T: ContactsBackend + 'static } Ok(result.map(ContactsServiceResponse::Contacts)?) }, - ContactsServiceRequest::GetContactOnlineStatus(last_seen) => { - let result = self.get_online_status(last_seen); + ContactsServiceRequest::GetContactOnlineStatus(contact) => { + let result = self.get_online_status(&contact).await; Ok(result.map(ContactsServiceResponse::OnlineStatus)?) }, } @@ -277,7 +279,7 @@ where T: ContactsBackend + 'static // Update offline status if let Ok(contacts) = self.db.get_contacts().await { for contact in contacts { - let online_status = self.get_online_status(contact.last_seen)?; + let online_status = self.get_online_status(&contact).await?; if online_status == ContactOnlineStatus::Online { continue; } @@ -302,9 +304,17 @@ where T: ContactsBackend + 'static Ok(()) } - fn get_online_status(&self, last_seen: Option) -> Result { + async fn get_online_status(&self, contact: &Contact) -> Result { let mut online_status = ContactOnlineStatus::NeverSeen; - if let Some(time) = last_seen { + match self.connectivity.get_peer_info(contact.node_id.clone()).await? { + Some(peer_data) => { + if peer_data.banned_until().is_some() { + return Ok(ContactOnlineStatus::Banned(peer_data.banned_reason)); + } + }, + None => return Ok(online_status), + }; + if let Some(time) = contact.last_seen { if self.is_online(time) { online_status = ContactOnlineStatus::Online; } else { diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index 7eed610dd4..8d5fdd2490 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -2251,16 +2251,24 @@ pub unsafe extern "C" fn liveness_data_get_message_type( pub unsafe extern "C" fn liveness_data_get_online_status( liveness_data: *mut TariContactsLivenessData, error_out: *mut c_int, -) -> c_int { +) -> *const c_char { let mut error = 0; + let mut result = CString::new("").expect("Blank CString will not fail."); ptr::swap(error_out, &mut error as *mut c_int); if liveness_data.is_null() { error = LibWalletError::from(InterfaceError::NullError("liveness_data".to_string())).code; ptr::swap(error_out, &mut error as *mut c_int); - return -1; + return result.into_raw(); } let status = (*liveness_data).online_status(); - status as c_int + match CString::new(status.to_string()) { + Ok(v) => result = v, + _ => { + error = LibWalletError::from(InterfaceError::PointerError("message".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + }, + } + result.into_raw() } /// Frees memory for a TariContactsLivenessData diff --git a/base_layer/wallet_ffi/wallet.h b/base_layer/wallet_ffi/wallet.h index 8ef8bf8936..09b190b334 100644 --- a/base_layer/wallet_ffi/wallet.h +++ b/base_layer/wallet_ffi/wallet.h @@ -1235,8 +1235,8 @@ int liveness_data_get_message_type(TariContactsLivenessData *liveness_data, * The ```liveness_data_destroy``` method must be called when finished with a TariContactsLivenessData to prevent a * memory leak */ -int liveness_data_get_online_status(TariContactsLivenessData *liveness_data, - int *error_out); +const char *liveness_data_get_online_status(TariContactsLivenessData *liveness_data, + int *error_out); /** * Frees memory for a TariContactsLivenessData diff --git a/comms/core/src/connectivity/manager.rs b/comms/core/src/connectivity/manager.rs index c83556d285..0d849c5fb1 100644 --- a/comms/core/src/connectivity/manager.rs +++ b/comms/core/src/connectivity/manager.rs @@ -248,6 +248,16 @@ impl ConnectivityManagerActor { .cloned(), ); }, + GetPeerStats(node_id, reply) => { + let peer = match self.peer_manager.find_by_node_id(&node_id).await { + Ok(v) => v, + Err(e) => { + error!(target: LOG_TARGET, "Error when retrieving peer: {:?}", e); + None + }, + }; + let _result = reply.send(peer); + }, GetAllConnectionStates(reply) => { let states = self.pool.all().into_iter().cloned().collect(); let _result = reply.send(states); diff --git a/comms/core/src/connectivity/requester.rs b/comms/core/src/connectivity/requester.rs index 44a550bca4..0dcb353d83 100644 --- a/comms/core/src/connectivity/requester.rs +++ b/comms/core/src/connectivity/requester.rs @@ -39,7 +39,11 @@ use super::{ manager::ConnectivityStatus, ConnectivitySelection, }; -use crate::{connection_manager::ConnectionManagerError, peer_manager::NodeId, PeerConnection}; +use crate::{ + connection_manager::ConnectionManagerError, + peer_manager::{NodeId, Peer}, + PeerConnection, +}; const LOG_TARGET: &str = "comms::connectivity::requester"; @@ -100,6 +104,7 @@ pub enum ConnectivityRequest { BanPeer(NodeId, Duration, String), AddPeerToAllowList(NodeId), RemovePeerFromAllowList(NodeId), + GetPeerStats(NodeId, oneshot::Sender>), } /// Handle to make requests and read events from the ConnectivityManager actor. @@ -204,6 +209,16 @@ impl ConnectivityRequester { reply_rx.await.map_err(|_| ConnectivityError::ActorResponseCancelled) } + /// Get the peer information from the peer, will return none if the peer is not found + pub async fn get_peer_info(&self, node_id: NodeId) -> Result, ConnectivityError> { + let (reply_tx, reply_rx) = oneshot::channel(); + self.sender + .send(ConnectivityRequest::GetPeerStats(node_id, reply_tx)) + .await + .map_err(|_| ConnectivityError::ActorDisconnected)?; + reply_rx.await.map_err(|_| ConnectivityError::ActorResponseCancelled) + } + /// Get the current [ConnectivityStatus](self::ConnectivityStatus). pub async fn get_connectivity_status(&mut self) -> Result { let (reply_tx, reply_rx) = oneshot::channel(); diff --git a/comms/core/src/test_utils/mocks/connectivity_manager.rs b/comms/core/src/test_utils/mocks/connectivity_manager.rs index 1bed761d3a..6dda3f9f0e 100644 --- a/comms/core/src/test_utils/mocks/connectivity_manager.rs +++ b/comms/core/src/test_utils/mocks/connectivity_manager.rs @@ -259,6 +259,9 @@ impl ConnectivityManagerMock { }) .await }, + GetPeerStats(_, _) => { + unimplemented!() + }, GetAllConnectionStates(_) => unimplemented!(), BanPeer(_, _, _) => {}, AddPeerToAllowList(_) => {},