mod request;
mod response;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use futures::{future, Future};
use http;
use tiny_http;
use tokio_threadpool::ThreadPool;
use self::request::as_http_request;
use self::response::as_tiny_http_response;
use {Body, Handler, Responder, Result};
pub struct Server<H, ReqBody>
where
H: Handler<ReqBody>,
ReqBody: Body,
{
server: tiny_http::Server,
handler: Arc<H>,
marker: PhantomData<ReqBody>,
}
impl<H, ReqBody> Server<H, ReqBody>
where
H: Handler<ReqBody>,
ReqBody: Body,
{
pub fn new(addr: SocketAddr, handler: H) -> Result<Server<H, ReqBody>> {
let server = tiny_http::Server::http(addr)?;
let handler = Arc::new(handler);
let marker = PhantomData;
Ok(Server {
server,
handler,
marker,
})
}
pub fn addr(&self) -> SocketAddr {
self.server.server_addr()
}
pub fn run(self) -> Result<()> {
let pool = ThreadPool::new();
loop {
let req = match self.server.recv() {
Ok(req) => req,
Err(e) => {
eprintln!("Server error: {}", e);
continue;
}
};
let handler = self.handler.clone();
pool.spawn(future::lazy(move || Server::process_request(handler, req)));
}
}
fn process_request(
handler: Arc<H>,
mut req: tiny_http::Request,
) -> impl Future<Item = (), Error = ()> {
let http_request = as_http_request(&mut req);
future::lazy(move || Ok(http_request?.into_parts()))
.and_then(|(parts, body)| {
body.into_body::<ReqBody>()
.map(move |body| http::Request::from_parts(parts, body))
})
.and_then(move |http_request| {
handler
.handle(http_request, http::Response::builder())
.into_response()
})
.and_then(as_tiny_http_response)
.and_then(move |resp| {
req.respond(resp)?;
Ok(())
})
.or_else(|err| {
eprintln!("Server error processing request: {}", err);
Ok(())
})
}
}