use std::marker::PhantomData;
use anyhow::Error;
use bytes::Bytes;
use futures::StreamExt;
use http_body_util::{BodyExt, Empty, Full, StreamBody, combinators::BoxBody};
use hyper::{HeaderMap, Response, body::{Frame, Incoming}, header::HeaderValue};
use crate::common::stream::ByteStream;
pub struct Final;
pub struct SetStatus;
#[derive(Debug)]
pub struct HttpResponse {
body: BoxBody<Bytes, Error>,
parts: hyper::http::response::Parts,
}
impl HttpResponse {
pub fn builder() -> HttpResponseBuilder<SetStatus> {
HttpResponseBuilder {
builder: Response::builder(),
_state: PhantomData
}
}
pub fn from_parts(body: BoxBody<Bytes, Error>, parts: hyper::http::response::Parts) -> HttpResponse {
HttpResponse {
body,
parts
}
}
pub fn body(self) -> ByteStream {
let stream = self.body.into_data_stream();
ByteStream::new(stream)
}
pub fn status(&self) -> u16 {
self.parts.status.as_u16()
}
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
&self.parts.headers
}
}
pub struct HttpResponseBuilder<State> {
builder: hyper::http::response::Builder,
_state: PhantomData<State>
}
impl HttpResponseBuilder<SetStatus> {
pub fn status(mut self, status: u16) -> HttpResponseBuilder<Final> {
self.builder = self.builder.status(status);
HttpResponseBuilder {
builder: self.builder,
_state: PhantomData
}
}
}
impl HttpResponseBuilder<Final> {
pub fn body_empty(self) -> anyhow::Result<HttpResponse> {
let body = Empty::new().map_err(|e| match e {}).boxed();
let response = self.builder.body(body)?;
Ok(HttpResponse::from(response))
}
pub fn body_boxed(self, body: BoxBody<Bytes, Error>) -> anyhow::Result<HttpResponse> {
let response = self.builder.body(body)?;
Ok(HttpResponse::from(response))
}
pub fn body_bytes(self, body: impl Into<Bytes>) -> anyhow::Result<HttpResponse> {
let body = Full::from(body.into()).map_err(|e| match e {}).boxed();
let response = self.builder.body(body)?;
Ok(HttpResponse::from(response))
}
pub fn body_stream(self, stream: ByteStream) -> anyhow::Result<HttpResponse> {
let mapped_stream = stream.inner_stream().map(|res| { res.map(Frame::data) });
let body = StreamBody::new(mapped_stream);
let boxed_body: BoxBody<Bytes, Error> = BodyExt::boxed(body);
let response: Response<BoxBody<Bytes, Error>> = self.builder.body(boxed_body)?;
Ok(HttpResponse::from(response))
}
pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.builder = self.builder.header(key.into(), value.into());
self
}
pub fn headers(mut self, headers: &HeaderMap<HeaderValue>) -> Self {
for (key, value) in headers.iter() {
self.builder = self.builder.header(key, value);
}
self
}
}
impl From<HttpResponse> for Response<BoxBody<Bytes, Error>> {
fn from(res: HttpResponse) -> Self {
Response::from_parts(res.parts, res.body)
}
}
impl From<Response<BoxBody<Bytes, Error>>> for HttpResponse {
fn from(res: Response<BoxBody<Bytes, Error>>) -> Self {
let (parts, body) = res.into_parts();
HttpResponse::from_parts(body, parts)
}
}
impl From<Response<Incoming>> for HttpResponse {
fn from(req: Response<Incoming>) -> Self {
let (parts, body) = req.into_parts();
let body = body.map_err(|e| anyhow::Error::from(e));
HttpResponse::from_parts(body.boxed(), parts)
}
}