Initial commit

This commit is contained in:
2025-04-13 12:10:52 -04:00
commit c50857f210
5 changed files with 648 additions and 0 deletions
+214
View File
@@ -0,0 +1,214 @@
use std::fs::File;
use std::net::Ipv4Addr;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
use std::string::ToString;
use std::sync::mpsc;
use std::sync::mpsc::Sender;
use std::{io, thread};
use std::io::BufRead;
use std::time::{Duration, SystemTime};
use ansi_term::Colour::{Green, Red};
use clap::Parser;
use log::{debug, error, log_enabled, info, Level};
#[derive(Clone)]
struct HistoricHost {
pub name: String,
pub address: Ipv4Addr,
pub history: Vec<u128>,
pub alive: bool
}
#[derive(Clone, Debug)]
struct PingResult {
pub address: Ipv4Addr,
pub rtt: u128
}
impl HistoricHost {
pub fn dump_state(&self) {
let working_history = self.history.clone();
if working_history.len() == 0 {
println!("No Results for {} yet.", self.name);
return;
}
let num_results = working_history.len();
let mut running_total = 0;
for result in working_history {
running_total += result;
}
let average_ping_time = running_total.div_ceil(num_results as u128);
println!("Counted {} results, total time {} with average {}",
num_results, running_total, average_ping_time
);
}
pub fn get_ping_time_for(target: Ipv4Addr) -> (i32, Duration) {
let start_time = SystemTime::now();
let result = Command::new("/usr/bin/ping").arg(target.to_string())
.arg("-c 1")
.arg("-4")
.arg("-w 10")
.arg("-W 1")
.output().unwrap().status.code().unwrap_or(255);
let ping_duration = SystemTime::now().duration_since(start_time).unwrap_or(Duration::from_secs(600));
(result, ping_duration)
}
pub fn get_ping_time(&self) -> (i32, Duration) {
HistoricHost::get_ping_time_for(self.address)
}
pub fn ping(&mut self) {
let (result, ping_duration) = self.get_ping_time();
match result {
0 => {
self.history.push(ping_duration.as_millis())
},
1 => {
println!("Error ping to {}", self.name);
},
_ => {
println!("General Ping Error.");
}
}
}
}
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct PPArgs {
pub targets: Option<PathBuf>
}
// The output is wrapped in a Result to allow matching on errors.
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn main() {
env_logger::init();
let args = PPArgs::parse();
let targets = match args.targets {
Some(file) => {
println!("Loading hosts from {}", file.to_str().unwrap_or("no file."));
let mut working = vec![];
if let Ok(lines) = read_lines(file) {
// Consumes the iterator, returns an (Optional) String
for line in lines.map_while(Result::ok) {
println!("{}", line);
working.push(line.to_string())
}
}
working.to_vec()
}
None => {
println!("Default Hosts used.");
vec!["127.0.0.1".to_string(), "1.1.1.1".to_string(), "8.8.8.8".to_string()]
}
};
let (sender, receiver) = mpsc::channel::<PingResult>();
// sender gets cloned and sent to each pinger
let mut hosts = vec![];
info!("Building hosts list...");
// build hosts list...
for target in targets {
hosts.push(
HistoricHost {
name: target.to_string(),
address: Ipv4Addr::from_str(&target).unwrap_or(Ipv4Addr::new(127,0,0,1)),
history: vec![],
alive: false
}
)
}
info!("Completed building with {} hosts.", hosts.len());
info!("Starting Manager Thread");
// Manager Thread
let my_hosts = hosts.clone();
let _ = thread::spawn(move || {
loop {
println!("\x1b[2J --------------");
for current_target in my_hosts.clone() {
// debug!("[MT] Preparing to send off ping request to {}", current_target.address.to_string());
let start_time = SystemTime::now();
let result = Command::new("/usr/bin/ping").arg(current_target.address.to_string())
.arg("-c 1")
.arg("-4")
.arg("-w 10")
.arg("-W 1")
.output().unwrap().status.code().unwrap_or(255);
let ping_duration = SystemTime::now().duration_since(start_time).unwrap_or(Duration::from_secs(600));
let to_send = if result == 0 {
PingResult { address: current_target.address, rtt: ping_duration.as_millis() }
} else {
PingResult { address: current_target.address, rtt: u128::MAX }
};
let my_sender = sender.clone();
let _ = my_sender.send(to_send);
}
thread::sleep(Duration::from_secs(2));
}
});
info!("Manager Thread Started");
info!("Starting Data Thread");
// Data Thread
let _ = thread::spawn(move || {
debug!("[DT] STARTING WITH {} HOSTS", hosts.len());
loop {
if let Ok(rx) = receiver.recv_timeout(Duration::from_micros(1000)) {
let addr = rx.clone().address;
let rtt = rx.clone().rtt;
if rtt == u128::MAX {
// error!("[DT] No reply from {}", addr);
println!("{} not responding", Red.paint(addr.to_string()));
} else {
// debug!("[DT] Recieved a ping result from {} with time of {}", addr, rtt);
println!("{} responding.", Green.paint(addr.to_string()));
}
}
}
});
info!("Data Thread Started");
info!("Keep Alive Thread Starting.");
let _ = thread::spawn(move || {
let mut counter = 0 ;
loop {
thread::sleep(Duration::from_millis(1000));
counter += 1;
if counter % 1000 == 0 {
info!("Keep Alive Counter at {}", counter);
}
}
}).join();
//
// let _ = thread::spawn(move || {
// loop {
// println!("-- Status Start -- ");
// for host in &hosts.clone() {
// host.dump_state();
// }
// println!("-- Status Done -- ");
// thread::sleep(Duration::from_secs(1));
// }
// }).join();
}