isner 0.0.1-alpha.2

A static HTTP server that aims to be minimalistic and fast.
Documentation
use std::net::{TcpListener, ToSocketAddrs};
use std::path::Path;

use anyhow::{Context, Error};
use clap::{App, Arg};
use fehler::throws;
use threadpool::ThreadPool;

use isner::connection_handler::run;
use isner::file_handler::FileHandler;

const DEFAULT_HOST: &str = "127.0.0.1";
const DEFAULT_PORT: &str = "8000";
const DEFAULT_CONCURRENCY: &str = "10";

fn build_args<'a>() -> App<'a, 'a> {
    App::new("isner")
        .version("0.0.1-alpha.1")
        .author("Elias Tandel <elias.tandel@gmail.com>")
        .about("Simple file server in rust")
        .arg(
            Arg::with_name("host")
                .help("Address to which the server will be bound")
                .short("h")
                .long("host")
                .value_name("ADDRESS")
                .default_value(DEFAULT_HOST),
        )
        .arg(
            Arg::with_name("port")
                .help("Port to which the server will be bound")
                .short("p")
                .long("port")
                .value_name("PORT")
                .default_value(DEFAULT_PORT),
        )
        .arg(
            Arg::with_name("concurrency")
                .help("Maximum number of concurrent requests")
                .short("c")
                .long("concurrency")
                .default_value(DEFAULT_CONCURRENCY),
        )
        .arg(
            Arg::with_name("directory")
                .help("Root directory")
                .short("d")
                .long("directory")
                .value_name("DIR")
                .required(true)
        )
}

#[throws]
fn main() {
    env_logger::init();

    let matches = build_args().get_matches();

    let listener = {
        let host = matches.value_of("host").unwrap_or(DEFAULT_HOST);
        let port = matches
            .value_of("port")
            .unwrap_or(DEFAULT_PORT)
            .parse::<u16>()?;
        let mut addrs_iter = (host, port).to_socket_addrs().context("Invalid address")?;
        let bind_to = addrs_iter.next().context("Invalid address")?;

        TcpListener::bind(bind_to).with_context(|| format!("Could not bind to {}", bind_to))?
    };

    let pool = {
        let pool_size = matches
            .value_of("concurrency")
            .unwrap_or(DEFAULT_CONCURRENCY)
            .parse::<usize>()
            .context("concurrency value must be integer")?;
        ThreadPool::new(pool_size)
    };

    let root_dir = matches.value_of("directory").unwrap();
    let handler = FileHandler::new(Path::new(root_dir).to_owned());

    run(listener, pool, handler);
}