use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
use hyper;
use hyper::body::Body as HyperBody;
use hyper::http::Request as HyperRequest;
use hyper::http::Response as HyperResponse;
use hyper::service::Service as HyperService;
use crate::CommunicationChannel;
use crate::{errors::RhodError, RhodConnInfo, RhodHandlerInStack, RhodRequest, RhodStack};
type SecureFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
pub struct RhodHyperService<C> {
stack: Arc<RhodStack<C>>,
conn: RhodConnInfo,
}
impl<C> RhodHyperService<C> {
pub fn new(stack: Arc<RhodStack<C>>, conn: RhodConnInfo) -> RhodHyperService<C> {
RhodHyperService { stack, conn }
}
}
impl<C: CommunicationChannel> HyperService<HyperRequest<HyperBody>> for RhodHyperService<C> {
type Response = HyperResponse<HyperBody>;
type Error = RhodError;
type Future = SecureFuture<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, h_req: HyperRequest<HyperBody>) -> Self::Future {
let stack = Arc::clone(&self.stack);
let conn = self.conn.clone();
Box::pin(async move {
let mut req = RhodRequest::new(h_req);
let mut err = None;
let mut dyn_handlers = vec![];
let mut counter: usize = 0;
let mut communication = C::new();
for handler in stack.handlers.iter() {
let handler = match handler {
RhodHandlerInStack::DynamicRhodHandler(dyn_handler) => {
let aux = dyn_handler
.get_handler(&conn, &req, &mut communication)
.await;
dyn_handlers.push(aux);
counter += 1;
aux
}
RhodHandlerInStack::RhodHandler(handler) => &**handler,
};
match &err {
None => match handler
.handle_request(&conn, &mut req, &mut communication)
.await
{
Ok(()) => (),
Err(e) => {
e.log();
err = Some(e);
}
},
Some(e) => {
handler.catch_request(&conn, &req, e, &communication).await;
}
}
}
if let Some(e) = err {
return Err(e);
}
match stack.service.serve(&conn, req, &mut communication).await {
Ok(mut res) => {
for handler in stack.handlers.iter().rev() {
let handler = match handler {
RhodHandlerInStack::DynamicRhodHandler(_) => {
counter -= 1;
dyn_handlers[counter]
}
RhodHandlerInStack::RhodHandler(handler) => &**handler,
};
match &err {
None => match handler
.handle_response(&conn, res, &mut communication)
.await
{
(new_res, Ok(())) => res = new_res,
(new_res, Err(e)) => {
res = new_res;
e.log();
err = Some(e);
}
},
Some(e) => {
handler.catch_response(&conn, &res, e, &communication).await;
}
}
}
if let Some(e) = err {
return Err(e);
}
Ok(res.into_hyper_response())
}
Err(e) => {
e.log();
Err(e)
}
}
})
}
}