Skip to content

Commit

Permalink
doc: Improves documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ignlg committed Apr 17, 2020
1 parent 4deba54 commit ead2147
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 30 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pingkeeper"
description = """
Command line application that monitors network (direct connection or ping) and, in case of failure, runs a command. Optionally it can monitor that the command is permanently running and restart it if network is unreachable.
Command line application that monitorises that network is reachable (direct tcp connection or ping) and, in case of failure, runs a command. Optionally it can monitor that the command is permanently running and restart it if network is unreachable.
"""
version = "3.0.0"
authors = ["Ignacio Lago <[email protected]>"]
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# pingkeeper

[![Build Status](https://travis-ci.org/ignlg/pingkeeper.svg?branch=master)](https://travis-ci.org/ignlg/pingkeeper)
[![Latest version](https://img.shields.io/crates/v/online.svg)](https://crates.io/crates/online)
![Stability stable](https://img.shields.io/badge/stability-stable-green.svg)

Command line application that monitors network (direct connection or ping) and, in case of failure, runs a command. Optionally it can monitor that the command is permanently running and restart it if network is unreachable.
Command line application that monitorises that network is reachable (direct tcp connection or ping) and, in case of failure, runs a command. Optionally it can monitor that the command is permanently running and restart it if network is unreachable.

Proudly made from Barcelona with Rust 🦀.

Expand Down Expand Up @@ -79,6 +81,7 @@ ARGS:
- [x] opt `--use-ping`, use system ping instead of direct connection.
- [x] opt `-t --timeout`, seconds waiting for network connection.
- [x] opt `--max-errors`, number of keep-alive errors allowed in a row to keep running.
- [x] improve documentation.

### v2.0.0

Expand All @@ -104,15 +107,15 @@ ARGS:

## Backlog

- [ ] improve documentation.
- [ ] export lib too.
- [ ] opt `--kill-cmd`, custom kill command.
- [ ] opt `--check-cmd`, custom check network command.

- [ ] pingkeeper tests with mocks.
- [ ] website.
- [ ] LaunchDaemon generator.
- [ ] macOS notifications: connection lost, connection recovered.
- [ ] opt `--disable-notifications`.

- [ ] detect SIGTERM on subprocess and stop.
- [ ] write pid to proc.
- [ ] opt `-f --force` to kill pid and remove pid from proc.
Expand Down
2 changes: 2 additions & 0 deletions src/pingkeeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use network_monitor::NetworkMonitor;
mod logger;
use logger::{logger, LogLevel};

/// Pingkeeper errors
#[derive(Debug, Eq, PartialEq)]
pub enum PingkeeperError {
NoHostsToPing,
Expand All @@ -41,6 +42,7 @@ pub enum PingkeeperError {
/// Time between loops
const CHECK_MS: usize = 100;

/// Monitorises that network is reachable and, in case of failure, runs a command
pub fn pingkeeper(opt: Opt) -> Result<(), PingkeeperError> {
// logger
let logger = if !opt.quiet {
Expand Down
10 changes: 5 additions & 5 deletions src/pingkeeper/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct Executor {

// Public impl
impl Executor {
/// Create a new Executor instance
/// Creates a new Executor instance
pub fn new(command: String) -> Self {
Self {
command,
Expand All @@ -55,7 +55,7 @@ impl Executor {
error: None,
}
}
/// Spawn a child process
/// Spawns a child process
pub fn execute(&mut self, quiet: bool) -> bool {
let mut cmd = process::Command::new("/bin/sh");
cmd.arg("-c").arg(&self.command);
Expand All @@ -77,7 +77,7 @@ impl Executor {
}
}
}
/// Send signal to child process, if any
/// Sends kill signal to child process, if any
pub fn kill(&mut self) -> Result<(), ExecutorError> {
if let Some(child) = &mut self.child {
if kill(Pid::from_raw(child.id() as i32), self.signal).is_err() {
Expand All @@ -100,7 +100,7 @@ impl Executor {
}
Ok(false)
}
/// Get child process PID, if any
/// Gets child process PID, if any
pub fn get_pid(&mut self) -> Option<u32> {
if let Ok(is_alive) = self.is_alive() {
if is_alive {
Expand All @@ -111,7 +111,7 @@ impl Executor {
}
None
}
/// Set signal
/// Sets kill signal
pub fn set_signal(&mut self, signal: &str) {
if let Ok(signal) = Signal::from_str(signal) {
self.signal = Some(signal);
Expand Down
3 changes: 2 additions & 1 deletion src/pingkeeper/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/// Verbosity levels
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd)]
pub enum LogLevel {
QUIET = 0,
Expand All @@ -37,7 +38,7 @@ impl From<u32> for LogLevel {
}
}

/// Filter and write output to stdout/stderr
/// Returns a logger function that writes message to stdout/stderr if verbosity level allows it
pub fn logger(verbose: LogLevel) -> impl Fn(LogLevel, String) -> () {
move |level: LogLevel, message: String| match (level, verbose) {
(LogLevel::ERROR, v) if v >= LogLevel::ERROR => eprintln!("PK error: {}", message),
Expand Down
49 changes: 29 additions & 20 deletions src/pingkeeper/network_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::time::Duration;

const DEFAULT_TIMEOUT: u64 = 2;

/// Ping errors
/// Network monitor errors
#[derive(Debug, PartialEq, Eq)]
pub enum NetworkError {
NetworkUnreachable,
Expand All @@ -34,7 +34,7 @@ pub enum NetworkError {
InvalidTimeout,
}

/// Ping a host and return if it is reachable
/// Pings a host and returns if it is reachable
fn ping(ping_opt: &str, host: &str) -> bool {
process::Command::new("/bin/sh")
.arg("-c")
Expand All @@ -45,7 +45,21 @@ fn ping(ping_opt: &str, host: &str) -> bool {
.success()
}

/// Check if it can connect to at least one addresses
/// Checks if a ping replies from one host at least
fn can_ping_some(hosts: Vec<String>, ping_opt: String) -> bool {
if ping(&ping_opt, &hosts[0]) {
return true;
}
let n = hosts.len();
for result in hosts.with_threads(n).map(move |s| ping(&ping_opt, &s)) {
if result {
return true;
}
}
false
}

/// Checks if a connect can be stablished to one address at least
fn can_connect_some(addresses: Vec<SocketAddr>, timeout: Duration) -> bool {
if TcpStream::connect_timeout(&addresses[0], timeout).is_ok() {
return true;
Expand All @@ -62,7 +76,7 @@ fn can_connect_some(addresses: Vec<SocketAddr>, timeout: Duration) -> bool {
false
}

/// Ping
/// Network monitor
pub struct NetworkMonitor {
hosts: Vec<String>,
port: Option<u32>,
Expand All @@ -72,6 +86,7 @@ pub struct NetworkMonitor {

// Public
impl NetworkMonitor {
/// Instantiates a new NetworkMonitor
pub fn new(hosts: Vec<String>) -> Self {
NetworkMonitor {
hosts,
Expand All @@ -80,7 +95,7 @@ impl NetworkMonitor {
timeout: Duration::from_secs(DEFAULT_TIMEOUT),
}
}
/// Check if ping has pong
/// Checks if ping answers with a pong
pub fn is_ping_pong(&self) -> Result<(), NetworkError> {
if self.hosts.is_empty() {
return Err(NetworkError::NoHostsToCheck);
Expand All @@ -92,18 +107,13 @@ impl NetworkMonitor {
if let Some(opt) = &self.ping_opt {
ping_opt = String::from(opt)
};
if ping(&ping_opt, &hosts[0]) {
return Ok(());
}
let n = self.hosts.len();
for result in hosts.with_threads(n).map(move |s| ping(&ping_opt, &s)) {
if result {
return Ok(());
}
if can_ping_some(hosts, ping_opt) {
Ok(())
} else {
Err(NetworkError::NetworkUnreachable)
}
Err(NetworkError::NetworkUnreachable)
}
/// Check if network is reachable
/// Checks if network is reachable
pub fn is_network_reachable(&self) -> Result<(), NetworkError> {
if self.hosts.is_empty() {
return Err(NetworkError::NoHostsToCheck);
Expand All @@ -124,15 +134,15 @@ impl NetworkMonitor {
}
}

/// Set port, for is_network_reachable
/// Sets port, for is_network_reachable
pub fn set_port(&mut self, port: u32) {
self.port = Some(port);
}
/// Set ping options, for is_ping_pong
/// Sets ping options, for is_ping_pong
pub fn set_ping_opt(&mut self, ping_opt: String) {
self.ping_opt = Some(ping_opt);
}
/// Set timeout
/// Sets timeout for direct connection
pub fn set_timeout(&mut self, secs: u64) -> Result<(), NetworkError> {
if secs > 0 {
self.timeout = Duration::from_secs(secs);
Expand All @@ -145,14 +155,13 @@ impl NetworkMonitor {

// Private
impl NetworkMonitor {
/// Get hosts as network addresses
/// Gets hosts as network addresses
fn get_addresses(&self, port: u32) -> Vec<SocketAddr> {
self
.hosts
.iter()
.map(|addr| {
let ip_port = format!("{}:{}", addr, port);
print!("{}", ip_port);
ip_port.parse::<SocketAddr>()
})
.filter(|addr| addr.is_ok())
Expand Down

0 comments on commit ead2147

Please sign in to comment.