nurtex_proxy/tools/
ping.rs1use 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#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct PingInfo {
14 pub pinged_services: HashMap<String, u64>,
15 pub average_ping: Option<u64>,
16}
17
18fn 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
30pub 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
69pub 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}