1use crate::{SmolRuntime, SmolTransport};
2use async_net::TcpStream;
3use std::{
4 io::{Error, ErrorKind, Result},
5 net::SocketAddr,
6};
7use trillium_server_common::{
8 Connector, Transport,
9 url::{Host, Url},
10};
11
12#[derive(Default, Debug, Clone, Copy)]
14pub struct ClientConfig {
15 pub nodelay: Option<bool>,
17
18 pub ttl: Option<u32>,
20}
21
22impl ClientConfig {
23 pub const fn new() -> Self {
25 Self {
26 nodelay: None,
27 ttl: None,
28 }
29 }
30
31 pub const fn with_nodelay(mut self, nodelay: bool) -> Self {
33 self.nodelay = Some(nodelay);
34 self
35 }
36
37 pub const fn with_ttl(mut self, ttl: u32) -> Self {
39 self.ttl = Some(ttl);
40 self
41 }
42}
43
44impl Connector for ClientConfig {
45 type Runtime = SmolRuntime;
46 type Transport = SmolTransport<TcpStream>;
47 type Udp = crate::SmolUdpSocket;
48
49 fn runtime(&self) -> Self::Runtime {
50 SmolRuntime::default()
51 }
52
53 async fn connect(&self, url: &Url) -> Result<Self::Transport> {
54 if url.scheme() != "http" {
55 return Err(Error::new(
56 ErrorKind::InvalidInput,
57 format!("unknown scheme {}", url.scheme()),
58 ));
59 }
60
61 let port = url
62 .port_or_known_default()
63 .ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("{url} missing port")))?;
66
67 let host = url
68 .host()
69 .ok_or_else(|| Error::new(ErrorKind::InvalidInput, format!("{url} missing host")))?;
70
71 let mut tcp = match host {
72 Host::Domain(domain) => Self::Transport::connect((domain, port)).await?,
73 Host::Ipv4(ip) => Self::Transport::connect((ip, port)).await?,
74 Host::Ipv6(ip) => Self::Transport::connect((ip, port)).await?,
75 };
76
77 if let Some(nodelay) = self.nodelay {
78 tcp.set_nodelay(nodelay)?;
79 }
80
81 if let Some(ttl) = self.ttl {
82 tcp.set_ip_ttl(ttl)?;
83 }
84
85 Ok(tcp)
86 }
87
88 async fn resolve(&self, host: &str, port: u16) -> Result<Vec<SocketAddr>> {
89 async_net::resolve((host, port)).await
90 }
91}
92
93#[cfg(unix)]
94impl Connector for SmolTransport<async_net::unix::UnixStream> {
95 type Runtime = SmolRuntime;
96 type Transport = Self;
97 type Udp = crate::SmolUdpSocket;
98
99 async fn connect(&self, _url: &Url) -> Result<Self::Transport> {
100 Ok(self.clone())
101 }
102
103 fn runtime(&self) -> Self::Runtime {
104 SmolRuntime::default()
105 }
106
107 async fn resolve(&self, _host: &str, _port: u16) -> Result<Vec<SocketAddr>> {
108 Ok(vec![])
109 }
110}