areq_smol/connect.rs
1use {
2 areq::{Address, Error, HandshakeWith, Session},
3 async_net::TcpStream,
4 url::Host,
5};
6
7/// Extension trait to connect a [TCP stream](TcpStream).
8///
9/// If a connection is successful, it returns an HTTP client and a future
10/// that needs to be polled in background while the client sends requests
11/// and receives responses. To do this, you can spawn the task in an
12/// [executor] or poll it concurrently with the client, for example,
13/// using [`try_zip`].
14///
15/// [executor]: https://docs.rs/async-executor/latest/async_executor/struct.Executor.html
16/// [`try_zip`]: https://docs.rs/futures-lite/latest/futures_lite/future/fn.try_zip.html
17///
18/// # Example
19///
20/// ```
21/// use {
22/// areq_smol::{http::Uri, http1::Http1, prelude::*},
23/// async_executor::Executor,
24/// std::io::Error,
25/// };
26///
27/// async fn get(ex: &Executor<'_>) -> Result<String, Error> {
28/// let uri = Uri::from_static("http://127.0.0.1:3001/hello");
29///
30/// // Establish a connection to the address
31/// let (mut client, conn) = Http1::default().connect(&uri).await?;
32///
33/// // Spawn the task in background
34/// ex.spawn(conn).detach();
35///
36/// // Now you can work with the client
37/// // The background task will complete once the client is dropped
38/// client.get(uri, ()).await?.text().await
39/// }
40/// ```
41///
42/// You can also use an extension method [`handle`](crate::smol::Handle::handle),
43/// which takes an async closure, calls it on the client, and polls the task
44/// in background for the entire duration of the closure execution.
45///
46/// ```
47/// use {
48/// areq_smol::{http::Uri, http1::Http1, prelude::*},
49/// std::io::Error,
50/// };
51///
52/// async fn get() -> Result<String, Error> {
53/// let uri = Uri::from_static("http://127.0.0.1:3001/hello");
54///
55/// Http1::default()
56/// .connect(&uri)
57/// .await?
58/// .handle(async |client| client.get(uri, ()).await?.text().await)
59/// .await
60/// }
61/// ```
62pub trait Connect<A, B>: HandshakeWith<TcpStream, B> {
63 /// Connects to the given address.
64 async fn connect(self, addr: A) -> Result<(Self::Client, Self::Task), Error>;
65}
66
67impl<H, A, B> Connect<A, B> for H
68where
69 A: TryInto<Address, Error: Into<Error>>,
70 H: HandshakeWith<TcpStream, B>,
71{
72 #[inline]
73 async fn connect(self, addr: A) -> Result<(Self::Client, Self::Task), Error> {
74 let addr = addr.try_into().map_err(A::Error::into)?;
75 let io = match &addr.host {
76 Host::Domain(d) => TcpStream::connect((d.as_str(), addr.port)).await?,
77 Host::Ipv4(ip4) => TcpStream::connect((*ip4, addr.port)).await?,
78 Host::Ipv6(ip6) => TcpStream::connect((*ip6, addr.port)).await?,
79 };
80
81 let se = Session { addr, io };
82 self.handshake(se).await
83 }
84}