use iron::prelude::*;
use iron::{BeforeMiddleware, AfterMiddleware, typemap};
use std::time::SystemTime;

struct ResponseTime;

impl typemap::Key for ResponseTime { type Value = u128; }

impl BeforeMiddleware for ResponseTime {
    fn before(&self, req: &mut Request) -> IronResult<()> {
       req.extensions.insert::<ResponseTime>(get_time_in_nanos());
        Ok(())
    }
}

impl AfterMiddleware for ResponseTime {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        let delta = get_time_in_nanos() - *req.extensions.get::<ResponseTime>().unwrap();
        println!("Request: {}, took: {} ms", req.url, (delta as f64) / 1000000.0);
        Ok(res)
    }
}

fn get_time_in_nanos() -> u128 {
    SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos()
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((iron::status::Ok, "Hello World\n")))
}

fn main() {
    let mut chain = Chain::new(hello_world);
    chain.link_before(ResponseTime);
    chain.link_after(ResponseTime);
    println!("Listen on: 127.0.0.1:8080");
    Iron::new(chain).http("127.0.0.1:8080").unwrap();
}
