1use std::result::Result;
2
3use quicli::prelude::*;
4
5use clap_port_flag::Port;
6use futures::prelude::*;
7use hyper::{self, service::service_fn, Body, Response, Server, StatusCode};
8use mime_guess;
9use tokio;
10
11use Site;
12
13pub fn serve(site: Site, port: &Port) -> Result<(), Error> {
14 let site = Box::new(site);
15 let site: &'static Site = &*Box::leak(site);
16
17 let listener = port.bind()?;
18
19 let handle = tokio::reactor::Handle::current();
20 let listener = tokio::net::TcpListener::from_std(listener, &handle)?;
21 let addr = listener.local_addr()?;
22
23 let service = move || {
24 service_fn(move |req| {
25 let path = &req.uri().path()[1..];
26 let page = site.get(path);
27 if let Some(page) = page {
28 trace!("[200] {} {}", req.method(), req.uri());
29 Response::builder()
30 .status(StatusCode::OK)
31 .header(hyper::header::CONTENT_ENCODING, "gzip")
32 .header(hyper::header::CONTENT_DISPOSITION, "inline")
33 .header(
34 hyper::header::CONTENT_TYPE,
35 mime_guess::guess_mime_type_opt(path)
36 .map(|m| m.to_string())
37 .unwrap_or_else(|| "text/html".to_string()),
38 ).body(Body::from(page))
39 } else {
40 debug!("[404] {} {}", req.method(), req.uri());
41 Response::builder()
42 .status(StatusCode::NOT_FOUND)
43 .body(Body::from("Not found"))
44 }
45 })
46 };
47 let server = Server::builder(listener.incoming())
48 .serve(service)
49 .map_err(|e| eprintln!("server error: {}", e));
50
51 println!("Server listening on http://{}", addr);
52 tokio::run(server);
53
54 Ok(())
55}