1use crate::TokioTransport;
2use async_compat::Compat;
3use std::{
4 future::Future,
5 io::{Error, ErrorKind, Result},
6 time::Duration,
7};
8use tokio::net::TcpStream;
9use trillium_server_common::{
10 async_trait,
11 url::{Host, Url},
12 Connector, Transport,
13};
14
15#[derive(Default, Debug, Clone, Copy)]
19pub struct ClientConfig {
20 pub nodelay: Option<bool>,
23
24 pub ttl: Option<u32>,
26
27 pub linger: Option<Option<Duration>>,
30}
31
32impl ClientConfig {
33 pub const fn new() -> Self {
35 Self {
36 nodelay: None,
37 ttl: None,
38 linger: None,
39 }
40 }
41
42 pub const fn with_nodelay(mut self, nodelay: bool) -> Self {
44 self.nodelay = Some(nodelay);
45 self
46 }
47
48 pub const fn with_ttl(mut self, ttl: u32) -> Self {
50 self.ttl = Some(ttl);
51 self
52 }
53
54 pub const fn with_linger(mut self, linger: Option<Duration>) -> Self {
56 self.linger = Some(linger);
57 self
58 }
59}
60
61#[async_trait]
62impl Connector for ClientConfig {
63 type Transport = TokioTransport<Compat<TcpStream>>;
64
65 async fn connect(&self, url: &Url) -> Result<Self::Transport> {
66 if url.scheme() != "http" {
67 return Err(Error::new(
68 ErrorKind::InvalidInput,
69 format!("unknown scheme {}", url.scheme()),
70 ));
71 }
72
73 let host = url
74 .host()
75 .ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("{url} missing host")))?;
76
77 let port = url
78 .port_or_known_default()
79 .ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("{url} missing port")))?;
81
82 let mut tcp = match host {
83 Host::Domain(domain) => Self::Transport::connect((domain, port)).await?,
84 Host::Ipv4(ip) => Self::Transport::connect((ip, port)).await?,
85 Host::Ipv6(ip) => Self::Transport::connect((ip, port)).await?,
86 };
87
88 if let Some(nodelay) = self.nodelay {
89 tcp.set_nodelay(nodelay)?;
90 }
91
92 if let Some(ttl) = self.ttl {
93 tcp.set_ip_ttl(ttl)?;
94 }
95
96 if let Some(dur) = self.linger {
97 tcp.set_linger(dur)?;
98 }
99
100 Ok(tcp)
101 }
102
103 fn spawn<Fut: Future<Output = ()> + Send + 'static>(&self, fut: Fut) {
104 tokio::task::spawn(fut);
105 }
106}