Refactor hyper router

* Make it simpler to implement middleware
* Switch from the current thread runtime to the default one. It enables us to inject TLS support later one and potentially more scalable, unfortunately it involves some additonal cloning of the router, because we can't rely on thread local vars anymore
* Introduce `call` entrypoint for Handler, so it's possible to handle any HTTP method in one place, handy for middleware
* Implement example of middleware
This commit is contained in:
hashmap
2018-09-19 17:10:52 +02:00
parent ba72e6e29e
commit d5ef3d9d12
4 changed files with 90 additions and 105 deletions
+28 -13
View File
@@ -19,14 +19,13 @@
//! register them on a ApiServer.
use hyper::rt::Future;
use hyper::service::service_fn;
use hyper::{Body, Request, Server};
use router::ResponseFuture;
use hyper::{rt, Body, Request, Server};
use router::{Handler, HandlerObj, ResponseFuture, Router};
use std::fmt::{self, Display};
use std::net::SocketAddr;
use tokio::runtime::current_thread::Runtime;
use failure::{Backtrace, Context, Fail};
use util::LOGGER;
/// Errors that can be returned by an ApiEndpoint implementation.
#[derive(Debug)]
@@ -95,18 +94,16 @@ impl ApiServer {
}
/// Starts the ApiServer at the provided address.
pub fn start<F>(&mut self, addr: SocketAddr, f: &'static F) -> Result<(), String>
where
F: Fn(Request<Body>) -> ResponseFuture + Send + Sync + 'static,
{
pub fn start(&mut self, addr: SocketAddr, router: Router) -> Result<(), String> {
let server = Server::bind(&addr)
.serve(move || service_fn(f))
.serve(router)
.map_err(|e| eprintln!("server error: {}", e));
let mut rt = Runtime::new().unwrap();
if rt.block_on(server).is_err() {
return Err("tokio block_on error".to_owned());
}
//let mut rt = Runtime::new().unwrap();
//if rt.block_on(server).is_err() {
// return Err("tokio block_on error".to_owned());
//}
rt::run(server);
Ok(())
}
@@ -119,3 +116,21 @@ impl ApiServer {
// }
}
}
// Simple example of middleware
pub struct LoggingMiddleware {
next: HandlerObj,
}
impl LoggingMiddleware {
pub fn new(next: HandlerObj) -> LoggingMiddleware {
LoggingMiddleware { next }
}
}
impl Handler for LoggingMiddleware {
fn call(&self, req: Request<Body>) -> ResponseFuture {
debug!(LOGGER, "REST call: {} {}", req.method(), req.uri().path());
self.next.call(req)
}
}