use std::time::Duration;
use nym_client_core::client::base_client::ClientState;
use nym_socks5_client_core::config::Socks5;
use nym_sphinx::addressing::clients::Recipient;
use nym_task::connections::LaneQueueLengths;
use nym_task::ShutdownTracker;
use tokio::sync::RwLockReadGuard;
use nym_topology::{NymRouteProvider, NymTopology, NymTopologyError};
use crate::mixnet::client::MixnetClientBuilder;
use crate::Result;
pub struct Socks5MixnetClient {
pub(crate) nym_address: Recipient,
pub(crate) client_state: ClientState,
pub(crate) task_handle: ShutdownTracker,
pub(crate) socks5_config: Socks5,
}
impl Socks5MixnetClient {
pub async fn connect_new<S: Into<String>>(provider_mix_address: S) -> Result<Self> {
MixnetClientBuilder::new_ephemeral()
.socks5_config(Socks5::new(provider_mix_address))
.build()?
.connect_to_mixnet_via_socks5()
.await
}
pub fn nym_address(&self) -> &Recipient {
&self.nym_address
}
pub fn socks5_url(&self) -> String {
format!("socks5h://{}", self.socks5_config.bind_address)
}
pub fn shared_lane_queue_lengths(&self) -> LaneQueueLengths {
self.client_state.shared_lane_queue_lengths.clone()
}
pub async fn manually_overwrite_topology(&self, new_topology: NymTopology) {
self.client_state
.topology_accessor
.manually_change_topology(new_topology)
.await
}
pub fn restore_automatic_topology_refreshing(&self) {
self.client_state.topology_accessor.release_manual_control()
}
pub async fn disconnect(self) {
self.task_handle.shutdown().await;
}
async fn read_current_route_provider(&self) -> Option<RwLockReadGuard<'_, NymRouteProvider>> {
self.client_state
.topology_accessor
.current_route_provider()
.await
}
pub async fn wait_for_topology(&self, timeout: Duration) -> Result<(), NymTopologyError> {
let deadline = tokio::time::Instant::now() + timeout;
loop {
if self.read_current_route_provider().await.is_some() {
return Ok(());
}
if tokio::time::Instant::now() >= deadline {
return Err(NymTopologyError::EmptyNetworkTopology);
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
}
}