extern crate futures;
extern crate http;
extern crate hyper;
use futures::future::{self, Future};
use hyper::Body;
use hyper::server::{Request, Response, Service};
pub type LuminalFuture = Box<Future<Item = Response, Error = hyper::Error>>;
pub trait Handler {
fn handle(&self, req: http::Request<Body>) -> Result<LuminalFuture, Response>;
}
pub struct HandlerService<H: Handler> {
handler: H,
}
impl<H: Handler> HandlerService<H> {
pub fn new(handler: H) -> Self {
HandlerService { handler }
}
}
impl<H: Handler> Service for HandlerService<H> {
type Request = Request;
type Response = Response;
type Error = hyper::Error;
type Future = LuminalFuture;
fn call(&self, request: Request) -> Self::Future {
match self.handler.handle(request.into()) {
Ok(response) => response,
Err(error) => Box::new(future::ok(error)),
}
}
}
pub fn handler_fn<F>(func: F) -> HandlerFn<F>
where
F: Fn(http::Request<Body>) -> Result<LuminalFuture, Response>,
{
HandlerFn { func }
}
pub struct HandlerFn<F>
where
F: Fn(http::Request<Body>) -> Result<LuminalFuture, Response>,
{
func: F,
}
impl<F> Handler for HandlerFn<F>
where
F: Fn(http::Request<Body>) -> Result<LuminalFuture, Response>,
{
fn handle(&self, req: http::Request<Body>) -> Result<LuminalFuture, Response> {
(self.func)(req)
}
}
#[cfg(test)]
mod tests {
extern crate tokio_core;
use futures::Stream;
use hyper::Method;
use hyper::{Body, StatusCode};
use self::tokio_core::reactor::Core;
use super::*;
enum TestHandler {
Success(String),
Failure(String),
}
impl Handler for TestHandler {
fn handle(&self, _request: http::Request<Body>) -> Result<LuminalFuture, Response> {
match *self {
TestHandler::Success(ref body) => {
let body: String = body.clone();
Ok(Box::new(futures::future::ok(
Response::new().with_status(StatusCode::Ok).with_body(body),
)))
}
TestHandler::Failure(ref error) => {
let body: String = error.clone();
Err(Response::new()
.with_status(StatusCode::InternalServerError)
.with_body(body))
}
}
}
}
fn test_fn(_req: http::Request<Body>) -> Result<LuminalFuture, Response> {
Ok(Box::new(futures::future::ok(
Response::new()
.with_status(StatusCode::Ok)
.with_body(String::from("test")),
)))
}
#[test]
fn test_success() {
let handler = TestHandler::Success(String::from("Success"));
let service = HandlerService::new(handler);
assert_call(&service, Method::Get, "/foo", (&StatusCode::Ok, "Success"));
}
#[test]
fn test_failure() {
let handler = TestHandler::Failure(String::from("Error"));
let service = HandlerService::new(handler);
assert_call(
&service,
Method::Get,
"/foo",
(&StatusCode::InternalServerError, "Error"),
);
}
#[test]
fn test_handler_fn() {
let handler = handler_fn(test_fn);
let service = HandlerService::new(handler);
assert_call(&service, Method::Get, "/foo", (&StatusCode::Ok, "test"));
}
fn assert_call<H>(
service: &HandlerService<H>,
method: Method,
uri: &str,
expected: (&StatusCode, &str),
) where
H: Handler,
{
let uri = uri.parse()
.expect("Should have been able to convert to uri");
let req: Request<Body> = Request::new(method, uri);
let work = service.call(req);
let mut core = Core::new().expect("Should have been able to create core");
let response = core.run(work)
.expect("Should have been able to run router call");
assert_eq!(
*expected.0,
response.status(),
"Should have received {} status.",
expected.0
);
let body = core.run(response.body().concat2())
.expect("Should have been able to resolve body concat");
let body: &[u8] = &body.to_vec();
assert_eq!(
expected.1.as_bytes(),
body,
"Should have received correct body content"
);
}
}