index : static-web-server.git

ascending towards madness

author Jose Quintana <joseluisquintana20@gmail.com> 2021-01-07 0:34:01.0 +00:00:00
committer Jose Quintana <joseluisquintana20@gmail.com> 2021-01-07 0:34:01.0 +00:00:00
commit
bbe6ed8bc2b39da45394ab0203e6dc13739a5eb5 [patch]
tree
4a18c5fa72efa2b088f9fb344de13b2035759132
parent
f40e332175c46612c96b06871a6014d8cf78495e
download
bbe6ed8bc2b39da45394ab0203e6dc13739a5eb5.tar.gz

feat: termination signals support



Diff

 src/bin/server.rs          | 13 +++++++----
 src/core/mod.rs            |  4 +--
 src/core/signal_manager.rs | 56 +-----------------------------------------------
 src/core/signals.rs        | 51 +++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 62 insertions(+), 62 deletions(-)

diff --git a/src/bin/server.rs b/src/bin/server.rs
index 4f17f92..6254d82 100644
--- a/src/bin/server.rs
+++ b/src/bin/server.rs
@@ -7,7 +7,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
extern crate static_web_server;

use structopt::StructOpt;
use tracing::info;
use tracing::warn;
use warp::Filter;

use self::static_web_server::core::*;
@@ -22,11 +22,16 @@ async fn server(opts: config::Options) -> Result {
        .recover(rejection::handle_rejection)
        .with(warp::trace::request());

    info!("listening on http://[{}]:{}", &opts.host, &opts.port);

    let host = opts.host.parse::<std::net::IpAddr>()?;
    let port = opts.port;

    tokio::task::spawn(warp::serve(filters).run((host, port)));

    warp::serve(filters).run((host, opts.port)).await;
    signals::wait(|sig: signals::Signal| {
        let code = signals::as_int(sig);
        warn!("Signal {} caught. Server execution exited.", code);
        std::process::exit(code)
    });

    Ok(())
}
diff --git a/src/core/mod.rs b/src/core/mod.rs
index e68fe1d..161938e 100644
--- a/src/core/mod.rs
+++ b/src/core/mod.rs
@@ -2,9 +2,9 @@ pub mod config;
pub mod helpers;
pub mod logger;
pub mod rejection;
pub mod signal_manager;
pub mod signals;

#[macro_use]
pub mod result;

pub use crate::core::result::*;
pub use result::*;
diff --git a/src/core/signal_manager.rs b/src/core/signal_manager.rs
deleted file mode 100644
index 06be40c..0000000
--- a/src/core/signal_manager.rs
+++ /dev/null
@@ -1,56 +0,0 @@
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;

/// It waits for an incoming Termination Signal like Ctrl+C (SIGINT), SIGTERM, etc
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 => {
                // Current std::process::Command ip does not have a way to find
                // process id, so we just wait until we have no children
                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),
        }
    }
}

/// It casts a `signal::Signal` to `i32`
pub fn signal_to_int(sig: signal::Signal) -> i32 {
    sig as c_int
}
diff --git a/src/core/signals.rs b/src/core/signals.rs
new file mode 100644
index 0000000..6947b11
--- /dev/null
+++ b/src/core/signals.rs
@@ -0,0 +1,51 @@
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;

pub use signal::Signal;

/// It waits for an incoming Termination Signal like Ctrl+C (SIGINT), SIGTERM, etc
pub fn wait<F>(func: F)
where
    F: Fn(signal::Signal),
{
    let sig_trap = signal::trap::Trap::trap(&[SIGTERM, SIGINT, SIGCHLD]);
    for sig in sig_trap {
        match sig {
            SIGCHLD => {
                // Current std::process::Command ip does not have a way to find
                // process id, so we just wait until we have no children
                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 => func(sig),
        }
    }
}

/// It casts a given `signal::Signal` to `i32`.
pub fn as_int(sig: signal::Signal) -> i32 {
    sig as c_int
}