feat: termination signal manager (resolves #13)
Diff
Cargo.lock | 29 +++++++++++++--------------
Cargo.toml | 3 ++-
src/main.rs | 34 ++++++++++++++------------------
src/signal_manager.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 88 insertions(+), 34 deletions(-)
@@ -157,16 +157,6 @@ dependencies = [
]
[[package]]
name = "ctrlc"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a4ba686dff9fa4c1c9636ce1010b0cf98ceb421361b0bb3d6faeec43bd217a7"
dependencies = [
"nix",
"winapi",
]
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -316,7 +306,7 @@ dependencies = [
[[package]]
name = "iron_staticfile_middleware"
version = "0.2.0"
source = "git+https://github.com/joseluisq/iron-staticfile-middleware.git#562b241a80a7e216ccdbe1d4d603f1a0b621d5b1"
source = "git+https://github.com/joseluisq/iron-staticfile-middleware.git#4e02bc6eda9cf88bf4b7866581ae83efda7f3110"
dependencies = [
"iron",
"log 0.4.8",
@@ -431,9 +421,9 @@ dependencies = [
[[package]]
name = "nix"
version = "0.17.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
dependencies = [
"bitflags",
"cc",
@@ -863,6 +853,16 @@ dependencies = [
]
[[package]]
name = "signal"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f6ce83b159ab6984d2419f495134972b48754d13ff2e3f8c998339942b56ed9"
dependencies = [
"libc",
"nix",
]
[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -879,14 +879,15 @@ name = "static-web-server"
version = "1.5.0"
dependencies = [
"chrono",
"ctrlc",
"env_logger",
"flate2",
"hyper-native-tls",
"iron",
"iron_staticfile_middleware",
"log 0.4.8",
"nix",
"openssl",
"signal",
"structopt",
]
@@ -29,7 +29,8 @@ structopt = "0.3"
flate2 = "1.0"
iron_staticfile_middleware = { git = "https://github.com/joseluisq/iron-staticfile-middleware.git" }
hyper-native-tls = "0.3"
ctrlc = "3.1"
nix = "0.14"
signal = "0.7"
[dev-dependencies]
openssl = { version = "0.10", features = ["vendored"] }
@@ -1,10 +1,11 @@
extern crate chrono;
extern crate ctrlc;
extern crate env_logger;
extern crate flate2;
extern crate hyper_native_tls;
extern crate iron;
extern crate iron_staticfile_middleware;
extern crate nix;
extern crate signal;
#[macro_use]
extern crate log;
@@ -14,6 +15,7 @@ mod config;
mod error_page;
mod gzip;
mod logger;
mod signal_manager;
mod staticfiles;
use crate::config::Options;
@@ -24,21 +26,23 @@ use iron::prelude::*;
use log::LevelFilter;
use staticfiles::*;
use std::io::Write;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use structopt::StructOpt;
fn on_server_running(server_name: &str, proto: &str, addr: &str, running: Arc<AtomicBool>) {
fn on_server_running(server_name: &str, proto: &str, addr: &str) {
info!(
"Static {} Server `{}` is running on {}",
proto, server_name, addr
);
println!("Waiting for Ctrl-C signal...");
while running.load(Ordering::SeqCst) {}
signal_manager::wait_for_signal(|sig: signal::Signal| {
let code = signal_manager::signal_to_int(sig);
println!("Exiting server execution...");
std::process::exit(0)
println!();
warn!("SIGINT {} caught. HTTP Server execution exited.", code);
std::process::exit(code)
})
}
fn main() {
@@ -59,16 +63,8 @@ fn main() {
let addr = &format!("{}{}{}", opts.host.to_string(), ":", opts.port.to_string());
let proto = if opts.tls { "HTTPS" } else { "HTTP" };
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
let files = StaticFiles::new(StaticFilesOptions {
root_dir: opts.root,
assets_dir: opts.assets,
@@ -80,12 +76,12 @@ fn main() {
let ssl = NativeTlsServer::new(opts.tls_pkcs12, &opts.tls_pkcs12_passwd).unwrap();
match Iron::new(files.handle()).https(addr, ssl) {
Result::Ok(_) => on_server_running(&opts.name, &proto, addr, running),
Result::Ok(_) => on_server_running(&opts.name, &proto, addr),
Result::Err(err) => panic!("{:?}", err),
}
} else {
match Iron::new(files.handle()).http(addr) {
Result::Ok(_) => on_server_running(&opts.name, &proto, addr, running),
Result::Ok(_) => on_server_running(&opts.name, &proto, addr),
Result::Err(err) => panic!("{:?}", err),
}
}
@@ -0,0 +1,56 @@
use nix::errno::Errno;
use nix::libc::c_int;
use nix::sys::signal::{SIGCHLD, SIGINT, SIGTERM};
use nix::sys::wait::WaitStatus::{Exited, Signaled, StillAlive};
use nix::sys::wait::{waitpid, WaitPidFlag};
use nix::Error;
use signal::trap::Trap;
pub fn wait_for_signal<F>(f: F)
where
F: Fn(signal::Signal),
{
let signal_trap = Trap::trap(&[SIGTERM, SIGINT, SIGCHLD]);
for sig in signal_trap {
match sig {
SIGCHLD => {
loop {
match waitpid(None, Some(WaitPidFlag::WNOHANG)) {
Ok(Exited(pid, status)) => {
println!("{} exited with status {}", pid, status);
continue;
}
Ok(Signaled(pid, sig, _)) => {
println!("{} killed by {}", pid, sig as c_int);
continue;
}
Ok(StillAlive) => {
break;
}
Ok(status) => {
println!("Temporary status {:?}", status);
continue;
}
Err(Error::Sys(Errno::ECHILD)) => {
return;
}
Err(e) => {
panic!("Error {:?}", e);
}
}
}
}
sig => f(sig),
}
}
}
pub fn signal_to_int(sig: signal::Signal) -> i32 {
sig as c_int
}