use std::collections::HashMap;
use std::fmt::Display;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use serde::Serialize;
use tokio::sync::{Mutex, MutexGuard};
use water_uri::{IntoUri, Uri};
#[derive(Debug)]
pub struct HttpRequest {
pub(crate) method:&'static str,
pub(crate) path:String,
pub(crate) headers:HashMap<String,String>,
pub(crate) body: Option<HttpBody>
}
impl HttpRequest {
pub fn new(into_uri:impl IntoUri ) -> HttpRequest {
let mut path = into_uri.to_string();
if let Ok(uri) = Uri::new(path.clone()) {
path = uri.path.unwrap();
}
HttpRequest {
method:"GET",
path,
headers:HashMap::new(),
body:None,
}
}
pub fn get(into_uri:impl IntoUri) -> HttpRequest {
Self::new(into_uri)
}
pub fn post(into_uri:impl IntoUri) -> HttpRequest {
let mut new = Self::new(into_uri);
new.set_method("POST");
new
}
pub fn patch(into_uri:impl IntoUri) -> HttpRequest {
let mut new = Self::new(into_uri);
new.set_method("PATCH");
new
}
pub fn delete(into_uri:impl IntoUri) -> HttpRequest {
let mut new = Self::new(into_uri);
new.set_method("PATCH");
new
}
pub fn set_method(&mut self,method:&'static str){
self.method = method;
}
pub fn set_body(&mut self,body:HttpBody){
self.body = Some(body);
}
pub fn set_header(&mut self,key:impl Display,value:impl Display){
self.headers.insert(format!("{key}"),format!("{value}"));
}
}
#[derive(Debug)]
pub enum HttpBody {
Bytes(Vec<u8>),
Stream(BodyBytesSender)
}
impl HttpBody {
pub fn from_string(value:impl ToString)->HttpBody{
Self::from_bytes(value.to_string().as_bytes())
}
pub fn from_bytes(bytes:&[u8])->HttpBody{
HttpBody::Bytes(bytes.to_vec())
}
pub fn from_json(json:&impl Serialize)->HttpBody{
HttpBody::Bytes(serde_json::to_vec(json).unwrap())
}
pub fn send_chunks_stream(length:usize)->(HttpBody,Sender<(BytesSlice,bool)>){
let (sender,receiver) = channel(length);
let body = BodyBytesSender{
receiver:Mutex::new(receiver),
length
};
( HttpBody::Stream(body),sender)
}
}
type BytesSlice = Vec<u8>;
#[derive(Debug)]
pub struct BodyBytesSender{
pub(crate)receiver:Mutex<Receiver<(BytesSlice,bool)>>,
pub(crate)length:usize
}
impl BodyBytesSender {
pub async fn receiver(&self)->MutexGuard<Receiver<(BytesSlice,bool)>>{
let r = self.receiver.lock().await;
r
}
}