use http_body_util::Full;
use hyper_tungstenite::hyper::{Request, Response};
use ripress::res::response_status::StatusCode;
use std::{mem, sync::Arc};
use tokio_tungstenite::tungstenite::{
http::{response::Builder, HeaderName, HeaderValue, Version},
Bytes,
};
pub struct Context {
pub request: Arc<Request<Full<Bytes>>>,
pub(crate) response: Builder,
}
pub struct ResponseBuilder<'a> {
builder: &'a mut Builder,
}
impl Context {
pub fn response(&mut self) -> ResponseBuilder<'_> {
ResponseBuilder {
builder: &mut self.response,
}
}
}
impl<'a> ResponseBuilder<'a> {
pub fn status<T: Into<StatusCode>>(self, status: T) -> Self {
let builder = mem::take(self.builder);
*self.builder = builder.status(status.into().as_u16());
self
}
pub fn header(&mut self, key: HeaderName, value: HeaderValue) -> &mut Self {
let builder = mem::take(self.builder);
*self.builder = builder.header(key, value);
self
}
pub fn header_str(
&mut self,
key: &str,
value: &str,
) -> Result<&mut Self, Box<dyn std::error::Error>> {
let builder = mem::take(self.builder);
let header_name = HeaderName::from_bytes(key.as_bytes())?;
let header_value = HeaderValue::from_bytes(value.as_bytes())?;
*self.builder = builder.header(header_name, header_value);
Ok(self)
}
pub fn version(&mut self, version: Version) -> &mut Self {
let builder = mem::take(self.builder);
*self.builder = builder.version(version);
self
}
pub fn headers<I>(&mut self, headers: I) -> Result<&mut Self, Box<dyn std::error::Error>>
where
I: IntoIterator<Item = (&'static str, &'static str)>,
{
for (key, value) in headers {
self.header_str(key, value)?;
}
Ok(self)
}
pub fn content_type(
&mut self,
content_type: &str,
) -> Result<&mut Self, Box<dyn std::error::Error>> {
self.header_str("content-type", content_type)
}
pub fn content_length(&mut self, len: u64) -> Result<&mut Self, Box<dyn std::error::Error>> {
self.header_str("content-length", &len.to_string())
}
pub fn location(&mut self, location: &str) -> Result<&mut Self, Box<dyn std::error::Error>> {
self.header_str("location", location)
}
pub fn body<B: Into<Bytes>>(
self,
body: B,
) -> Result<Response<Full<Bytes>>, Box<dyn std::error::Error>> {
let builder = mem::take(self.builder);
builder
.body(Full::new(body.into()))
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
}
}