1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use std::error::Error;
use futures::future::BoxFuture;
use url::Url;
use crate::Transport;
/// Knows how to establish a transport to a remote endpoint.
///
/// Implementations provide both *where* to connect ([`Dialer::url`]) and
/// *how* to connect ([`Dialer::connect`]). A single `Dialer` instance
/// can be shared across multiple connectors (via `Arc`).
pub trait Dialer: Send + Sync + 'static {
/// The error produced when the dialer permanently fails.
///
/// Implementations which never produce permanent failures can use
/// [`std::convert::Infallible`].
type Error: Error + Send + Sync + 'static;
/// The URL identifying the remote endpoint.
///
/// This is used for logging and debugging
fn url(&self) -> Url;
/// Establish a new transport to the remote endpoint.
///
/// Called each time the dialer needs a connection — both on the
/// initial dial and on each reconnection attempt after backoff.
/// Return [`DialError::TransientFailure`] to retry, or
/// [`DialError::PermanentFailure`] to stop without retrying.
fn connect(&self) -> BoxFuture<'static, Result<Transport, DialError<Self::Error>>>;
}
/// An error returned by [`Dialer::connect`].
///
/// Transient failures are retried according to the dialer's backoff
/// configuration. Permanent failures stop the dialer immediately and are
/// returned by [`DialerHandle::established`](crate::DialerHandle::established).
#[derive(Debug)]
pub enum DialError<E> {
/// The dialer cannot recover from this error by retrying.
PermanentFailure(E),
/// Establishing the transport failed, but a later attempt may succeed.
TransientFailure(Box<dyn Error + Send + Sync + 'static>),
}
impl<E> DialError<E> {
/// Construct a transient failure from any thread-safe error.
pub fn transient(error: impl Error + Send + Sync + 'static) -> Self {
Self::TransientFailure(Box::new(error))
}
}
impl<E: std::fmt::Display> std::fmt::Display for DialError<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::PermanentFailure(error) => write!(f, "permanent dial failure: {error}"),
Self::TransientFailure(error) => write!(f, "transient dial failure: {error}"),
}
}
}
impl<E: Error + 'static> Error for DialError<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::PermanentFailure(error) => Some(error),
Self::TransientFailure(error) => Some(error.as_ref()),
}
}
}