1use crate::{SmolRuntime, SmolTransport};
2use async_net::TcpStream;
3use std::{
4 io::{Error, ErrorKind, Result},
5 net::SocketAddr,
6};
7use trillium_server_common::{Connector, Destination, Transport, url::Url};
8
9#[derive(Default, Debug, Clone, Copy)]
11pub struct ClientConfig {
12 pub nodelay: Option<bool>,
14
15 pub ttl: Option<u32>,
17}
18
19impl ClientConfig {
20 pub const fn new() -> Self {
22 Self {
23 nodelay: None,
24 ttl: None,
25 }
26 }
27
28 pub const fn with_nodelay(mut self, nodelay: bool) -> Self {
30 self.nodelay = Some(nodelay);
31 self
32 }
33
34 pub const fn with_ttl(mut self, ttl: u32) -> Self {
36 self.ttl = Some(ttl);
37 self
38 }
39}
40
41impl Connector for ClientConfig {
42 type Runtime = SmolRuntime;
43 type Transport = SmolTransport<TcpStream>;
44 type Udp = crate::SmolUdpSocket;
45
46 fn runtime(&self) -> Self::Runtime {
47 SmolRuntime::default()
48 }
49
50 async fn connect(&self, url: &Url) -> Result<Self::Transport> {
51 self.connect_to(Destination::from_url(url)?).await
52 }
53
54 async fn connect_to(&self, destination: Destination) -> Result<Self::Transport> {
55 if destination.secure() {
56 return Err(Error::new(
57 ErrorKind::InvalidInput,
58 "this connector does not support TLS",
59 ));
60 }
61
62 let addrs = destination.addrs();
63 let mut tcp = if addrs.is_empty() {
64 let host = destination.host().ok_or_else(|| {
65 Error::new(
66 ErrorKind::InvalidInput,
67 "destination has neither host nor addresses",
68 )
69 })?;
70 Self::Transport::connect((host, destination.port())).await?
71 } else {
72 Self::Transport::connect(addrs).await?
73 };
74
75 if let Some(nodelay) = self.nodelay {
76 tcp.set_nodelay(nodelay)?;
77 }
78
79 if let Some(ttl) = self.ttl {
80 tcp.set_ip_ttl(ttl)?;
81 }
82
83 Ok(tcp)
84 }
85
86 async fn resolve(&self, host: &str, port: u16) -> Result<Vec<SocketAddr>> {
87 async_net::resolve((host, port)).await
88 }
89}
90
91#[cfg(unix)]
102#[derive(Clone, Debug)]
103pub struct UnixClientConfig {
104 path: std::path::PathBuf,
105}
106
107#[cfg(unix)]
108impl UnixClientConfig {
109 pub fn new(path: impl Into<std::path::PathBuf>) -> Self {
111 Self { path: path.into() }
112 }
113
114 async fn dial(&self) -> Result<SmolTransport<async_net::unix::UnixStream>> {
115 SmolTransport::connect_unix(&self.path).await
116 }
117}
118
119#[cfg(unix)]
120impl Connector for UnixClientConfig {
121 type Runtime = SmolRuntime;
122 type Transport = SmolTransport<async_net::unix::UnixStream>;
123 type Udp = ();
124
125 async fn connect(&self, url: &Url) -> Result<Self::Transport> {
126 if url.scheme() == "https" {
127 return Err(Error::new(
128 ErrorKind::InvalidInput,
129 "this connector does not support TLS",
130 ));
131 }
132 self.dial().await
133 }
134
135 async fn connect_to(&self, destination: Destination) -> Result<Self::Transport> {
136 if destination.secure() {
137 return Err(Error::new(
138 ErrorKind::InvalidInput,
139 "this connector does not support TLS",
140 ));
141 }
142 self.dial().await
143 }
144
145 fn runtime(&self) -> Self::Runtime {
146 SmolRuntime::default()
147 }
148
149 async fn resolve(&self, _host: &str, _port: u16) -> Result<Vec<SocketAddr>> {
150 Ok(vec![])
151 }
152}