use std::future::Future;
use std::net::SocketAddr;
use crate::connection::ConnectionInfo;
use crate::server::configuration::ServerConfiguration;
use crate::server::server_handle::ServerHandle;
use super::IncomingStream;
#[must_use = "You must call `serve` on a `Server` to start listening for incoming connections"]
pub struct Server {
config: ServerConfiguration,
incoming: Vec<IncomingStream>,
}
impl Default for Server {
fn default() -> Self {
Self::new()
}
}
impl Server {
pub fn new() -> Self {
Self {
config: ServerConfiguration::default(),
incoming: Vec::new(),
}
}
pub fn set_config(mut self, config: ServerConfiguration) -> Self {
self.config = config;
self
}
pub fn get_config(&self) -> &ServerConfiguration {
&self.config
}
pub async fn bind(mut self, addr: SocketAddr) -> std::io::Result<Self> {
let incoming = IncomingStream::bind(addr).await?;
self.incoming.push(incoming);
Ok(self)
}
pub fn listen(mut self, incoming: IncomingStream) -> Self {
self.incoming.push(incoming);
self
}
pub fn serve<HandlerFuture, ApplicationState>(
self,
handler: fn(
http::Request<hyper::body::Incoming>,
Option<ConnectionInfo>,
ApplicationState,
) -> HandlerFuture,
application_state: ApplicationState,
) -> ServerHandle
where
HandlerFuture: Future<Output = crate::response::Response> + 'static,
ApplicationState: Clone + Send + Sync + 'static,
{
self.try_serve(handler, application_state).unwrap()
}
pub fn try_serve<HandlerFuture, ApplicationState>(
self,
handler: fn(
http::Request<hyper::body::Incoming>,
Option<ConnectionInfo>,
ApplicationState,
) -> HandlerFuture,
application_state: ApplicationState,
) -> Result<ServerHandle, std::io::Error>
where
HandlerFuture: Future<Output = crate::response::Response> + 'static,
ApplicationState: Clone + Send + Sync + 'static,
{
if self.incoming.is_empty() {
let err_msg = "Cannot serve: there is no source of incoming connections. You must call `bind` or `listen` on the `Server` instance before invoking `serve`.";
return Err(std::io::Error::new(std::io::ErrorKind::Other, err_msg));
}
Ok(ServerHandle::new(
self.config,
self.incoming,
handler,
application_state,
))
}
}