trillium_async_std/
client.rs

1use crate::AsyncStdTransport;
2use async_std::net::TcpStream;
3use std::{
4    future::Future,
5    io::{Error, ErrorKind, Result},
6};
7use trillium_server_common::{
8    async_trait,
9    url::{Host, Url},
10    Connector, Transport,
11};
12
13/**
14configuration for the tcp Connector
15*/
16#[derive(Default, Debug, Clone, Copy)]
17pub struct ClientConfig {
18    /// disable [nagle's algorithm](https://en.wikipedia.org/wiki/Nagle%27s_algorithm)
19    pub nodelay: Option<bool>,
20
21    /// set a time to live for the tcp protocol
22    pub ttl: Option<u32>,
23}
24
25impl ClientConfig {
26    /// constructs a default ClientConfig
27    pub const fn new() -> Self {
28        Self {
29            nodelay: None,
30            ttl: None,
31        }
32    }
33
34    /// chainable setter to set default nodelay
35    pub const fn with_nodelay(mut self, nodelay: bool) -> Self {
36        self.nodelay = Some(nodelay);
37        self
38    }
39
40    /// chainable setter for ip ttl
41    pub const fn with_ttl(mut self, ttl: u32) -> Self {
42        self.ttl = Some(ttl);
43        self
44    }
45}
46
47#[async_trait]
48impl Connector for ClientConfig {
49    type Transport = AsyncStdTransport<TcpStream>;
50
51    async fn connect(&self, url: &Url) -> Result<Self::Transport> {
52        if url.scheme() != "http" {
53            return Err(Error::new(
54                ErrorKind::InvalidInput,
55                format!("unknown scheme {}", url.scheme()),
56            ));
57        }
58
59        let host = url
60            .host()
61            .ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("{url} missing host")))?;
62
63        let port = url
64            .port_or_known_default()
65            // this should be ok because we already checked that the scheme is http, which has a default port
66            .ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("{url} missing port")))?;
67
68        let mut tcp = match host {
69            Host::Domain(domain) => Self::Transport::connect((domain, port)).await?,
70            Host::Ipv4(ip) => Self::Transport::connect((ip, port)).await?,
71            Host::Ipv6(ip) => Self::Transport::connect((ip, port)).await?,
72        };
73
74        if let Some(nodelay) = self.nodelay {
75            tcp.set_nodelay(nodelay)?;
76        }
77
78        if let Some(ttl) = self.ttl {
79            tcp.set_ip_ttl(ttl)?;
80        }
81
82        Ok(tcp)
83    }
84
85    fn spawn<Fut: Future<Output = ()> + Send + 'static>(&self, fut: Fut) {
86        async_std::task::spawn(fut);
87    }
88}