reqwest_proxy_pool/
proxy.rs1use governor::{clock::DefaultClock, middleware::NoOpMiddleware, state::{InMemoryState, NotKeyed}, Quota, RateLimiter};
4use std::num::NonZeroU32;
5use std::sync::Arc;
6use std::time::Instant;
7
8#[derive(Debug, Clone, Copy, PartialEq)]
10pub enum ProxyStatus {
11 Unknown,
13 Healthy,
15 Unhealthy,
17}
18
19#[derive(Debug, Clone)]
21pub struct Proxy {
22 pub url: String,
24 pub status: ProxyStatus,
26 pub success_count: usize,
28 pub failure_count: usize,
30 pub last_check: Instant,
32 pub response_time: Option<f64>,
34 pub limiter: Arc<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
36}
37
38impl Proxy {
39 pub fn new(url: String, max_rps: f64) -> Self {
41 let quota = Quota::per_second(NonZeroU32::new(max_rps.ceil() as u32).unwrap_or(NonZeroU32::new(1).unwrap()));
43 let limiter = Arc::new(RateLimiter::direct(quota));
44
45 Self {
46 url,
47 status: ProxyStatus::Unknown,
48 success_count: 0,
49 failure_count: 0,
50 last_check: Instant::now(),
51 response_time: None,
52 limiter,
53 }
54 }
55
56 pub fn to_reqwest_proxy(&self) -> Result<reqwest::Proxy, reqwest::Error> {
58 reqwest::Proxy::all(&self.url)
59 }
60
61 pub fn success_rate(&self) -> f64 {
63 let total = self.success_count + self.failure_count;
64 if total == 0 {
65 return 0.0;
66 }
67 self.success_count as f64 / total as f64
68 }
69}