Skip to main content

nurtex_proxy/tools/
ping.rs

1use std::sync::Arc;
2use std::sync::atomic::{AtomicU8, AtomicU64, Ordering};
3use std::time::Instant;
4
5use hashbrown::HashMap;
6use tokio::io::AsyncWriteExt;
7use tokio::sync::Mutex;
8
9use crate::Proxy;
10
11/// Структура информации о пинге
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct PingInfo {
14  pub pinged_services: HashMap<String, u64>,
15  pub average_ping: Option<u64>,
16}
17
18/// Вспомогательная функция получения пингуемых сервисов по умолчанию
19fn default_pinged_services() -> Vec<(String, u16)> {
20  vec![
21    ("cloudflare.com".to_string(), 80),
22    ("facebook.com".to_string(), 80),
23    ("yandex.ru".to_string(), 80),
24    ("youtube.com".to_string(), 80),
25    ("github.com".to_string(), 80),
26    ("reddit.com".to_string(), 80),
27  ]
28}
29
30/// Функция пингования прокси
31pub async fn ping_proxy(proxy: &Proxy, pinged_services: Option<Vec<(String, u16)>>) -> PingInfo {
32  let mut ping_info = PingInfo {
33    pinged_services: HashMap::new(),
34    average_ping: None,
35  };
36
37  if !proxy.is_available().await {
38    return ping_info;
39  }
40
41  let mut total_pinged_services = 0;
42  let mut total_ping = 0;
43
44  let ps = if let Some(services) = pinged_services { services } else { default_pinged_services() };
45
46  for (service_host, service_port) in ps {
47    let start_time = Instant::now();
48
49    match proxy.connect(&service_host, service_port).await {
50      Ok(mut s) => {
51        let _ = s.shutdown().await;
52
53        let ping = start_time.elapsed().as_millis();
54
55        total_pinged_services += 1;
56        total_ping += ping as u64;
57
58        ping_info.pinged_services.insert(service_host, ping as u64);
59      }
60      Err(_) => {}
61    }
62  }
63
64  ping_info.average_ping = Some(total_ping / total_pinged_services as u64);
65
66  ping_info
67}
68
69/// Функция параллельного пингования прокси
70pub async fn ping_proxy_parallel(proxy: Arc<Proxy>, pinged_services: Option<Vec<(String, u16)>>) -> PingInfo {
71  let ping_info = PingInfo {
72    pinged_services: HashMap::new(),
73    average_ping: None,
74  };
75
76  let ping_info_mutex = Arc::new(Mutex::new(ping_info));
77
78  if !proxy.is_available().await {
79    return ping_info_mutex.lock().await.clone();
80  }
81
82  let total_pinged_services = Arc::new(AtomicU8::new(0));
83  let total_ping = Arc::new(AtomicU64::new(0));
84
85  let mut handles = Vec::new();
86
87  let ps = if let Some(services) = pinged_services { services } else { default_pinged_services() };
88
89  for (service_host, service_port) in ps {
90    let proxy_clone = Arc::clone(&proxy);
91    let ping_info_mutex_clone = Arc::clone(&ping_info_mutex);
92    let total_pinged_services_clone = Arc::clone(&total_pinged_services);
93    let total_ping_clone = Arc::clone(&total_ping);
94
95    let handle = tokio::spawn(async move {
96      let start_time = Instant::now();
97
98      match proxy_clone.connect(&service_host, service_port).await {
99        Ok(mut s) => {
100          let _ = s.shutdown().await;
101
102          let ping = start_time.elapsed().as_millis();
103
104          total_pinged_services_clone.fetch_add(1, Ordering::SeqCst);
105          total_ping_clone.fetch_add(ping as u64, Ordering::SeqCst);
106
107          ping_info_mutex_clone.lock().await.pinged_services.insert(service_host, ping as u64);
108        }
109        Err(_) => {}
110      }
111    });
112
113    handles.push(handle);
114  }
115
116  for handle in handles {
117    let _ = handle.await;
118  }
119
120  let average_ping = total_ping.load(Ordering::SeqCst) / total_pinged_services.load(Ordering::SeqCst) as u64;
121  ping_info_mutex.lock().await.average_ping = Some(average_ping);
122
123  ping_info_mutex.lock().await.clone()
124}
125
126#[cfg(test)]
127mod tests {
128  use std::sync::Arc;
129
130  use crate::tools::{ping_proxy, ping_proxy_parallel};
131  use crate::{Proxy, ProxyType};
132
133  #[tokio::test]
134  async fn test_ping_proxy() {
135    let proxy = Proxy::new("98.175.31.222:4145", ProxyType::Socks5);
136
137    let result = ping_proxy(&proxy, None).await;
138
139    for (name, ping) in result.pinged_services {
140      println!("Пинг {}: {}ms", name, ping);
141    }
142
143    println!("===============================");
144
145    if let Some(average_ping) = result.average_ping {
146      println!("Средний пинг прокси: {}ms", average_ping);
147    }
148  }
149
150  #[tokio::test]
151  async fn test_ping_proxy_parallel() {
152    let proxy = Proxy::new("98.175.31.222:4145", ProxyType::Socks5);
153
154    let result = ping_proxy_parallel(Arc::new(proxy), None).await;
155
156    for (name, ping) in result.pinged_services {
157      println!("Пинг {}: {}ms", name, ping);
158    }
159
160    println!("===============================");
161
162    if let Some(average_ping) = result.average_ping {
163      println!("Средний пинг прокси: {}ms", average_ping);
164    }
165  }
166}