extern crate fisher;
extern crate nix;
extern crate toml;
use std::fs;
use std::io::Read;
use std::path::Path;
use fisher::*;
use nix::sys::signal::{Signal, SigSet};
static VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
fn show_version() {
if let Some(version) = VERSION {
println!("Fisher {}", version);
} else {
println!("Fisher (version unknown)");
}
}
fn usage(exit_code: i32, error_msg: &str) -> ! {
if error_msg.len() > 0 {
println!("Error: {}\n", error_msg);
}
println!("Usage: fisher <config_file>");
println!("Execute `fisher --help` for more details");
::std::process::exit(exit_code);
}
fn parse_cli() -> String {
let mut only_args = false;
let mut flag_help = false;
let mut flag_version = false;
let mut config_path = None;
for arg in ::std::env::args().skip(1) {
if !only_args && arg.chars().next() == Some('-') {
match arg.as_str() {
"--" => only_args = true,
"-h" | "--help" => flag_help = true,
"--version" => flag_version = true,
_ => usage(1, &format!("invalid flag: {}", arg)),
}
} else if config_path.is_none() {
config_path = Some(arg);
} else {
usage(1, &format!("unexpected argument: {}", arg));
}
}
if flag_help {
show_version();
println!("Simple webhooks catcher\n");
println!("ARGUMENTS");
println!(" config_path The path to the configuration file");
println!();
println!("OPTIONS");
println!(" -h | --help Show this message");
println!(" --version Show the Fisher version");
::std::process::exit(0);
} else if flag_version {
show_version();
::std::process::exit(0);
} else if let Some(path) = config_path {
path
} else {
usage(1, "too few arguments");
}
}
fn read_config<P: AsRef<Path>>(path: P) -> Result<Config> {
let mut file = fs::File::open(path)?;
let mut buffer = String::new();
file.read_to_string(&mut buffer)?;
Ok(toml::from_str(&buffer).map_err(|e| {
Error::from_kind(ErrorKind::BoxedError(Box::new(e)).into())
})?)
}
fn app() -> Result<()> {
let mut signals = SigSet::empty();
signals.add(Signal::SIGINT);
signals.add(Signal::SIGTERM);
signals.add(Signal::SIGUSR1);
signals.thread_block()?;
let config_path = parse_cli();
let mut app = Fisher::new(read_config(&config_path)?)?;
println!("HTTP server listening on {}", app.web_address().unwrap());
loop {
match signals.wait()? {
Signal::SIGINT | Signal::SIGTERM => break,
Signal::SIGUSR1 => {
println!("Reloading configuration and scripts...");
match read_config(&config_path) {
Ok(new_config) => {
if let Err(err) = app.reload(new_config) {
err.pretty_print()
}
}
Err(err) => err.pretty_print(),
}
}
_ => {}
}
}
app.stop()?;
Ok(())
}
fn main() {
if let Err(err) = app() {
err.pretty_print();
std::process::exit(1);
}
}