mod tcp; pub use tcp::*; #[cfg(unix)] mod unix; #[cfg(unix)] pub use unix::*; #[cfg(windows)] mod windows; #[cfg(windows)] pub use windows::*; use crate::client::{Client, ReconnectStrategy, UntypedClient}; use crate::common::{authentication::AuthHandler, Connection, Transport}; use async_trait::async_trait; use std::{convert, io, time::Duration}; /// Interface that performs the connection to produce a [`Transport`] for use by the [`Client`]. #[async_trait] pub trait Connector { /// Type of transport produced by the connection. type Transport: Transport + 'static; async fn connect(self) -> io::Result; } #[async_trait] impl Connector for T { type Transport = T; async fn connect(self) -> io::Result { Ok(self) } } /// Builder for a [`Client`] or [`UntypedClient`]. pub struct ClientBuilder { auth_handler: H, connector: C, reconnect_strategy: ReconnectStrategy, timeout: Option, } impl ClientBuilder { pub fn auth_handler(self, auth_handler: U) -> ClientBuilder { ClientBuilder { auth_handler, connector: self.connector, reconnect_strategy: self.reconnect_strategy, timeout: self.timeout, } } pub fn connector(self, connector: U) -> ClientBuilder { ClientBuilder { auth_handler: self.auth_handler, connector, reconnect_strategy: self.reconnect_strategy, timeout: self.timeout, } } pub fn reconnect_strategy(self, reconnect_strategy: ReconnectStrategy) -> ClientBuilder { ClientBuilder { auth_handler: self.auth_handler, connector: self.connector, reconnect_strategy, timeout: self.timeout, } } pub fn timeout(self, timeout: impl Into>) -> Self { Self { auth_handler: self.auth_handler, connector: self.connector, reconnect_strategy: self.reconnect_strategy, timeout: timeout.into(), } } } impl ClientBuilder<(), ()> { pub fn new() -> Self { Self { auth_handler: (), reconnect_strategy: ReconnectStrategy::default(), connector: (), timeout: None, } } } impl Default for ClientBuilder<(), ()> { fn default() -> Self { Self::new() } } impl ClientBuilder where H: AuthHandler + Send, C: Connector, { /// Establishes a connection with a remote server using the configured [`Transport`] /// and other settings, returning a new [`UntypedClient`] instance once the connection /// is fully established and authenticated. pub async fn connect_untyped(self) -> io::Result { let auth_handler = self.auth_handler; let retry_strategy = self.reconnect_strategy; let timeout = self.timeout; let f = async move { let transport = match timeout { Some(duration) => tokio::time::timeout(duration, self.connector.connect()) .await .map_err(|x| io::Error::new(io::ErrorKind::TimedOut, x)) .and_then(convert::identity)?, None => self.connector.connect().await?, }; let connection = Connection::client(transport, auth_handler).await?; Ok(UntypedClient::spawn(connection, retry_strategy)) }; match timeout { Some(duration) => tokio::time::timeout(duration, f) .await .map_err(|x| io::Error::new(io::ErrorKind::TimedOut, x)) .and_then(convert::identity), None => f.await, } } /// Establishes a connection with a remote server using the configured [`Transport`] and other /// settings, returning a new [`Client`] instance once the connection is fully established and /// authenticated. pub async fn connect(self) -> io::Result> { Ok(self.connect_untyped().await?.into_typed_client()) } }