7 Commits

Author SHA1 Message Date
tmerritt 1106850cba permission issues. putting on hold. 2025-04-25 13:00:01 -04:00
tmerritt 4684b81ea1 adds ability to read hosts.txt if no file is specified on the command line, using defaults if hosts.txt is missing
compiles but doesnt actually ping the targets.  all come back as failure.
2025-04-25 11:49:11 -04:00
tmerritt e1b435bf7b more hosts and better naming for peterborough 2025-04-23 11:08:35 -04:00
tmerritt f57325bc6b Updates dependencies 2025-04-23 10:53:09 -04:00
tmerritt 613f22d31c Removes 'magic numbers' and uses constants for number of seconds in hour and day 2025-04-23 10:52:33 -04:00
tmerritt 002ad36068 Rolls 'duration_to_string' into pp 2025-04-22 16:09:49 -04:00
tmerritt 4ec95af6d0 optimized main loop
Adds colour to the text display
2025-04-22 16:03:30 -04:00
11 changed files with 1167 additions and 233 deletions
Generated
+916 -21
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -10,8 +10,13 @@ ansi_term = "0.12"
clap = { version = "4.5", features = ["derive"] }
csv = "1.3"
[[bin]]
name = "duration_to_string"
# Ratatui
color-eyre = "0.6.3"
crossterm = "0.28.1"
ratatui = "0.29.0"
# Internal Ping
ping-rs = "0.1"
[[bin]]
name = "pp"
+1
View File
@@ -1,3 +1,4 @@
address,name
10.3.100.1,Belleville Router
10.11.31.3,Belleville VPN 11-31
10.12.32.1,Belleville VPN 12-32
+1
View File
@@ -1,3 +1,4 @@
address,name
10.3.100.1,Belleville Router
10.11.31.3,Belleville VPN 11-31
10.12.32.1,Belleville VPN 12-32
+7 -6
View File
@@ -1,14 +1,15 @@
10.3.100.1,Belleville Router
10.3.100.1,Belleville Gateway
10.11.31.3,Belleville VPN 11-31
10.12.32.1,Belleville VPN 12-32
192.186.110.6,Belleville Cogeco
129.222.197.36,Belleville Starlink
10.2.100.1,Lindsay Gateway
24.143.184.98,Lindsay Cogeco
192.168.1.50,Lindsay Sign
10.11.21.1,Lindsay VPN 11-21
10.12.22.1,Lindsay VPN 11-22
8.8.8.8,Google DNS
1.1.1.1,1111 DNS
192.168.0.1,Peterborough Gateway
24.51.235.162,Peterborough Cogeco
99.214.0.92,Peterborough Rogers
216.234.202.122,Lindsay Starlink
24.143.184.98,Lindsay Cogeco
192.186.110.6,Belleville Cogeco
129.222.197.36,Belleville Starlink
192.168.0.50,Sign
-41
View File
@@ -1,41 +0,0 @@
use std::time::Duration;
pub fn duration_to_string(to_convert: Duration) -> String {
let mut total_seconds = to_convert.as_secs();
let mut working_string = String::new();
if total_seconds > 86400 {
// days
let num_days = total_seconds / 86400;
working_string = format!("{} days", num_days);
total_seconds = total_seconds - (num_days * 86400);
}
if total_seconds > 3600 {
// hours
let num_hours = total_seconds / 3600;
if num_hours > 0 {
working_string = format!("{} {} hours", working_string, num_hours);
total_seconds = total_seconds - (num_hours * 3600);
}
}
if total_seconds > 60 {
let num_minutes = total_seconds / 60;
if num_minutes > 0 {
working_string = format!("{} {} minutes", working_string, num_minutes);
total_seconds = total_seconds - (num_minutes * 60);
}
// minutes
}
working_string = format!("{} {} seconds.", working_string, total_seconds);
working_string
}
fn main() {
println!("1m 12s => {}", duration_to_string(Duration::from_secs(72)));
println!("1h 1m 12s => {}", duration_to_string(Duration::from_secs(3672)));
println!("1d 1h 1m 12s => {}", duration_to_string(Duration::from_secs(90072)));
println!("30d 1h 1m 12s => {}", duration_to_string(Duration::from_secs(2595672)));
}
+96 -33
View File
@@ -14,8 +14,52 @@ use pp::manager::Manager;
use pp::SECONDS_BETWEEN_DISPLAY;
use pp::target_state::TargetState;
use std::{env, error::Error, ffi::OsString, process};
use color_eyre::owo_colors::OwoColorize;
use crossterm::style::Stylize;
use log::debug;
const SECONDS_IN_MINUTE: u32 = 60;
const SECONDS_IN_HOUR: u32 = SECONDS_IN_MINUTE * 60;
const SECONDS_IN_DAY: u32 = SECONDS_IN_HOUR * 24;
fn get_default_targets() -> BTreeMap<String, TargetState> {
pub fn duration_to_string(to_convert: Duration) -> String {
let mut total_seconds = to_convert.as_secs() as u32;
let mut working_string = String::new();
if total_seconds > 86400 {
// days
let num_days = (total_seconds / SECONDS_IN_DAY) as u32;
working_string = format!("{} days", num_days);
total_seconds = total_seconds - (num_days * SECONDS_IN_DAY);
}
if total_seconds > 3600 {
// hours
let num_hours = (total_seconds / SECONDS_IN_HOUR) as u32;
if num_hours > 0 {
working_string = format!("{} {} hours", working_string, num_hours);
total_seconds = total_seconds - (num_hours * SECONDS_IN_HOUR);
}
}
if total_seconds > 60 {
let num_minutes = (total_seconds / SECONDS_IN_MINUTE) as u32;
if num_minutes > 0 {
working_string = format!("{} {} minutes", working_string, num_minutes);
total_seconds = total_seconds - (num_minutes * SECONDS_IN_MINUTE);
}
// minutes
}
working_string = format!("{} {} seconds", working_string, total_seconds);
working_string
}
struct PPState {}
impl PPState {
pub fn get_default_targets() -> BTreeMap<String, TargetState> {
let mut working = BTreeMap::new();
working.insert("Localhost".to_string(),
TargetState {
@@ -70,23 +114,23 @@ fn get_default_targets() -> BTreeMap<String, TargetState> {
},
);
working
}
fn build_targets_from_file(filename: Option<PathBuf>) -> BTreeMap<String, TargetState> {
let mut hosts: BTreeMap<String, TargetState> = get_default_targets();
}
pub fn build_targets_from_file(filename: Option<PathBuf>) -> BTreeMap<String, TargetState> {
PPState::get_default_targets();
if let Some(file) = filename {
hosts = if !&file.exists() {
println!("Cant load hosts from {:?}. Using default host list.", file.clone().as_os_str());
let mut working = BTreeMap::new();
if !&file.exists() {
debug!("Cant load hosts from {:?}. Using default host list.", file.clone().as_os_str());
// use
get_default_targets()
PPState::get_default_targets()
} else {
println!("LOADING HOSTS FROM {:?}", file.to_str());
debug!("LOADING HOSTS FROM {:?}", file.to_str());
let file = File::open(file);
let mut rdr = csv::Reader::from_reader(file.unwrap());
for result in rdr.records() {
let record = result.unwrap();
hosts.insert(record[1].to_string(),
working.insert(record[1].to_string(),
TargetState {
name: record[1].to_string(),
target: Ipv4Addr::from_str(&record[0]).unwrap(),
@@ -95,36 +139,44 @@ fn build_targets_from_file(filename: Option<PathBuf>) -> BTreeMap<String, Target
last_rtt: 0,
});
}
hosts
working
}
} else {
PPState::get_default_targets()
}
}
hosts
}
fn ips_from_state(to_read_from: BTreeMap<String, TargetState>) -> Vec<Ipv4Addr> {
fn ips_from_state(to_read_from: BTreeMap<String, TargetState>) -> Vec<Ipv4Addr> {
let mut working: Vec<Ipv4Addr> = vec![];
for current in to_read_from {
working.push(current.1.target);
}
working
}
}
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct AppSettings {
/// 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<PathBuf>,
}
}
fn main() {
fn main() {
// Get App Settings
let settings = AppSettings::parse();
print!("Prep to load targets...");
let mut targets = build_targets_from_file(settings.ping_host_file);
let file_to_check = match settings.ping_host_file {
None => {
PathBuf::from("./hosts.txt")
}
Some(actual) => {
actual
}
};
let mut targets = PPState::build_targets_from_file(Some(file_to_check));
// channel to send requests to ping
let (ping_response_sender, ping_response_listener) = mpsc::channel::<PingResult>();
@@ -135,8 +187,10 @@ fn main() {
let mut display_loop_start = SystemTime::now();
let mut duration_since_last_loop = SystemTime::now().duration_since(display_loop_start).unwrap();
loop {
let now = SystemTime::now();
if let Ok(response) = ping_response_listener.recv_timeout(Duration::from_millis(100)) {
for (_, (name, current_state)) in targets.clone().iter().enumerate() {
let local_targets = targets.clone();
for (_, (name, current_state)) in local_targets.iter().enumerate() {
if current_state.target == response.target {
let last_alive_change = if response.success == current_state.alive {
current_state.last_alive_change
@@ -155,27 +209,36 @@ fn main() {
}
}
}
duration_since_last_loop = SystemTime::now()
duration_since_last_loop = 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\t\t\t | Alive \t | RTT \t\t");
for (name, current_result) in targets.clone() {
let mut target_string = String::new();
let time_since_last_change = SystemTime::now().duration_since(current_result.last_alive_change).unwrap();
target_string = format!("{} ({})", name, current_result.target);
let time_since_last_change = now
.duration_since(current_result.last_alive_change)
.unwrap_or(Duration::from_secs(0));
let mut target_string = format!("{} ({})", name, current_result.target);
while target_string.len() < 34 {
target_string = format!("{} ", target_string);
target_string.push(' ');
// target_string = format!("{} ", target_string);
}
println!("{} \t | {} \t | {}\t | Changed {}s ago",
target_string = if current_result.alive {
target_string.green().to_string()
} else {
target_string.red().to_string()
};
println!("{} \t | {} \t | {}\t | Changed {} ago",
target_string,
current_result.alive,
current_result.last_rtt, time_since_last_change.as_secs()
current_result.last_rtt,
duration_to_string(time_since_last_change)
);
}
display_loop_start = SystemTime::now();
display_loop_start = now;
}
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ pub mod manager;
pub mod ping_request;
pub mod ping_result;
pub mod target_state;
mod tui;
pub const SECONDS_BETWEEN_DISPLAY: u32 = 1;
pub const SECONDS_BETWEEN_PING: u32 = 2;
+18 -22
View File
@@ -1,17 +1,15 @@
use std::net::Ipv4Addr;
use std::net::{IpAddr, Ipv4Addr};
use std::process::Command;
use std::sync::mpsc::Sender;
use std::thread;
use std::time::{Duration, SystemTime};
use ping_rs::send_ping;
use crate::ping_request::PingRequest;
use crate::ping_result::PingResult;
use crate::SECONDS_BETWEEN_PING;
pub struct Manager;
const WIN_PING_SUCCESS: i32 = 1;
const LIN_PING_SUCCESS: i32 = 0;
impl Manager {
pub fn spawn_manager_thread(targets: Vec<Ipv4Addr>, sender: Sender<PingResult>) {
let local_targets = targets.clone();
@@ -34,27 +32,25 @@ impl Manager {
let mut result = 0;
let mut success = true;
let start_time = SystemTime::now();
#[cfg(any(target_os="windows"))] {
result = Command::new("c:/windows/system32/ping.exe").arg(request.target.to_string())
.arg("-n 1")
.arg(format!("-w {}", crate::SECONDS_BETWEEN_PING))
.arg("-4")
.output().unwrap().status.code().unwrap_or(255);
success = result == WIN_PING_SUCCESS as i32;;
}
#[cfg(any(target_os="linux"))] {
result = Command::new("/usr/bin/ping").arg(request.target.to_string())
.arg("-c 1")
.arg("-4")
.arg(format!("-w {}", SECONDS_BETWEEN_PING))
.arg("-W 1")
.output().unwrap().status.code().unwrap_or(255);
success = result == LIN_PING_SUCCESS as i32;
}
let target_address = IpAddr::from(request.target);
let options = ping_rs::PingOptions { ttl: 128, dont_fragment: false };
let data = [1,2,3,4];
let result = send_ping(&target_address, Duration::from_secs(10), &data, Some(&options));
let ping_duration = SystemTime::now()
.duration_since(start_time)
.unwrap_or(Duration::from_secs(600));
let success = ping_duration.as_millis() >= SECONDS_BETWEEN_PING as u128 && success;
let success = match &result {
Ok(reply) => {
println!("Good reply -> {}/{}/{}", reply.address, data.len(), reply.rtt);
true
},
Err(e) => { println!("ERROR {:?}", e); false }
};
sender.send(PingResult {
target: local_request.target,
success,
+13
View File
@@ -1,5 +1,10 @@
use std::net::Ipv4Addr;
use std::time::SystemTime;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::prelude::{StatefulWidget, Style};
use ratatui::style::Color;
use ratatui::widgets::Widget;
#[derive(Clone, Debug)]
pub struct TargetState {
@@ -21,3 +26,11 @@ impl Default for TargetState {
}
}
}
struct TargetStateWidget;
impl StatefulWidget for TargetStateWidget {
type State = TargetStateWidget;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
buf.set_string(area.left(),area.top(),"This is the string set ", Style::default().fg(Color::Red));
}
}
View File