sozu 0.9.0

sozu, a fast, reliable, hot reconfigurable HTTP reverse proxy
use clap::{App,Arg,SubCommand,ArgMatches};
use worker::begin_worker_process;
use upgrade::begin_new_master_process;

pub fn init<'a>() -> ArgMatches<'a> {
  App::new("sozu")
    .version(crate_version!())
    .about("hot reconfigurable proxy")
    .subcommand(SubCommand::with_name("start")
                .about("launch the master process")
                .arg(Arg::with_name("config")
                    .short("c")
                    .long("config")
                    .value_name("FILE")
                    .help("Sets a custom config file")
                    .takes_value(true)
                    .required(option_env!("SOZU_CONFIG").is_none())))
    .subcommand(SubCommand::with_name("worker")
                .about("start a worker (internal command, should not be used directly)")
                .arg(Arg::with_name("id").long("id")
                     .takes_value(true).required(true).help("worker identifier"))
                .arg(Arg::with_name("fd").long("fd")
                     .takes_value(true).required(true).help("IPC file descriptor"))
                .arg(Arg::with_name("scm").long("scm")
                     .takes_value(true).required(true).help("IPC SCM_RIGHTS file descriptor"))
                .arg(Arg::with_name("configuration-state-fd").long("configuration-state-fd")
                     .takes_value(true).required(true).help("configuration data file descriptor"))
                .arg(Arg::with_name("command-buffer-size").long("command-buffer-size")
                     .takes_value(true).required(true).help("Worker's channel buffer size"))
                .arg(Arg::with_name("max-command-buffer-size").long("max-command-buffer-size")
                     .takes_value(true).required(true).help("Worker's channel max buffer size")))
    .subcommand(SubCommand::with_name("upgrade")
                .about("start a new master process (internal command, should not be used directly)")
                .arg(Arg::with_name("fd").long("fd")
                     .takes_value(true).required(true).help("IPC file descriptor"))
                .arg(Arg::with_name("upgrade-fd").long("upgrade-fd")
                     .takes_value(true).required(true).help("upgrade data file descriptor"))
                .arg(Arg::with_name("command-buffer-size").long("command-buffer-size")
                     .takes_value(true).required(true).help("Master's command buffer size"))
                .arg(Arg::with_name("max-command-buffer-size").long("max-command-buffer-size")
                     .takes_value(true).required(false).help("Master's max command buffer size")))
    .get_matches()
}

pub fn get_fd<'a>(matches: &ArgMatches<'a>) -> i32 {
  matches.value_of("fd").expect("needs a file descriptor")
    .parse::<i32>().expect("the file descriptor must be a number")
}

pub fn get_scm<'a>(matches: &ArgMatches<'a>) -> i32 {
  matches.value_of("scm").expect("needs a file descriptor")
    .parse::<i32>().expect("the SCM_RIGHTS file descriptor must be a number")
}

pub fn get_configuration_state_fd<'a>(matches: &ArgMatches<'a>) -> i32 {
  matches.value_of("configuration-state-fd")
    .expect("needs a configuration state file descriptor")
    .parse::<i32>().expect("the file descriptor must be a number")
}

pub fn get_id<'a>(matches: &ArgMatches<'a>) -> i32 {
  matches.value_of("id").expect("needs a worker id")
    .parse::<i32>().expect("the worker id must be a number")
}

pub fn get_buffer_size<'a>(matches: &ArgMatches<'a>) -> usize {
  matches.value_of("command-buffer-size")
    .and_then(|size| size.parse::<usize>().ok())
    .unwrap_or(1_000_000)
}

pub fn get_max_buffer_size<'a>(matches: &ArgMatches<'a>, buffer_size: usize) -> usize {
  matches.value_of("max-command-buffer-size")
    .and_then(|size| size.parse::<usize>().ok())
    .unwrap_or(buffer_size * 2)
}

pub fn get_upgrade_fd<'a>(matches: &ArgMatches<'a>) -> i32 {
  matches.value_of("upgrade-fd").expect("needs an upgrade file descriptor")
    .parse::<i32>().expect("the file descriptor must be a number")
}

pub fn upgrade_worker<'a>(matches: &ArgMatches<'a>) -> Option<()> {
  matches.subcommand_matches("worker").and_then(|worker_matches| {
    let fd = get_fd(worker_matches);
    let scm = get_scm(worker_matches);
    let configuration_state_fd = get_configuration_state_fd(worker_matches);
    let id = get_id(worker_matches);
    let buffer_size = get_buffer_size(worker_matches);
    let max_buffer_size = get_max_buffer_size(worker_matches, buffer_size);

    begin_worker_process(fd, scm, configuration_state_fd, id, buffer_size, max_buffer_size);
    Some(())
  })
}

pub fn upgrade_master<'a>(matches: &ArgMatches<'a>) -> Option<()> {
 matches.subcommand_matches("upgrade").and_then(|upgrade_matches| {
    let fd = get_fd(upgrade_matches);
    let upgrade_fd = get_upgrade_fd(upgrade_matches);
    let buffer_size = get_buffer_size(upgrade_matches);
    let max_buffer_size = get_max_buffer_size(upgrade_matches, buffer_size);

    begin_new_master_process(fd, upgrade_fd, buffer_size, max_buffer_size);
    Some(())
  })
}