use crate::Result;
use headers::{Header, HeaderMapExt};
use hyper::header::{HeaderName, HeaderValue};
use hyper::{Body, StatusCode};
use serde::Serialize;
use std::convert::TryInto;
use std::path::Path;
use tokio::io::AsyncRead;
use tokio_util::io::ReaderStream;
use tracing::debug;
#[derive(Debug)]
pub struct Response {
inner: hyper::Response<Body>,
}
impl Response {
pub fn ok() -> Self {
Self {
inner: hyper::Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.expect("ok status with empty body should never fail"),
}
}
pub fn status(s: StatusCode) -> Self {
Self {
inner: hyper::Response::builder()
.status(s)
.body(Body::empty())
.expect("status with empty body should never fail"),
}
}
pub fn set_status(&mut self, s: StatusCode) {
*self.inner.status_mut() = s;
}
pub fn get_status(&self) -> StatusCode {
self.inner.status()
}
pub fn body(mut self, body: impl Into<Body>) -> Self {
*self.inner.body_mut() = body.into();
self
}
pub fn reader(mut self, r: impl AsyncRead + Send + 'static) -> Self {
let body = Body::wrap_stream(ReaderStream::new(r));
*self.inner.body_mut() = body;
self
}
pub async fn path(self, path: impl AsRef<Path>) -> Result<Self> {
let target = path.as_ref();
let reader = tokio::fs::File::open(&target).await?;
let mime = mime_guess::from_path(&target).first_or_text_plain();
debug!("guessed mime: {}", mime);
Ok(self.header(headers::ContentType::from(mime)).reader(reader))
}
pub fn json(mut self, body: impl Serialize) -> Result<Self> {
let data = serde_json::to_vec(&body)?;
self.set_header(headers::ContentType::json());
*self.inner.body_mut() = Body::from(data);
Ok(self)
}
pub fn form(mut self, body: impl Serialize) -> Result<Self> {
let form = serde_urlencoded::to_string(body)?;
self.set_header(headers::ContentType::form_url_encoded());
*self.inner.body_mut() = Body::from(form);
Ok(self)
}
pub fn header<H: Header>(mut self, h: H) -> Self {
self.set_header(h);
self
}
pub fn set_header<H: Header>(&mut self, h: H) {
self.inner.headers_mut().typed_insert(h);
}
pub fn raw_header<N, K>(mut self, name: N, key: K) -> Result<Self>
where
N: TryInto<HeaderName>,
K: TryInto<HeaderValue>,
<N as TryInto<HeaderName>>::Error: Into<anyhow::Error>,
<K as TryInto<HeaderValue>>::Error: Into<anyhow::Error>,
{
self.set_raw_header(name, key)?;
Ok(self)
}
pub fn set_raw_header<N, K>(&mut self, name: N, key: K) -> Result<()>
where
N: TryInto<HeaderName>,
K: TryInto<HeaderValue>,
<N as TryInto<HeaderName>>::Error: Into<anyhow::Error>,
<K as TryInto<HeaderValue>>::Error: Into<anyhow::Error>,
{
self.inner
.headers_mut()
.insert(name.try_into()?, key.try_into()?);
Ok(())
}
pub fn into_inner(self) -> hyper::Response<hyper::Body> {
self.inner
}
}
impl From<hyper::Response<Body>> for Response {
fn from(hyper_response: hyper::Response<Body>) -> Self {
Self {
inner: hyper_response,
}
}
}
impl AsRef<hyper::Response<Body>> for Response {
fn as_ref(&self) -> &hyper::Response<Body> {
&self.inner
}
}