monoio_transports/connectors/mod.rs
1//! Defines core traits and types for creating and composing network connectors.
2//!
3//! This module provides the following key components:
4//!
5//! - The [`Connector`] trait for establishing connections
6//! - The [`ConnectorExt`] trait for adding timeout functionality
7//! - The [`TransportConnMetadata`] trait for retrieving connection metadata
8mod l4_connector;
9#[cfg(feature = "hyper")]
10pub mod pollio;
11mod tls_connector;
12
13use std::{future::Future, time::Duration};
14
15pub use l4_connector::*;
16pub use tls_connector::*;
17
18/// The [`Connector`] trait defines an interface for establishing connections.
19/// This trait is designed to be composable, allowing for the creation of modular
20/// and stackable connectors. Each connector in the stack can add its own layer
21/// of functionality, such as TCP connection, Unix Domain Socket (UDS) connection,
22/// TLS encryption, or HTTP protocol handling.
23///
24/// # Type Parameters
25///
26/// - `K`: The key type used to identify the connection target.
27///
28/// # Associated Types
29///
30/// - `Connection`: The type of the established connection.
31/// - `Error`: The error type that may occur during connection.
32///
33/// # Examples
34///
35/// Here are examples of how to stack different connectors:
36///
37/// ## HTTP over Unix Domain Socket
38///
39/// ```rust
40/// use http::request;
41/// use monoio_http::{common::body::HttpBody, h1::payload::Payload};
42/// use monoio_transports::{
43/// connectors::{Connector, UnixConnector},
44/// http::HttpConnector,
45/// };
46///
47/// #[monoio::main]
48/// async fn main() -> Result<(), monoio_transports::TransportError> {
49/// let connector: HttpConnector<UnixConnector, _, _> = HttpConnector::default();
50/// let mut conn = connector.connect("./examples/uds.sock").await?;
51///
52/// let req = request::Builder::new()
53/// .uri("/get")
54/// .header("Host", "test")
55/// .body(HttpBody::H1(Payload::None))
56/// .unwrap();
57///
58/// let (res, _) = conn.send_request(req).await;
59/// let resp = res?;
60/// assert_eq!(200, resp.status());
61///
62/// Ok(())
63/// }
64/// ```
65///
66/// ## HTTPS over TCP
67///
68/// ```rust
69/// use monoio_transports::{
70/// connectors::{Connector, TcpConnector, TcpTlsAddr, TlsConnector},
71/// http::HttpConnector,
72/// };
73///
74/// #[monoio::main]
75/// async fn main() -> Result<(), monoio_transports::TransportError> {
76/// let connector: HttpConnector<TlsConnector<TcpConnector>, _, _> =
77/// HttpConnector::build_tls_http2_only();
78///
79/// let addr: TcpTlsAddr = "https://example.com".try_into()?;
80/// let conn = connector.connect(addr).await?;
81///
82/// // Use the connection...
83///
84/// Ok(())
85/// }
86/// ```
87///
88/// These examples demonstrate how connectors can be stacked to create
89/// different connection types (HTTP over UDS, HTTPS over TCP) using the
90/// same `Connector` trait.
91pub trait Connector<K> {
92 type Connection;
93 type Error;
94
95 /// Attempts to establish a connection.
96 ///
97 /// # Parameters
98 ///
99 /// - `key`: The key identifying the connection target.
100 ///
101 /// # Returns
102 ///
103 /// A `Future` that resolves to a `Result` containing either the established
104 /// connection or an error.
105 fn connect(&self, key: K) -> impl Future<Output = Result<Self::Connection, Self::Error>>;
106}
107
108/// Extends the `Connector` trait with timeout functionality.
109///
110/// This trait is automatically implemented for all types that implement `Connector<K>`.
111pub trait ConnectorExt<K>: Connector<K> {
112 fn connect_with_timeout(
113 &self,
114 key: K,
115 timeout: Duration,
116 ) -> impl Future<Output = Result<Result<Self::Connection, Self::Error>, monoio::time::error::Elapsed>>;
117}
118
119impl<K, T: Connector<K>> ConnectorExt<K> for T {
120 #[inline]
121 fn connect_with_timeout(
122 &self,
123 key: K,
124 timeout: Duration,
125 ) -> impl Future<Output = Result<Result<Self::Connection, Self::Error>, monoio::time::error::Elapsed>>
126 {
127 monoio::time::timeout(timeout, self.connect(key))
128 }
129}
130
131/// Provides additional information about the connection.
132///
133/// This trait is useful for transport connectors like TLS, TCP, UDS, etc.
134pub trait TransportConnMetadata {
135 /// The type of metadata associated with this connection.
136 type Metadata;
137
138 /// Retrieves the metadata from the connection.
139 ///
140 /// # Returns
141 ///
142 /// An instance of the associated type `Metadata`.
143 fn get_conn_metadata(&self) -> Self::Metadata;
144}
145
146/// Represents the Application-Layer Protocol Negotiation (ALPN) protocol.
147#[derive(Default, Copy, Clone)]
148pub enum Alpn {
149 /// HTTP/2 protocol
150 HTTP2,
151 /// HTTP/1.1 protocol
152 HTTP11,
153 /// No ALPN protocol specified (default)
154 #[default]
155 None,
156}
157
158/// Holds metadata for a transport connection.
159///
160/// Currently only holds the ALPN protocol information.
161#[derive(Default, Copy, Clone)]
162pub struct TransportConnMeta {
163 alpn: Alpn,
164}
165
166impl TransportConnMeta {
167 /// Sets the ALPN protocol based on the provided byte vector.
168 ///
169 /// # Arguments
170 ///
171 /// * `alpn` - An optional vector of bytes representing the ALPN protocol.
172 ///
173 /// # Notes
174 ///
175 /// Sets `Alpn::HTTP2` if the vector contains "h2", otherwise sets `Alpn::None`.
176 pub fn set_alpn(&mut self, alpn: Option<Vec<u8>>) {
177 self.alpn = match alpn {
178 Some(p) if p == b"h2" => Alpn::HTTP2,
179 _ => Alpn::None,
180 }
181 }
182
183 /// Checks if the ALPN protocol is set to HTTP/2.
184 ///
185 /// # Returns
186 ///
187 /// `true` if the ALPN protocol is HTTP/2, `false` otherwise.
188 pub fn is_alpn_h2(&self) -> bool {
189 matches!(self.alpn, Alpn::HTTP2)
190 }
191}