From f9cf88911f4a32275c4e7d308088a43c5e365176 Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Thu, 17 Apr 2025 09:54:22 -0400 Subject: [PATCH] Threads now does backend work and displays a nice UI every 5 seconds --- Cargo.toml | 5 ++ src/bin/threads.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/bin/threads.rs diff --git a/Cargo.toml b/Cargo.toml index a9511ba..ff9cd05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,8 @@ env_logger = "0.11" log = "0.4" ansi_term = "0.12" clap = { version = "4.5.36", features = ["derive"] } + + +[[bin]] +name = "threads" + diff --git a/src/bin/threads.rs b/src/bin/threads.rs new file mode 100644 index 0000000..0cd3961 --- /dev/null +++ b/src/bin/threads.rs @@ -0,0 +1,148 @@ +use std::net::Ipv4Addr; +use std::process::Command; +use std::sync::mpsc; +use std::sync::mpsc::Receiver; +use std::sync::mpsc::Sender; +use std::thread; +use std::time::{Duration, SystemTime}; + +const SECONDS_BETWEEN_DISPLAY: u32 = 5; +const SECONDS_BETWEEN_PING: u32 = 1; + +#[derive(Clone)] +struct PingRequest { + target: Ipv4Addr, +} + +#[derive(Clone)] +struct PingResult { + target: Ipv4Addr, + success: bool, + rtt: u32, +} + +fn spawn_manager_thread(targets: Vec, sender: Sender) { + let local_targets = targets.clone(); + thread::spawn(move || { + loop { + for target in &local_targets { + spawn_single_ping(PingRequest { target: *target }, sender.clone()); + } + thread::sleep(Duration::from_secs(SECONDS_BETWEEN_PING as u64)); + } + }); +} + +// Spawns a thread that pings a target and sends the response back to the main thread +// via the sender +fn spawn_single_ping(request: PingRequest, sender: Sender) { + let local_request = request.clone(); + thread::spawn(move || { + + let start_time = SystemTime::now(); + + let result = Command::new("/usr/bin/ping").arg(request.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)); + + let success = ping_duration.as_millis() >= SECONDS_BETWEEN_PING as u128 && result == 0; + + + // println!("Attempt for for {}", local_request.target); + sender.send(PingResult { target: local_request.target, success, rtt: ping_duration.as_millis() as u32 }) + }); +} + + +#[derive(Clone)] +struct TargetState { + target: Ipv4Addr, + alive: bool, + last_rtt: u32, +} + +impl Default for TargetState { + fn default() -> Self { + TargetState { + target: Ipv4Addr::new(127, 0, 0, 1), + alive: false, + last_rtt: 0, + } + } +} + +#[derive(Default)] +pub struct State { + targets: Vec, +} + +impl State { + pub fn add_target(&mut self, to_add: Ipv4Addr) { + self.targets.push(TargetState { + target: to_add, + ..TargetState::default() + }); + } + + pub fn targets_ipv4(&self) -> Vec { + let mut working = vec![]; + + for current in &self.targets { + working.push(current.target); + } + + working + } +} + + +fn main() { + // channel to send requests to ping + let (ping_response_sender, ping_response_listener) = mpsc::channel::(); + + println!("Taxation is Theft"); + + let targets = vec![Ipv4Addr::new(127, 0, 0, 1), + Ipv4Addr::new(172, 24, 10, 200), + Ipv4Addr::new(1,1,1,1)]; + let mut state = State::default(); + + for current in &targets { + state.add_target(*current); + } + + println!("Setting up requests for {} hosts.", targets.len()); + 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)) { + // println!("Master got a ping response for {} with {}/{}", response.target, response.success, response.rtt); + for (index, current_state) in state.targets.clone().iter().enumerate() { + if current_state.target == response.target { + let new_state = TargetState { + target: current_state.target, + alive: response.success, + last_rtt: response.rtt, + }; + state.targets[index] = new_state.clone(); + println!("({}) Found the target -> {}/{}/{}", state.targets.clone().len(), new_state.target, new_state.alive, new_state.last_rtt); + } + } + } + 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!("------------"); + for current_result in state.targets.clone() { + println!("{} / {} -> {}", current_result.target, current_result.alive, current_result.last_rtt); + } + display_loop_start = SystemTime::now(); + } + } +}