1use std::net::{IpAddr, SocketAddr};
2use std::time::Duration;
3
4use anyhow::Result;
5use tokio::net::TcpStream;
6use tokio::time::timeout;
7
8pub struct TcpConnector {
10 timeout: Duration,
11}
12
13impl TcpConnector {
14 pub fn new() -> Self {
16 Self {
17 timeout: Duration::from_secs(5),
18 }
19 }
20
21 pub fn with_timeout(timeout: Duration) -> Self {
23 Self { timeout }
24 }
25
26 pub async fn check_port<A: Into<IpAddr>>(&self, host: A, port: u16) -> Result<bool> {
28 let addr = SocketAddr::new(host.into(), port);
29 let connect_future = TcpStream::connect(addr);
30
31 match timeout(self.timeout, connect_future).await {
32 Ok(Ok(_)) => Ok(true),
33 Ok(Err(_)) => Ok(false),
34 Err(_) => Ok(false), }
36 }
37
38 pub async fn check_ports<A: Into<IpAddr> + Clone>(
40 &self,
41 host: A,
42 ports: &[u16],
43 ) -> Result<Vec<(u16, bool)>> {
44 let mut results = Vec::with_capacity(ports.len());
45
46 for &port in ports {
47 let is_open = self.check_port(host.clone(), port).await?;
48 results.push((port, is_open));
49 }
50
51 Ok(results)
52 }
53
54 pub async fn ping<S: AsRef<str>>(&self, host: S) -> Result<bool> {
56 let host_str = host.as_ref().to_string();
58 let timeout_secs = self.timeout.as_secs().to_string();
59
60 let status = tokio::process::Command::new("ping")
62 .arg("-c")
63 .arg("1") .arg("-W")
65 .arg(timeout_secs) .arg(host_str) .output()
68 .await?;
69
70 Ok(status.status.success())
71 }
72}
73
74impl Default for TcpConnector {
75 fn default() -> Self {
76 Self::new()
77 }
78}