use super::{rootservice::RootService, Request, Response};
use contrib::BodyParser;
use futures::{Future, Stream};
use hyper::server::conn::Http;
use native_tls::TlsAcceptor;
use proto::{ArcHandler, ArcService, MiddleWare};
use routing::Router;
use std::{io, sync::Arc};
use tokio::{self, net::TcpListener};
use tokio_tls::TlsAcceptorExt;
pub struct ArcReactor {
port: i16,
arc_handler: ArcHandler,
tls_acceptor: Option<Arc<TlsAcceptor>>,
}
impl Default for ArcReactor {
fn default() -> Self {
ArcReactor {
port: 8080,
arc_handler: ArcHandler {
before: Some(mw![BodyParser]),
after: None,
handler: None,
},
tls_acceptor: None,
}
}
}
impl ArcReactor {
pub fn new() -> Self {
ArcReactor::default()
}
pub fn port(mut self, port: i16) -> Self {
self.port = port;
self
}
pub fn tls(mut self, acceptor: TlsAcceptor) -> Self {
self.tls_acceptor = Some(Arc::new(acceptor));
self
}
pub fn routes(mut self, routes: Router) -> Self {
let routes = Box::new(routes) as Box<ArcService>;
self.arc_handler.handler = Some(routes);
self
}
pub fn service<S: ArcService + 'static>(mut self, service: S) -> Self {
let service = Box::new(service) as Box<ArcService>;
self.arc_handler.handler = Some(service);
self
}
pub fn before<M>(mut self, before: M) -> Self
where
M: MiddleWare<Request> + 'static,
{
self.arc_handler.before = Some(Box::new(before));
self
}
pub fn after<M>(mut self, after: M) -> Self
where
M: MiddleWare<Response> + 'static,
{
self.arc_handler.after = Some(Box::new(after));
self
}
pub fn start(self) -> Result<impl Future<Item = (), Error = ()> + Send, io::Error> {
let ArcReactor {
port,
arc_handler,
tls_acceptor: acceptor,
} = self;
let addr = format!("0.0.0.0:{}", port).parse().unwrap();
info!("Binding to port {}", port);
let listener = TcpListener::bind(&addr)?;
let http = Http::new();
let conn_stream_future = listener
.incoming()
.map_err(|err| error!("error accepting connection: {}", err))
.for_each(move |socket| {
let service = arc_handler.clone();
let remote_ip = socket.peer_addr().ok();
if let Some(ref acceptor) = acceptor {
let http_clone = http.clone();
let connection_future = acceptor
.accept_async(socket)
.map_err(|err| error!("TLS Handshake Error: {}", err))
.and_then(move |socket| {
http_clone
.serve_connection(socket, RootService { service, remote_ip })
.map_err(|err| error!("serve_connection Error: {}", err))
.and_then(|_| Ok(()))
});
tokio::spawn(connection_future);
} else {
let connection_future = http
.serve_connection(socket, RootService { service, remote_ip })
.map_err(|err| error!("serve_connection Error: {}", err))
.and_then(|_| Ok(()));
tokio::spawn(connection_future);
}
Ok(())
});
Ok(conn_stream_future)
}
}