use std::fs::File;
use std::io;
use std::io::BufRead;
use std::net::Ipv4Addr;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::mpsc;
use std::time::{Duration, SystemTime};
use clap::Parser;
use crate::manager::Manager;
use crate::ping_result::PingResult;
use crate::state::State;
use crate::target_state::TargetState;
mod manager;
mod state;
mod target_state;
mod ping_result;
mod ping_request;
const SECONDS_BETWEEN_DISPLAY: u32 = 1;
const SECONDS_BETWEEN_PING: u32 = 2;
fn read_lines
(filename: P) -> io::Result>>
where P: AsRef, {
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn build_targets_from_file(filename: Option) -> Vec{
let mut targets = vec![Ipv4Addr::new(127, 0, 0, 1),
Ipv4Addr::new(172, 24, 10, 1),
Ipv4Addr::new(1,1,1,1),
Ipv4Addr::new(8,8,8,8),
Ipv4Addr::new(216,121,247,231),
Ipv4Addr::new(216,234,202,122),
Ipv4Addr::new(24,143,184,98),
];
if let Some(file) = filename {
println!("File is {:?}", file.to_str());
if let Ok(lines) = read_lines(file) {
targets.clear();
// Consumes the iterator, returns an (Optional) String
for line in lines.map_while(Result::ok) {
targets.push(
Ipv4Addr::from_str(&*line).unwrap()
);
}
}
// targets = vec![];
};
targets
}
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct AppSettings {
/// File of list of hosts
#[arg(short, long)]
ping_host_file: Option,
}
fn main() {
// Get App Settings
let settings = AppSettings::parse();
// channel to send requests to ping
let (ping_response_sender, ping_response_listener) = mpsc::channel::();
let file_to_read = settings.ping_host_file;
let targets = build_targets_from_file(file_to_read);
let mut state = State::default();
for current in &targets {
state.add_target(*current);
}
println!("Setting up requests for {} hosts.", targets.len());
Manager::spawn_manager_thread(state.targets_ipv4().clone(), ping_response_sender.clone());
let mut display_loop_start = SystemTime::now();
let mut duration_since_last_loop = SystemTime::now().duration_since(display_loop_start).unwrap();
loop {
if let Ok(response) = ping_response_listener.recv_timeout(Duration::from_millis(100)) {
for (index, current_state) in state.targets.clone().iter().enumerate() {
if current_state.target == response.target {
let last_alive_change = if response.success == current_state.alive {
current_state.last_alive_change
} else {
SystemTime::now()
};
let new_state = TargetState {
target: current_state.target,
alive: response.success,
last_rtt: response.rtt,
last_alive_change,
};
state.targets[index] = new_state.clone();
}
}
}
duration_since_last_loop = SystemTime::now()
.duration_since(display_loop_start)
.expect("unable to figure out how long ago we displayed stuff");
if duration_since_last_loop.as_secs() > SECONDS_BETWEEN_DISPLAY as u64 {
println!("DISPLAY LOOP");
println!("Host \t\t | Alive \t | RTT \t\t");
for current_result in state.targets.clone() {
let time_since_last_change = SystemTime::now().duration_since(current_result.last_alive_change).unwrap();
let target_string = if current_result.target.clone().to_string().len() > 8 {
format!("{}", current_result.target)
} else {
format!("{}\t", current_result.target)
};
println!("{}\t | {} \t | {}\t | Changed {}s ago",
target_string,
current_result.alive,
current_result.last_rtt,time_since_last_change.as_secs()
);
}
display_loop_start = SystemTime::now();
}
}
}