use std::sync::Arc;
use std::cell::RefCell;
use std::time::SystemTime;
use std::result::Result as GenResult;
use std::io::{Error, ErrorKind};
use mime::Mime;
use bytes::BufMut;
use futures::future::{FutureExt, LocalBoxFuture};
use pi_hash::XHashMap;
use pi_handler::SGenType;
use tcp::Socket;
use crate::{service::HttpService,
route::RouterTab,
middleware::{MiddlewareResult, Middleware},
request::HttpRequest,
response::HttpResponse};
#[derive(Clone)]
pub struct GatewayContext {
params: Arc<RefCell<XHashMap<String, SGenType>>>, parts: XHashMap<String, SGenType>, cache_args: Option<(String, Mime, SystemTime)>, files_size: u64, files_len: usize, attrs: XHashMap<String, SGenType>, part_buf: Option<Vec<u8>>, }
unsafe impl Send for GatewayContext {}
unsafe impl Sync for GatewayContext {}
impl GatewayContext {
pub fn new() -> Self {
GatewayContext {
params: Arc::new(RefCell::new(XHashMap::default())),
parts: XHashMap::default(),
cache_args: None,
files_size: 0,
files_len: 0,
attrs: XHashMap::default(),
part_buf: None,
}
}
pub fn as_params(&self) -> &Arc<RefCell<XHashMap<String, SGenType>>> {
&self.params
}
pub fn clear_params(&mut self) {
self.params.borrow_mut().clear();
}
pub fn as_parts(&self) -> &XHashMap<String, SGenType> {
&self.parts
}
pub fn as_mut_parts(&mut self) -> &mut XHashMap<String, SGenType> {
&mut self.parts
}
pub fn clear_parts(&mut self) {
self.parts.clear();
}
pub fn get_cache_args(&self) -> Option<(String, Mime, SystemTime)> {
if let Some((file_path, mime, last_modified)) = &self.cache_args {
return Some((file_path.clone(), mime.clone(), last_modified.clone()));
}
None
}
pub fn set_cache_args(&mut self, args: Option<(String, Mime, SystemTime)>) {
self.cache_args = args;
}
pub fn get_files_size(&self) -> u64 {
self.files_size
}
pub fn set_files_size(&mut self, size: u64) {
self.files_size = size;
}
pub fn get_files_len(&self) -> usize {
self.files_len
}
pub fn set_files_len(&mut self, len: usize) {
self.files_len = len;
}
pub fn len(&self) -> usize {
self.attrs.len()
}
pub fn contains_key(&self, key: &String) -> bool {
self.attrs.contains_key(key)
}
pub fn get(&self, key: &String) -> Option<&SGenType> {
self.attrs.get(key)
}
pub fn set(&mut self, key: String, value: SGenType) -> Option<SGenType> {
self.attrs.insert(key, value)
}
pub fn remove(&mut self, key: &String) -> Option<SGenType> {
self.attrs.remove(key)
}
pub fn take_part_buf(&mut self) -> Option<Vec<u8>> {
self.part_buf.take()
}
pub fn push_part_buf(&mut self, buf: &[u8]) {
if let Some(part_buf) = &mut self.part_buf {
return part_buf.put_slice(buf);
}
self.part_buf = Some(Vec::from(buf));
}
}
pub struct HttpGateway<S: Socket, H: Middleware<S, GatewayContext>> {
context: GatewayContext, router_tab: Arc<RouterTab<S, GatewayContext, H>>, }
unsafe impl<S: Socket, H: Middleware<S, GatewayContext>> Send for HttpGateway<S, H> {}
unsafe impl<S: Socket, H: Middleware<S, GatewayContext>> Sync for HttpGateway<S, H> {}
impl<S: Socket, H: Middleware<S, GatewayContext>> HttpService<S> for HttpGateway<S, H> {
type Error = Error;
fn call(&mut self, req: HttpRequest<S>)
-> LocalBoxFuture<'static, GenResult<HttpResponse, Self::Error>> {
let middleware = self
.router_tab
.match_route(req.method(),
req.url().path());
let mut context = self.context.clone();
let future = async move {
if let Some(ware) = middleware {
context.clear_params(); context.set_cache_args(None); match ware.request(&mut context, req).await {
MiddlewareResult::Break(resp) => {
Ok(resp)
},
MiddlewareResult::Finish((req, resp)) => {
match ware.response(&mut context, req, resp).await {
MiddlewareResult::Break(resp) => {
Ok(resp)
},
MiddlewareResult::Finish((_, resp)) => {
Ok(resp)
},
MiddlewareResult::Throw(reason) => {
Err(reason)
},
_ => {
Err(Error::new(ErrorKind::Other,
"Invalid middleware result"))
}
}
},
MiddlewareResult::Throw(reason) => {
Err(reason)
},
_ => {
Err(Error::new(ErrorKind::Other,
"Invalid middleware result"))
},
}
} else {
Err(Error::new(ErrorKind::Other,
"Invalid route"))
}
};
future.boxed_local()
}
}
impl<S: Socket, H: Middleware<S, GatewayContext>> HttpGateway<S, H> {
pub fn with(router_tab: Arc<RouterTab<S, GatewayContext, H>>) -> Self {
HttpGateway {
context: GatewayContext::new(),
router_tab,
}
}
}