use bytes::Bytes;
use bytes::BytesMut;
use dashmap::DashMap;
use lazy_static::*;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::iter::FromIterator;
use thruster_proc::middleware_fn;
use crate::core::context::Context;
use crate::core::errors::{ErrorSet, ThrusterError as Error};
use crate::core::{MiddlewareNext, MiddlewareResult};
use crate::map_try;
lazy_static! {
static ref CACHE: DashMap<String, Vec<u8>> = DashMap::new();
static ref ROOT_DIR: String = env::var("RUST_ROOT_DIR").unwrap_or_else(|_| "/".to_string());
static ref HOST_DIR: String = env::var("RUST_HOST_DIR").unwrap_or_else(|_| "".to_string());
}
#[middleware_fn(_internal)]
pub async fn file<T: 'static + Context + Send>(
mut context: T,
_next: MiddlewareNext<T>,
) -> MiddlewareResult<T> {
let root_dir: &'static str = &ROOT_DIR;
let host_dir: &'static str = &HOST_DIR;
let path = context.route().replace(root_dir, host_dir);
let content = map_try!(get_file(&path), Err(_) => Error::not_found_error(context));
context.set_body_bytes(content);
Ok(context)
}
pub fn get_file(path: &str) -> Result<Bytes, std::io::Error> {
let path = path.replace("..", "");
let is_cache_off = env::var("RUST_CACHE").unwrap_or_else(|_| "off".to_string()) == "off";
let fetched = CACHE.get(&path);
match (is_cache_off, fetched) {
(false, Some(val)) => Ok(Bytes::from(BytesMut::from_iter(&*val))),
(false, None) => {
let val = read_file(&path)?;
CACHE.insert(path.clone(), val);
let val = CACHE.get(&path).unwrap();
Ok(Bytes::from(BytesMut::from_iter(&*val)))
}
(true, _) => {
let val = read_file(&path)?;
Ok(Bytes::from(BytesMut::from_iter(&*val)))
}
}
}
fn read_file(path: &str) -> Result<Vec<u8>, std::io::Error> {
let mut file = File::open(path)?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
Ok(contents)
}