rama_http_backend/server/
service.rsuse super::hyper_conn::HttpCoreConnServer;
use super::HttpServeResult;
use rama_core::graceful::ShutdownGuard;
use rama_core::rt::Executor;
use rama_core::{Context, Service};
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::{IntoResponse, Request};
use rama_net::stream::Stream;
use rama_tcp::server::TcpListener;
use std::convert::Infallible;
use std::fmt;
use std::future::Future;
use std::sync::Arc;
use tokio::net::ToSocketAddrs;
pub struct HttpServer<B> {
builder: B,
guard: Option<ShutdownGuard>,
}
impl<B> fmt::Debug for HttpServer<B>
where
B: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HttpServer")
.field("builder", &self.builder)
.finish()
}
}
impl<B> Clone for HttpServer<B>
where
B: Clone,
{
fn clone(&self) -> Self {
Self {
builder: self.builder.clone(),
guard: self.guard.clone(),
}
}
}
impl HttpServer<Http1ConnBuilder> {
pub fn http1() -> Self {
Self {
builder: Http1ConnBuilder::new(),
guard: None,
}
}
pub fn with_guard(mut self, guard: ShutdownGuard) -> Self {
self.guard = Some(guard);
self
}
pub fn maybe_with_guard(mut self, guard: Option<ShutdownGuard>) -> Self {
self.guard = guard;
self
}
pub fn set_guard(&mut self, guard: ShutdownGuard) -> &mut Self {
self.guard = Some(guard);
self
}
}
impl HttpServer<Http1ConnBuilder> {
pub fn http1_mut(&mut self) -> &mut Http1ConnBuilder {
&mut self.builder
}
}
impl HttpServer<H2ConnBuilder> {
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> {
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<State, S, Response, IO>(
&self,
ctx: Context<State>,
stream: IO,
service: S,
) -> HttpServeResult
where
State: Clone + Send + Sync + 'static,
S: Service<State, Request, Response = Response, Error = Infallible> + Clone,
Response: IntoResponse + Send + 'static,
IO: Stream,
{
self.builder
.http_core_serve_connection(ctx, stream, service)
.await
}
pub async fn listen<S, Response, A>(self, addr: A, service: S) -> HttpServeResult
where
S: Service<(), Request, Response = Response, Error = Infallible>,
Response: IntoResponse + Send + 'static,
A: ToSocketAddrs,
{
let tcp = TcpListener::bind(addr).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(())
}
pub async fn listen_with_state<State, S, Response, A>(
self,
state: State,
addr: A,
service: S,
) -> HttpServeResult
where
State: Clone + Send + Sync + 'static,
S: Service<State, Request, Response = Response, Error = Infallible>,
Response: IntoResponse + Send + 'static,
A: ToSocketAddrs,
{
let tcp = TcpListener::build_with_state(state).bind(addr).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(())
}
}
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, State, S, Response, IO> Service<State, IO> for HttpService<B, S>
where
B: HttpCoreConnServer,
State: Clone + Send + Sync + 'static,
S: Service<State, Request, Response = Response, Error = Infallible>,
Response: IntoResponse + Send + 'static,
IO: Stream,
{
type Response = ();
type Error = rama_core::error::BoxError;
fn serve(
&self,
ctx: Context<State>,
stream: IO,
) -> impl Future<Output = Result<Self::Response, Self::Error>> + Send + '_ {
let service = self.service.clone();
self.builder
.http_core_serve_connection(ctx, stream, service)
}
}