use crate::Request;
use chunked_transfer::Encoder;
use futures::future::BoxFuture;
use std::collections::HashMap;
use std::future::Future;
use std::io::Write;
use tokio::io::AsyncReadExt;
pub trait RouteDef {
fn call(&self, request: Request) -> BoxFuture<'static, Result<String, String>>;
}
impl<T, F> RouteDef for T
where
T: Fn(Request) -> F,
F: Future<Output = Result<String, String>> + Send + 'static,
{
fn call(&self, request: Request) -> BoxFuture<'static, Result<String, String>> {
Box::pin(self(request))
}
}
pub struct Route {
function: Box<dyn RouteDef>,
}
impl Route {
pub fn new(function: Box<dyn RouteDef>) -> Self {
Self { function }
}
pub async fn run(&self, request: Request) -> DataType {
if let Ok(v) = self.function.call(request).await {
DataType::Text(v)
} else {
DataType::Text(String::new()) }
}
}
pub enum DataType {
Text(String),
Bytes(Vec<u8>),
}
pub struct Routes {
routes: HashMap<String, Route>,
}
impl Routes {
pub async fn new() -> Self {
Self {
routes: HashMap::<String, Route>::new(),
}
}
pub async fn add_route(&mut self, route: String, content: Route) {
self.routes.insert(route, content);
}
pub async fn get_route(
&self,
request: String,
user_addr: std::net::SocketAddr,
is_secure: bool,
) -> Result<DataType, &str> {
let request = Request::new(request, user_addr, is_secure).await.unwrap();
if request.uri.contains("static") {
let file_path = format!(".{}", request.uri);
return match tokio::fs::File::open(file_path).await {
Ok(mut file_handle) => {
let mut contents = vec![];
file_handle.read_to_end(&mut contents).await.unwrap();
let result = String::from("HTTP/1.1 {}\r\nContent-type: image/jpeg;\r\nTransfer-Encoding: chunked\r\n\r\n");
let mut result = result.into_bytes();
let chunks = contents.chunks(5);
let mut iter_chunks = Vec::<std::io::IoSlice>::new();
for chunk in chunks {
iter_chunks.push(std::io::IoSlice::new(chunk));
}
let mut encoded = Vec::new();
{
let mut encoder = Encoder::with_chunks_size(&mut encoded, 8);
encoder.write_all_vectored(&mut iter_chunks).unwrap();
}
result.extend(&encoded);
match String::from_utf8(result.clone()) {
Ok(_) => {
let result = String::from("HTTP/1.1 {} {}\r\nContent-type: text/css;\r\nTransfer-Encoding: chunked\r\n\r\n");
let mut result = result.into_bytes();
result.extend(&encoded);
let v = String::from_utf8(result).expect("This should work");
return Ok(DataType::Text(v));
}
Err(_) => return Ok(DataType::Bytes(result)),
}
}
Err(e) => {
println!("Error loading static content: {}", e);
Ok(DataType::Text(String::from(
"ERROR - CONTENT NOT AVAILABLE",
)))
}
};
}
let func = match self.routes.get(&request.uri) {
Some(v) => v,
None => {
println!(
"Error - user requested '{}', which does not exist on this server.",
request.uri
);
self.routes.get(&"err".to_string()).unwrap() }
};
let result = func.run(request).await;
Ok(result)
}
}