mod accept;
mod io;
mod tls;
use std::process::ExitCode;
use std::sync::Arc;
use std::time::Duration;
use tokio::net::{TcpListener, ToSocketAddrs};
use crate::app::{AppService, Via};
use crate::error::Error;
use accept::accept;
use io::IoWithPermit;
use tls::TcpAcceptor;
#[cfg(feature = "native-tls")]
use tls::NativeTlsAcceptor;
#[cfg(feature = "rustls")]
use tls::RustlsAcceptor;
pub struct Server<App> {
app: Via<App>,
config: ServerConfig,
}
#[derive(Debug)]
struct ServerConfig {
max_connections: usize,
max_request_size: usize,
shutdown_timeout: Duration,
#[cfg(any(feature = "native-tls", feature = "rustls"))]
tls_handshake_timeout: Option<Duration>,
}
impl<App> Server<App>
where
App: Send + Sync + 'static,
{
pub fn new(app: Via<App>) -> Self {
Self {
app,
config: Default::default(),
}
}
pub fn max_connections(self, max_connections: usize) -> Self {
Self {
config: ServerConfig {
max_connections,
..self.config
},
..self
}
}
pub fn max_request_size(self, max_request_size: usize) -> Self {
Self {
config: ServerConfig {
max_request_size,
..self.config
},
..self
}
}
pub fn shutdown_timeout(self, shutdown_timeout: Duration) -> Self {
Self {
config: ServerConfig {
shutdown_timeout,
..self.config
},
..self
}
}
#[cfg(any(feature = "native-tls", feature = "rustls"))]
pub fn tls_handshake_timeout(self, tls_handshake_timeout: Option<Duration>) -> Self {
Self {
config: ServerConfig {
tls_handshake_timeout,
..self.config
},
..self
}
}
#[inline(never)]
pub async fn listen(self, address: impl ToSocketAddrs) -> Result<ExitCode, Error> {
let listener = TcpListener::bind(address).await?;
let service = AppService::new(Arc::new(self.app), self.config.max_request_size);
Ok(accept(TcpAcceptor, listener, service, self.config).await)
}
#[cfg(feature = "native-tls")]
#[inline(never)]
pub async fn listen_native_tls(
self,
address: impl ToSocketAddrs,
identity: native_tls::Identity,
) -> Result<ExitCode, Error> {
let acceptor = NativeTlsAcceptor::new(identity);
let listener = TcpListener::bind(address).await?;
let service = AppService::new(Arc::new(self.app), self.config.max_request_size);
Ok(accept(acceptor, listener, service, self.config).await)
}
#[cfg(feature = "rustls")]
#[inline(never)]
pub async fn listen_rustls(
self,
address: impl ToSocketAddrs,
rustls_config: rustls::ServerConfig,
) -> Result<ExitCode, Error> {
let acceptor = RustlsAcceptor::new(rustls_config);
let listener = TcpListener::bind(address).await?;
let service = AppService::new(Arc::new(self.app), self.config.max_request_size);
Ok(accept(acceptor, listener, service, self.config).await)
}
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
max_connections: 1000,
max_request_size: 104_857_600, shutdown_timeout: Duration::from_secs(30),
#[cfg(any(feature = "native-tls", feature = "rustls"))]
tls_handshake_timeout: Some(Duration::from_secs(10)),
}
}
}