static_filez/
server.rs

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}