xitca_server/net/
mod.rs

1use std::{io, sync::Arc};
2
3use xitca_io::net::{Stream, TcpListener};
4
5#[cfg(unix)]
6use xitca_io::net::UnixListener;
7
8use tracing::info;
9#[cfg(feature = "quic")]
10use xitca_io::net::{QuicListener, QuicListenerBuilder};
11
12/// trait for defining how socket listener would accept remote connection and omit connection stream asynchronously
13///
14/// listener must be thread safe type for parallel accessing by multiple worker threads.
15///
16/// # Examples
17/// ```rust
18/// use std::io;
19///
20/// use xitca_io::net::Stream;
21/// use xitca_server::net::{IntoListener, Listen};
22/// use xitca_service::fn_service;
23///
24/// // arbitrary socket type
25/// struct MySocket;
26///
27/// impl Listen for MySocket {
28///     async fn accept(&self) -> io::Result<Stream> {
29///         todo!("defining how my socket would accept remote connection in the type of Stream")
30///     }
31/// }
32///
33/// // arbitrary builder type for socket. allow for additional logic when constructing socket type
34/// struct MySocketBuilder;
35///
36/// impl IntoListener for MySocketBuilder {
37///     type Listener = MySocket;
38///
39///     fn into_listener(self) -> io::Result<Self::Listener> {
40///         // transform socket builder to the socket runner type.
41///         // this function is called from inside xitca-server and it's possible to tap into it's internal from here.
42///         // e.g: accessing the thread local storage or the async runtime(tokio)'s context.
43///         Ok(MySocket)
44///     }
45/// }
46///
47/// // service function receive connection stream from MySocket's Listen::accept method
48/// let service = fn_service(async |stream: Stream| {
49///     Ok::<_, io::Error>(())
50/// });
51///
52/// // start a server with socket builder where My socket would be instantiated and it's accepting logic would start and
53/// // run the service function when successfully accepted remote connection.
54/// let _ = xitca_server::Builder::new().listen("my_socket_service", MySocketBuilder, service);
55/// ```
56pub trait Listen: Send + Sync {
57    fn accept(&self) -> impl Future<Output = io::Result<Stream>> + Send;
58}
59
60mod _seal {
61    use core::{future::Future, pin::Pin};
62
63    use super::*;
64
65    type BoxFuture<'f, T> = Pin<Box<dyn Future<Output = T> + Send + 'f>>;
66
67    #[doc(hidden)]
68    /// dynamic compat trait for [Listen]
69    pub trait ListenDyn: Send + Sync {
70        fn accept_dyn(&self) -> BoxFuture<io::Result<Stream>>;
71    }
72
73    impl<S> ListenDyn for S
74    where
75        S: Listen,
76    {
77        #[inline]
78        fn accept_dyn(&self) -> BoxFuture<io::Result<Stream>> {
79            Box::pin(Listen::accept(self))
80        }
81    }
82}
83
84pub(crate) type ListenerDyn = Arc<dyn _seal::ListenDyn>;
85
86impl Listen for TcpListener {
87    async fn accept(&self) -> io::Result<Stream> {
88        let (stream, addr) = self.accept().await?;
89        let stream = stream.into_std()?;
90        Ok(Stream::Tcp(stream, addr))
91    }
92}
93
94#[cfg(unix)]
95impl Listen for UnixListener {
96    async fn accept(&self) -> io::Result<Stream> {
97        let (stream, _) = self.accept().await?;
98        let stream = stream.into_std()?;
99        let addr = stream.peer_addr()?;
100        Ok(Stream::Unix(stream, addr))
101    }
102}
103
104#[cfg(feature = "quic")]
105impl Listen for QuicListener {
106    async fn accept(&self) -> io::Result<Stream> {
107        let stream = self.accept().await?;
108        let addr = stream.peer_addr();
109        Ok(Stream::Udp(stream, addr))
110    }
111}
112
113/// Helper trait for converting listener types and register them to xitca-server
114/// By delay the conversion and make the process happen in server thread(s) it avoid possible panic due to runtime locality.
115///
116/// This trait is often utilized together with [Listen] trait. Please reference it's doc for examples.
117pub trait IntoListener: Send {
118    type Listener: Listen;
119
120    fn into_listener(self) -> io::Result<Self::Listener>;
121}
122
123impl IntoListener for std::net::TcpListener {
124    type Listener = TcpListener;
125
126    fn into_listener(self) -> io::Result<Self::Listener> {
127        self.set_nonblocking(true)?;
128        let listener = TcpListener::from_std(self)?;
129        info!("Started Tcp listening on: {:?}", listener.local_addr().ok());
130        Ok(listener)
131    }
132}
133
134#[cfg(unix)]
135impl IntoListener for std::os::unix::net::UnixListener {
136    type Listener = UnixListener;
137
138    fn into_listener(self) -> io::Result<Self::Listener> {
139        self.set_nonblocking(true)?;
140        let listener = UnixListener::from_std(self)?;
141        info!("Started Unix listening on: {:?}", listener.local_addr().ok());
142        Ok(listener)
143    }
144}
145
146#[cfg(feature = "quic")]
147impl IntoListener for QuicListenerBuilder {
148    type Listener = QuicListener;
149
150    fn into_listener(self) -> io::Result<Self::Listener> {
151        let udp = self.build()?;
152        info!("Started Udp listening on: {:?}", udp.endpoint().local_addr().ok());
153        Ok(udp)
154    }
155}