use std::process::ExitCode;
use std::sync::Arc;
use std::time::Duration;
use tokio::net::{TcpListener, ToSocketAddrs};
use super::accept;
use super::tls::TcpAcceptor;
use crate::app::{AppService, Via};
use crate::error::Error;
#[cfg(feature = "native-tls")]
use super::tls::NativeTlsAcceptor;
#[cfg(feature = "rustls")]
use super::tls::RustlsAcceptor;
pub struct Server<App> {
app: Via<App>,
config: ServerConfig,
}
#[derive(Debug)]
pub struct ServerConfig {
pub(super) max_connections: usize,
pub(super) max_request_size: usize,
pub(super) shutdown_timeout: Duration,
#[cfg(any(feature = "native-tls", feature = "rustls"))]
pub(super) 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
}
}
pub fn listen<A>(self, address: A) -> impl Future<Output = Result<ExitCode, Error>>
where
A: ToSocketAddrs,
{
let acceptor = TcpAcceptor;
let service = AppService::new(Arc::new(self.app), self.config.max_request_size);
async move {
let listener = TcpListener::bind(address).await?;
Ok(accept(self.config, acceptor, service, listener).await)
}
}
#[cfg(feature = "native-tls")]
pub fn listen_native_tls<A>(
self,
address: A,
identity: native_tls::Identity,
) -> impl Future<Output = Result<ExitCode, Error>>
where
A: ToSocketAddrs,
{
let acceptor = NativeTlsAcceptor::new(identity);
let service = AppService::new(Arc::new(self.app), self.config.max_request_size);
async {
let listener = TcpListener::bind(address).await?;
Ok(accept(self.config, acceptor, service, listener).await)
}
}
#[cfg(feature = "rustls")]
pub fn listen_rustls<A>(
self,
address: A,
rustls_config: rustls::ServerConfig,
) -> impl Future<Output = Result<ExitCode, Error>>
where
A: ToSocketAddrs,
{
let acceptor = RustlsAcceptor::new(rustls_config);
let service = AppService::new(Arc::new(self.app), self.config.max_request_size);
async {
let listener = TcpListener::bind(address).await?;
Ok(accept(self.config, acceptor, service, listener).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)),
}
}
}