use std::{borrow::Cow, collections::HashMap, fmt::Display, rc::Rc, sync::Arc, time::{SystemTime, UNIX_EPOCH}};
pub trait Response: Sync + Send {
fn as_response(&self) -> Vec<u8>;
}
pub struct HttpResponse<'a> {
headers: Vec<(&'a str, &'a str)>,
body: Cow<'a, str>,
}
pub struct BinaryResponse {
payload: Vec<u8>,
}
pub struct SSEResponse<'a> {
message: Cow<'a, str>,
fields: HashMap<Cow<'a, str>, Cow<'a, str>>
}
pub struct RawResponse<'a> {
payload: Cow<'a, [u8]>,
}
impl<'a> HttpResponse<'a> {
pub fn new() -> Self {
HttpResponse { headers: Vec::new(), body: Cow::Borrowed("") }
}
pub fn header(&mut self, name: &'a str, value: &'a str) {
self.headers.push((name, value));
}
pub fn body<T>(&mut self, body: T)
where
T: Into<Cow<'a, str>>
{
self.body = body.into();
}
}
impl<'a> SSEResponse<'a> {
pub fn new() -> Self {
SSEResponse { message: Cow::Borrowed(""), fields: HashMap::new() }
}
pub fn message<M>(&mut self, message: M)
where
M: Into<Cow<'a, str>>
{
self.message = message.into();
}
pub fn field<T, U>(&mut self, field_name: T, field_value: U)
where
T: Into<Cow<'a, str>>,
U: Into<Cow<'a, str>>,
{
self.fields.insert(field_name.into(), field_value.into());
}
pub fn init() -> Vec<u8> {
"HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nCache-Control: no-cache\r\nConnection: keep-alive\r\n\r\n".into()
}
}
impl BinaryResponse {
pub fn new(payload: Vec<u8>) -> Self {
BinaryResponse { payload }
}
}
impl<'a> RawResponse<'a> {
pub fn new<T>(payload: T) -> Self
where
T: Into<Cow<'a, [u8]>>
{
RawResponse { payload: payload.into() }
}
}
fn is_valid(str: &str) -> bool {
!(str.contains("\r") || str.contains("\n") || str.contains("\0"))
}
fn respond_http<T: Display>(payload: &T, len: usize, headers: Option<&Vec<(&str, &str)>>) -> String {
let mut headers_str = String::new();
if let Some(headers) = headers {
headers_str = headers.iter().map(|e| {
if is_valid(e.0) && is_valid(e.1) && e.0 != "Content-Length" {format!("{}: {}\r\n", e.0, e.1)} else {"".to_string()}
}).collect::<String>()
}
format!("HTTP/1.1 {}\r\nContent-Length: {}\r\n{}\r\n{}",
if len == 0 {"204 NO CONTENT"} else {"200 OK"},
if len != 0 {len} else {0},
headers_str,
payload
)
}
impl<'a> Response for Box<dyn Response>
{
fn as_response(&self) -> Vec<u8> {
(**self).as_response()
}
}
impl<'a, T> Response for &T
where
T: Response
{
fn as_response(&self) -> Vec<u8> {
(**self).as_response()
}
}
impl<'a> Response for SSEResponse<'a> {
fn as_response(&self) -> Vec<u8> {
format!("data: {}\"message\": \"{}\", \"timestamp\": \"{}\"{}{}\r\n\r\n",
"{",
self.message,
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis(),
self.fields.iter().map(|e| {format!(r#","{}": {}"#, e.0, e.1)}).collect::<String>(),
"}"
).into_bytes()
}
}
impl<'a> Response for HttpResponse<'a> {
fn as_response(&self) -> Vec<u8> {
respond_http(&self.body, self.body.len(), Some(&self.headers)).into_bytes()
}
}
impl<'a> Response for RawResponse<'a> {
fn as_response(&self) -> Vec<u8> {
self.payload.as_ref().into()
}
}
impl Response for BinaryResponse {
fn as_response(&self) -> Vec<u8> {
let mut payload = Vec::new();
payload.extend((self.payload.len() as u64).to_le_bytes());
payload.extend(&self.payload[..]);
payload
}
}
impl Response for () {
fn as_response(&self) -> Vec<u8> {
respond_http(&"", 0, None).into_bytes()
}
}
impl Response for &str {
fn as_response(&self) -> Vec<u8> {
respond_http(&self, self.len(), None).into_bytes()
}
}
impl Response for String {
fn as_response(&self) -> Vec<u8> {
respond_http(self, self.len(), None).into_bytes()
}
}
impl Response for Vec<u8> {
fn as_response(&self) -> Vec<u8> {
self.to_owned()
}
}
impl Response for i8 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 1, None).into_bytes()
}
}
impl Response for u8 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 1, None).into_bytes()
}
}
impl Response for i16 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 2, None).into_bytes()
}
}
impl Response for u16 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 2, None).into_bytes()
}
}
impl Response for i32 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 4, None).into_bytes()
}
}
impl Response for u32 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 4, None).into_bytes()
}
}
impl Response for i64 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 8, None).into_bytes()
}
}
impl Response for u64 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 8, None).into_bytes()
}
}
impl Response for i128 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 16, None).into_bytes()
}
}
impl Response for u128 {
fn as_response(&self) -> Vec<u8> {
respond_http(self, 16, None).into_bytes()
}
}