use std::net::{TcpStream, ToSocketAddrs};
use std::sync::mpsc::Sender;
use std::thread;
use std::time::{Duration, Instant};
const BATCH: usize = 8;
#[derive(Clone, Copy, PartialEq)]
pub enum Reach {
Probing,
Up(u64),
Down,
}
pub struct Msg {
pub key: String,
pub generation: u64,
pub reach: Reach,
}
pub struct Target {
pub key: String,
pub host: String,
pub port: u16,
}
pub fn probe_all(targets: Vec<Target>, generation: u64, tx: Sender<Msg>, timeout_secs: u64) {
let timeout = Duration::from_secs(timeout_secs.clamp(1, 60));
if targets.is_empty() {
return;
}
thread::spawn(move || {
for chunk in targets.chunks(BATCH) {
thread::scope(|s| {
for t in chunk {
let tx = tx.clone();
s.spawn(move || {
let reach = probe(&t.host, t.port, timeout);
let _ = tx.send(Msg {
key: t.key.clone(),
generation,
reach,
});
});
}
});
}
});
}
fn probe(host: &str, port: u16, timeout: Duration) -> Reach {
let started = Instant::now();
let Ok(mut addrs) = (host, port).to_socket_addrs() else {
return Reach::Down;
};
for addr in addrs.by_ref() {
if TcpStream::connect_timeout(&addr, timeout).is_ok() {
return Reach::Up(started.elapsed().as_millis() as u64);
}
}
Reach::Down
}