use std::future::Future;
use std::sync::Arc;
use std::time::Duration;
use tokio::net::{TcpListener, ToSocketAddrs};
#[cfg(feature = "rustls")]
use tokio_rustls::rustls;
use super::acceptor::{self, Acceptor};
use super::serve::serve;
use crate::{App, Error, Router};
const DEFAULT_MAX_CONNECTIONS: usize = 256;
const DEFAULT_SHUTDOWN_TIMEOUT: u64 = 30;
pub struct Server<State> {
state: Arc<State>,
router: Arc<Router<State>>,
max_connections: Option<usize>,
shutdown_timeout: Option<u64>,
#[cfg(feature = "rustls")]
rustls_config: Option<rustls::ServerConfig>,
}
async fn listen<State, A>(
acceptor: A,
address: impl ToSocketAddrs,
state: Arc<State>,
router: Arc<Router<State>>,
max_connections: Option<usize>,
shutdown_timeout: Option<u64>,
) -> Result<(), Error>
where
State: Send + Sync + 'static,
A: Acceptor + Send + Sync + 'static,
{
let listener = TcpListener::bind(address).await?;
let max_connections = max_connections.unwrap_or(DEFAULT_MAX_CONNECTIONS);
let shutdown_timeout = shutdown_timeout.map_or_else(
|| Duration::from_secs(DEFAULT_SHUTDOWN_TIMEOUT),
Duration::from_secs,
);
if let Err(error) = listener.local_addr() {
let _ = error;
}
let server = serve(
listener,
acceptor,
state,
router,
max_connections,
shutdown_timeout,
);
server.await
}
impl<State> Server<State>
where
State: Send + Sync + 'static,
{
pub fn new(app: App<State>) -> Self {
Self {
state: app.state,
router: Arc::new(app.router),
#[cfg(feature = "rustls")]
rustls_config: None,
max_connections: None,
shutdown_timeout: None,
}
}
#[cfg(feature = "rustls")]
pub fn listen<A: ToSocketAddrs>(self, address: A) -> impl Future<Output = Result<(), Error>> {
let tls_config = match self.rustls_config {
Some(config) => Arc::new(config),
None => panic!("rustls_config is required to use the 'rustls' feature"),
};
let acceptor = acceptor::rustls::RustlsAcceptor::new(tls_config);
let state = self.state;
let router = self.router;
let max_connections = self.max_connections;
let shutdown_timeout = self.shutdown_timeout;
listen(
acceptor,
address,
state,
router,
max_connections,
shutdown_timeout,
)
}
#[cfg(not(feature = "rustls"))]
pub fn listen<A: ToSocketAddrs>(self, address: A) -> impl Future<Output = Result<(), Error>> {
let acceptor = acceptor::http::HttpAcceptor;
let state = self.state;
let router = self.router;
let max_connections = self.max_connections;
let shutdown_timeout = self.shutdown_timeout;
listen(
acceptor,
address,
state,
router,
max_connections,
shutdown_timeout,
)
}
pub fn shutdown_timeout(self, timeout: u64) -> Self {
Self {
shutdown_timeout: Some(timeout),
..self
}
}
pub fn max_connections(self, n: usize) -> Self {
Self {
max_connections: Some(n),
..self
}
}
#[cfg(feature = "rustls")]
pub fn rustls_config(self, server_config: rustls::ServerConfig) -> Self {
Self {
rustls_config: Some(server_config),
..self
}
}
}