static-filez 0.1.0

Build compressed archives for static files and serve them over HTTP
Documentation
use std::result::Result;

use quicli::prelude::*;

use clap_port_flag::Port;
use futures::prelude::*;
use hyper::{self, service::service_fn, Body, Response, Server, StatusCode};
use mime_guess;
use tokio;

use Site;

pub fn serve(site: Site, port: &Port) -> Result<(), Error> {
    let site = Box::new(site);
    let site: &'static Site = &*Box::leak(site);

    let listener = port.bind()?;

    let handle = tokio::reactor::Handle::current();
    let listener = tokio::net::TcpListener::from_std(listener, &handle)?;
    let addr = listener.local_addr()?;

    let service = move || {
        service_fn(move |req| {
            let path = &req.uri().path()[1..];
            let page = site.get(path);
            if let Some(page) = page {
                trace!("[200] {} {}", req.method(), req.uri());
                Response::builder()
                    .status(StatusCode::OK)
                    .header(hyper::header::CONTENT_ENCODING, "gzip")
                    .header(hyper::header::CONTENT_DISPOSITION, "inline")
                    .header(
                        hyper::header::CONTENT_TYPE,
                        mime_guess::guess_mime_type_opt(path)
                            .map(|m| m.to_string())
                            .unwrap_or_else(|| "text/html".to_string()),
                    ).body(Body::from(page))
            } else {
                debug!("[404] {} {}", req.method(), req.uri());
                Response::builder()
                    .status(StatusCode::NOT_FOUND)
                    .body(Body::from("Not found"))
            }
        })
    };
    let server = Server::builder(listener.incoming())
        .serve(service)
        .map_err(|e| eprintln!("server error: {}", e));

    println!("Server listening on http://{}", addr);
    tokio::run(server);

    Ok(())
}