distant_net/client/
builder.rs

1mod tcp;
2pub use tcp::*;
3
4#[cfg(unix)]
5mod unix;
6
7#[cfg(unix)]
8pub use unix::*;
9
10#[cfg(windows)]
11mod windows;
12
13use std::time::Duration;
14use std::{convert, io};
15
16use async_trait::async_trait;
17use distant_auth::AuthHandler;
18#[cfg(windows)]
19pub use windows::*;
20
21use super::ClientConfig;
22use crate::client::{Client, UntypedClient};
23use crate::common::{Connection, Transport, Version};
24
25/// Interface that performs the connection to produce a [`Transport`] for use by the [`Client`].
26#[async_trait]
27pub trait Connector {
28    /// Type of transport produced by the connection.
29    type Transport: Transport + 'static;
30
31    async fn connect(self) -> io::Result<Self::Transport>;
32}
33
34#[async_trait]
35impl<T: Transport + 'static> Connector for T {
36    type Transport = T;
37
38    async fn connect(self) -> io::Result<Self::Transport> {
39        Ok(self)
40    }
41}
42
43/// Builder for a [`Client`] or [`UntypedClient`].
44pub struct ClientBuilder<H, C> {
45    auth_handler: H,
46    connector: C,
47    config: ClientConfig,
48    connect_timeout: Option<Duration>,
49    version: Version,
50}
51
52impl<H, C> ClientBuilder<H, C> {
53    /// Configure the authentication handler to use when connecting to a server.
54    pub fn auth_handler<U>(self, auth_handler: U) -> ClientBuilder<U, C> {
55        ClientBuilder {
56            auth_handler,
57            config: self.config,
58            connector: self.connector,
59            connect_timeout: self.connect_timeout,
60            version: self.version,
61        }
62    }
63
64    /// Configure the client-local configuration details.
65    pub fn config(self, config: ClientConfig) -> Self {
66        Self {
67            auth_handler: self.auth_handler,
68            config,
69            connector: self.connector,
70            connect_timeout: self.connect_timeout,
71            version: self.version,
72        }
73    }
74
75    /// Configure the connector to use to facilitate connecting to a server.
76    pub fn connector<U>(self, connector: U) -> ClientBuilder<H, U> {
77        ClientBuilder {
78            auth_handler: self.auth_handler,
79            config: self.config,
80            connector,
81            connect_timeout: self.connect_timeout,
82            version: self.version,
83        }
84    }
85
86    /// Configure a maximum duration to wait for a connection to a server to complete.
87    pub fn connect_timeout(self, connect_timeout: impl Into<Option<Duration>>) -> Self {
88        Self {
89            auth_handler: self.auth_handler,
90            config: self.config,
91            connector: self.connector,
92            connect_timeout: connect_timeout.into(),
93            version: self.version,
94        }
95    }
96
97    /// Configure the version of the client.
98    pub fn version(self, version: Version) -> Self {
99        Self {
100            auth_handler: self.auth_handler,
101            config: self.config,
102            connector: self.connector,
103            connect_timeout: self.connect_timeout,
104            version,
105        }
106    }
107}
108
109impl ClientBuilder<(), ()> {
110    pub fn new() -> Self {
111        Self {
112            auth_handler: (),
113            config: Default::default(),
114            connector: (),
115            connect_timeout: None,
116            version: Default::default(),
117        }
118    }
119}
120
121impl Default for ClientBuilder<(), ()> {
122    fn default() -> Self {
123        Self::new()
124    }
125}
126
127impl<H, C> ClientBuilder<H, C>
128where
129    H: AuthHandler + Send,
130    C: Connector,
131{
132    /// Establishes a connection with a remote server using the configured [`Transport`]
133    /// and other settings, returning a new [`UntypedClient`] instance once the connection
134    /// is fully established and authenticated.
135    pub async fn connect_untyped(self) -> io::Result<UntypedClient> {
136        let auth_handler = self.auth_handler;
137        let config = self.config;
138        let connect_timeout = self.connect_timeout;
139        let version = self.version;
140
141        let f = async move {
142            let transport = match connect_timeout {
143                Some(duration) => tokio::time::timeout(duration, self.connector.connect())
144                    .await
145                    .map_err(|x| io::Error::new(io::ErrorKind::TimedOut, x))
146                    .and_then(convert::identity)?,
147                None => self.connector.connect().await?,
148            };
149            let connection = Connection::client(transport, auth_handler, version).await?;
150            Ok(UntypedClient::spawn(connection, config))
151        };
152
153        match connect_timeout {
154            Some(duration) => tokio::time::timeout(duration, f)
155                .await
156                .map_err(|x| io::Error::new(io::ErrorKind::TimedOut, x))
157                .and_then(convert::identity),
158            None => f.await,
159        }
160    }
161
162    /// Establishes a connection with a remote server using the configured [`Transport`] and other
163    /// settings, returning a new [`Client`] instance once the connection is fully established and
164    /// authenticated.
165    pub async fn connect<T, U>(self) -> io::Result<Client<T, U>> {
166        Ok(self.connect_untyped().await?.into_typed_client())
167    }
168}