1use std::{fmt::Debug, io};
2
3use futures_util::{AsyncRead, AsyncWrite};
4
5use crate::TlsStream;
6
7#[derive(Clone)]
8enum TlsConnectorInner {
9 #[cfg(feature = "native-tls")]
10 NativeTls(crate::native::TlsConnector),
11 #[cfg(feature = "rustls")]
12 Rustls(futures_rustls::TlsConnector),
13 #[cfg(feature = "py-dynamic-openssl")]
14 PyDynamicOpenSsl(crate::py_ossl::TlsConnector),
15 #[cfg(not(any(
16 feature = "native-tls",
17 feature = "rustls",
18 feature = "py-dynamic-openssl"
19 )))]
20 None(std::convert::Infallible),
21}
22
23impl Debug for TlsConnectorInner {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 #[cfg(feature = "native-tls")]
27 Self::NativeTls(_) => f.debug_tuple("NativeTls").finish(),
28 #[cfg(feature = "rustls")]
29 Self::Rustls(_) => f.debug_tuple("Rustls").finish(),
30 #[cfg(feature = "py-dynamic-openssl")]
31 Self::PyDynamicOpenSsl(_) => f.debug_tuple("PyDynamicOpenSsl").finish(),
32 #[cfg(not(any(
33 feature = "native-tls",
34 feature = "rustls",
35 feature = "py-dynamic-openssl"
36 )))]
37 Self::None(f) => match *f {},
38 }
39 }
40}
41
42#[derive(Debug, Clone)]
45pub struct TlsConnector(TlsConnectorInner);
46
47#[cfg(feature = "native-tls")]
48impl From<native_tls::TlsConnector> for TlsConnector {
49 fn from(value: native_tls::TlsConnector) -> Self {
50 Self(TlsConnectorInner::NativeTls(value.into()))
51 }
52}
53
54#[cfg(feature = "rustls")]
55impl From<std::sync::Arc<rustls::ClientConfig>> for TlsConnector {
56 fn from(value: std::sync::Arc<rustls::ClientConfig>) -> Self {
57 Self(TlsConnectorInner::Rustls(value.into()))
58 }
59}
60
61#[cfg(feature = "py-dynamic-openssl")]
62#[doc(hidden)]
63impl From<compio_py_dynamic_openssl::SSLContext> for TlsConnector {
64 fn from(value: compio_py_dynamic_openssl::SSLContext) -> Self {
65 Self(TlsConnectorInner::PyDynamicOpenSsl(value.into()))
66 }
67}
68
69impl TlsConnector {
70 pub async fn connect<S>(&self, domain: &str, stream: S) -> io::Result<TlsStream<S>>
83 where
84 S: AsyncRead + AsyncWrite + Unpin,
85 {
86 match &self.0 {
87 #[cfg(feature = "native-tls")]
88 TlsConnectorInner::NativeTls(c) => {
89 let client = c.connect(domain, stream).await?;
90 Ok(TlsStream::from(client))
91 }
92 #[cfg(feature = "rustls")]
93 TlsConnectorInner::Rustls(c) => {
94 let client = c
95 .connect(
96 domain.to_string().try_into().map_err(io::Error::other)?,
97 stream,
98 )
99 .await?;
100 Ok(TlsStream::from(client))
101 }
102 #[cfg(feature = "py-dynamic-openssl")]
103 TlsConnectorInner::PyDynamicOpenSsl(c) => {
104 let client = c.connect(domain, stream).await?;
105 Ok(TlsStream::from(client))
106 }
107 #[cfg(not(any(
108 feature = "native-tls",
109 feature = "rustls",
110 feature = "py-dynamic-openssl"
111 )))]
112 TlsConnectorInner::None(f) => match *f {},
113 }
114 }
115}
116
117#[derive(Clone)]
118enum TlsAcceptorInner {
119 #[cfg(feature = "native-tls")]
120 NativeTls(crate::native::TlsAcceptor),
121 #[cfg(feature = "rustls")]
122 Rustls(futures_rustls::TlsAcceptor),
123 #[cfg(feature = "py-dynamic-openssl")]
124 PyDynamicOpenSsl(crate::py_ossl::TlsAcceptor),
125 #[cfg(not(any(
126 feature = "native-tls",
127 feature = "rustls",
128 feature = "py-dynamic-openssl"
129 )))]
130 None(std::convert::Infallible),
131}
132
133#[derive(Clone)]
139pub struct TlsAcceptor(TlsAcceptorInner);
140
141#[cfg(feature = "native-tls")]
142impl From<native_tls::TlsAcceptor> for TlsAcceptor {
143 fn from(value: native_tls::TlsAcceptor) -> Self {
144 Self(TlsAcceptorInner::NativeTls(value.into()))
145 }
146}
147
148#[cfg(feature = "rustls")]
149impl From<std::sync::Arc<rustls::ServerConfig>> for TlsAcceptor {
150 fn from(value: std::sync::Arc<rustls::ServerConfig>) -> Self {
151 Self(TlsAcceptorInner::Rustls(value.into()))
152 }
153}
154
155#[cfg(feature = "py-dynamic-openssl")]
156impl From<compio_py_dynamic_openssl::SSLContext> for TlsAcceptor {
157 fn from(value: compio_py_dynamic_openssl::SSLContext) -> Self {
158 Self(TlsAcceptorInner::PyDynamicOpenSsl(value.into()))
159 }
160}
161
162impl TlsAcceptor {
163 pub async fn accept<S>(&self, stream: S) -> io::Result<TlsStream<S>>
174 where
175 S: AsyncRead + AsyncWrite + Unpin,
176 {
177 match &self.0 {
178 #[cfg(feature = "native-tls")]
179 TlsAcceptorInner::NativeTls(c) => {
180 let server = c.accept(stream).await?;
181 Ok(TlsStream::from(server))
182 }
183 #[cfg(feature = "rustls")]
184 TlsAcceptorInner::Rustls(c) => {
185 let server = c.accept(stream).await?;
186 Ok(TlsStream::from(server))
187 }
188 #[cfg(feature = "py-dynamic-openssl")]
189 TlsAcceptorInner::PyDynamicOpenSsl(a) => {
190 let server = a.accept(stream).await?;
191 Ok(TlsStream::from(server))
192 }
193 #[cfg(not(any(
194 feature = "native-tls",
195 feature = "rustls",
196 feature = "py-dynamic-openssl"
197 )))]
198 TlsAcceptorInner::None(f) => match *f {},
199 }
200 }
201}