use super::HttpServeResult;
use super::core_conn::HttpCoreConnServer;
use rama_core::Service;
use rama_core::error::BoxError;
use rama_core::extensions::ExtensionsMut;
use rama_core::graceful::ShutdownGuard;
use rama_core::rt::Executor;
use rama_core::stream::Stream;
use rama_http::service::web::response::IntoResponse;
use rama_http_core::server::conn::auto::Builder as AutoConnBuilder;
use rama_http_core::server::conn::auto::Http1Builder as InnerAutoHttp1Builder;
use rama_http_core::server::conn::auto::Http2Builder as InnerAutoHttp2Builder;
use rama_http_core::server::conn::http1::Builder as Http1ConnBuilder;
use rama_http_core::server::conn::http2::Builder as H2ConnBuilder;
use rama_http_types::Request;
use rama_net::socket::Interface;
use rama_tcp::server::TcpListener;
use std::convert::Infallible;
use std::fmt;
use std::sync::Arc;
#[cfg(target_family = "unix")]
use ::{rama_unix::server::UnixListener, std::path::Path};
#[derive(Debug, Clone)]
pub struct HttpServer<B> {
builder: B,
guard: Option<ShutdownGuard>,
}
impl Default for HttpServer<AutoConnBuilder> {
#[inline(always)]
fn default() -> Self {
Self::auto(Executor::default())
}
}
impl HttpServer<Http1ConnBuilder> {
#[must_use]
pub fn http1() -> Self {
Self {
builder: Http1ConnBuilder::new(),
guard: None,
}
}
rama_utils::macros::generate_set_and_with! {
pub fn guard(mut self, guard: Option<ShutdownGuard>) -> Self {
self.guard = guard;
self
}
}
}
impl HttpServer<Http1ConnBuilder> {
pub fn http1_mut(&mut self) -> &mut Http1ConnBuilder {
&mut self.builder
}
}
impl HttpServer<H2ConnBuilder> {
#[must_use]
pub fn h2(exec: Executor) -> Self {
let guard = exec.guard().cloned();
Self {
builder: H2ConnBuilder::new(exec),
guard,
}
}
}
impl HttpServer<H2ConnBuilder> {
pub fn h2_mut(&mut self) -> &mut H2ConnBuilder {
&mut self.builder
}
}
impl HttpServer<AutoConnBuilder> {
#[must_use]
pub fn auto(exec: Executor) -> Self {
let guard = exec.guard().cloned();
Self {
builder: AutoConnBuilder::new(exec),
guard,
}
}
}
impl HttpServer<AutoConnBuilder> {
pub fn http1_mut(&mut self) -> InnerAutoHttp1Builder<'_> {
self.builder.http1()
}
pub fn h2_mut(&mut self) -> InnerAutoHttp2Builder<'_> {
self.builder.http2()
}
}
impl<B> HttpServer<B>
where
B: HttpCoreConnServer,
{
pub fn service<S>(self, service: S) -> HttpService<B, S> {
HttpService::new(self.builder, service)
}
pub async fn serve<S, Response, IO>(&self, stream: IO, service: S) -> HttpServeResult
where
S: Service<Request, Output = Response, Error = Infallible> + Clone,
Response: IntoResponse + Send + 'static,
IO: Stream + ExtensionsMut,
{
self.builder
.http_core_serve_connection(stream, service)
.await
}
pub async fn listen<S, Response, I>(self, interface: I, service: S) -> HttpServeResult
where
S: Service<Request, Output = Response, Error = Infallible>,
Response: IntoResponse + Send + 'static,
I: TryInto<Interface, Error: Into<BoxError>>,
{
let tcp = TcpListener::bind(interface).await?;
let service = HttpService::new(self.builder, service);
match self.guard {
Some(guard) => tcp.serve_graceful(guard, service).await,
None => tcp.serve(service).await,
};
Ok(())
}
#[cfg(target_family = "unix")]
#[cfg_attr(docsrs, doc(cfg(target_family = "unix")))]
pub async fn listen_unix<S, Response, P>(self, path: P, service: S) -> HttpServeResult
where
S: Service<Request, Output = Response, Error = Infallible>,
Response: IntoResponse + Send + 'static,
P: AsRef<Path>,
{
let socket = UnixListener::bind_path(path).await?;
let service = HttpService::new(self.builder, service);
match self.guard {
Some(guard) => socket.serve_graceful(guard, service).await,
None => socket.serve(service).await,
};
Ok(())
}
}
pub struct HttpService<B, S> {
builder: Arc<B>,
service: Arc<S>,
}
impl<B, S> std::fmt::Debug for HttpService<B, S>
where
B: fmt::Debug,
S: fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HttpService")
.field("builder", &self.builder)
.field("service", &self.service)
.finish()
}
}
impl<B, S> HttpService<B, S> {
fn new(builder: B, service: S) -> Self {
Self {
builder: Arc::new(builder),
service: Arc::new(service),
}
}
}
impl<B, S> Clone for HttpService<B, S> {
fn clone(&self) -> Self {
Self {
builder: self.builder.clone(),
service: self.service.clone(),
}
}
}
impl<B, S, Response, IO> Service<IO> for HttpService<B, S>
where
B: HttpCoreConnServer,
S: Service<Request, Output = Response, Error = Infallible>,
Response: IntoResponse + Send + 'static,
IO: Stream + ExtensionsMut,
{
type Output = ();
type Error = rama_core::error::BoxError;
fn serve(
&self,
stream: IO,
) -> impl Future<Output = Result<Self::Output, Self::Error>> + Send + '_ {
let service = self.service.clone();
self.builder.http_core_serve_connection(stream, service)
}
}