sysit/
ping.rs

1/*
2sysit | Check on the system with a quick glance!
3Copyright (C) 2021 Rohan Jain
4
5This program is free software: you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free Software
7Foundation, either version 3 of the License, or any later version.
8
9This program is distributed in the hope that it will be useful, but WITHOUT
10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12details.
13
14You should have received a copy of the GNU General Public License along with
15this program.  If not, see <https://www.gnu.org/licenses/>.
16*/
17
18use super::colors::colorize;
19use std::io::{BufRead, Result};
20use std::process::Command;
21use std::sync::{Arc, Mutex};
22use std::thread;
23use std::time::Duration;
24
25type Ping = (f32, String);
26
27fn parse_ping(output: Result<String>) -> Option<Ping> {
28    let output = output.ok()?;
29    if output.contains("time=") {
30        let mut ping_output = output.split("=").last().unwrap().split(" ");
31        let ping: f32 = ping_output.next().unwrap().parse().unwrap();
32        let unit = ping_output.next().unwrap();
33        Some((ping, unit.to_string()))
34    } else {
35        None
36    }
37}
38
39pub struct PingManager {
40    ping: Arc<Mutex<Option<Ping>>>,
41    host: String,
42}
43
44impl PingManager {
45    pub fn new(host: String) -> PingManager {
46        let ping_manager = PingManager {
47            host,
48            ping: Arc::new(Mutex::new(None)),
49        };
50        ping_manager.start();
51        ping_manager
52    }
53
54    fn start(self: &PingManager) -> () {
55        // Start the ping subprocess and its monitoring thread.
56        let ping = self.ping.clone();
57        let host = self.host.clone();
58
59        let _child = thread::spawn(move || {
60            let mut child = Command::new("ping")
61                .arg("-i 1")
62                .arg(host)
63                .stdout(std::process::Stdio::piped())
64                .spawn()
65                .expect("Failed to execute child!");
66
67            let child_stdout = child.stdout.as_mut().unwrap();
68
69            let reader = std::io::BufReader::new(child_stdout);
70            for line in reader.lines() {
71                *ping.lock().unwrap() = parse_ping(line);
72            }
73        });
74    }
75
76    pub fn wait(self: &PingManager) -> () {
77        // Wait (at most 200ms) for the first ping.
78        for _ in 0..20 {
79            if self.ping.lock().unwrap().is_some() {
80                break;
81            }
82            thread::sleep(Duration::from_millis(10));
83        }
84    }
85
86    pub fn current(self: &PingManager) -> String {
87        // Get the current ping (or N/A if we couldn't obtain it)
88        match self.ping.lock().unwrap().as_ref() {
89            None => "N/A".to_string(),
90            Some(ping) => colorize(format!("  {} {}", ping.0, ping.1), ping.0, 30.0, 100.0),
91        }
92    }
93}