use super::HttpServeResult;
use super::core_conn::HttpCoreConnServer;
use rama_core::Service;
use rama_core::error::BoxError;
use rama_core::extensions::ExtensionsRef;
use rama_core::graceful::ShutdownGuard;
use rama_core::io::Io;
use rama_core::rt::Executor;
use rama_http::service::web::response::IntoResponse;
use rama_http_core::server::conn::auto::Builder as AutoConnBuilder;
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::address::SocketAddress;
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,
exec: Executor,
}
impl Default for HttpServer<AutoConnBuilder> {
#[inline(always)]
fn default() -> Self {
Self::auto(Executor::default())
}
}
impl HttpServer<Http1ConnBuilder> {
#[must_use]
pub fn new_http1(exec: Executor) -> Self {
Self {
builder: Http1ConnBuilder::new(),
exec,
}
}
}
impl HttpServer<Http1ConnBuilder> {
pub fn http1(&mut self) -> &Http1ConnBuilder {
&self.builder
}
pub fn http1_mut(&mut self) -> &mut Http1ConnBuilder {
&mut self.builder
}
}
impl HttpServer<H2ConnBuilder> {
#[must_use]
pub fn new_h2(exec: Executor) -> Self {
Self {
builder: H2ConnBuilder::new(exec.clone()),
exec,
}
}
}
impl HttpServer<H2ConnBuilder> {
pub fn h2(&self) -> &H2ConnBuilder {
&self.builder
}
pub fn h2_mut(&mut self) -> &mut H2ConnBuilder {
&mut self.builder
}
}
impl HttpServer<AutoConnBuilder> {
#[must_use]
pub fn auto(exec: Executor) -> Self {
Self {
builder: AutoConnBuilder::new(exec.clone()),
exec,
}
}
}
impl HttpServer<AutoConnBuilder> {
#[inline(always)]
pub fn http1(&self) -> &Http1ConnBuilder {
self.builder.http1()
}
#[inline(always)]
pub fn http1_mut(&mut self) -> &mut Http1ConnBuilder {
self.builder.http1_mut()
}
#[inline(always)]
pub fn h2(&self) -> &H2ConnBuilder {
self.builder.h2()
}
#[inline(always)]
pub fn h2_mut(&mut self) -> &mut H2ConnBuilder {
self.builder.h2_mut()
}
}
impl<B> HttpServer<B>
where
B: HttpCoreConnServer,
{
pub fn service<S: Clone>(self, service: S) -> HttpService<B, S> {
HttpService {
guard: self.exec.guard().cloned(),
builder: Arc::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: Io + ExtensionsRef,
{
self.builder
.http_core_serve_connection(stream, service, self.exec.guard().cloned())
.await
}
pub async fn listen<S, Response, A>(self, address: A, service: S) -> HttpServeResult
where
S: Service<Request, Output = Response, Error = Infallible> + Clone,
Response: IntoResponse + Send + 'static,
A: TryInto<SocketAddress, Error: Into<BoxError>>,
{
let tcp = TcpListener::bind_address(address, self.exec.clone()).await?;
let service = HttpService {
guard: self.exec.guard().cloned(),
builder: Arc::new(self.builder),
service,
};
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, self.exec.clone()).await?;
let service = HttpService {
guard: self.exec.guard().cloned(),
builder: Arc::new(self.builder),
service: Arc::new(service),
};
socket.serve(service).await;
Ok(())
}
}
pub struct HttpService<B, S> {
guard: Option<ShutdownGuard>,
builder: Arc<B>,
service: 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("guard", &self.guard)
.field("builder", &self.builder)
.field("service", &self.service)
.finish()
}
}
impl<B, S: Clone> Clone for HttpService<B, S> {
fn clone(&self) -> Self {
Self {
guard: self.guard.clone(),
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> + Clone,
Response: IntoResponse + Send + 'static,
IO: Io + ExtensionsRef,
{
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, self.guard.clone())
}
}