reqwest_proxy_pool/
proxy.rs

1//! Proxy representation and status.
2
3use governor::{clock::DefaultClock, middleware::NoOpMiddleware, state::{InMemoryState, NotKeyed}, Quota, RateLimiter};
4use std::num::NonZeroU32;
5use std::sync::Arc;
6use std::time::Instant;
7
8/// Status of a proxy.
9#[derive(Debug, Clone, Copy, PartialEq)]
10pub enum ProxyStatus {
11    /// The proxy has not been tested yet.
12    Unknown,
13    /// The proxy is healthy and can be used.
14    Healthy,
15    /// The proxy is unhealthy and should not be used.
16    Unhealthy,
17}
18
19/// Representation of a proxy server.
20#[derive(Debug, Clone)]
21pub struct Proxy {
22    /// The URL of the proxy (e.g. "socks5://127.0.0.1:1080").
23    pub url: String,
24    /// The current status of the proxy.
25    pub status: ProxyStatus,
26    /// Number of successful requests made through this proxy.
27    pub success_count: usize,
28    /// Number of failed requests made through this proxy.
29    pub failure_count: usize,
30    /// Time when this proxy was last checked.
31    pub last_check: Instant,
32    /// Average response time in seconds, if available.
33    pub response_time: Option<f64>,
34    /// Rate limiter to control requests per second.
35    pub limiter: Arc<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
36}
37
38impl Proxy {
39    /// Create a new proxy with the given URL and rate limit.
40    pub fn new(url: String, max_rps: f64) -> Self {
41        // Create a rate limiter for this proxy
42        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    /// Convert the proxy URL to a reqwest::Proxy.
57    pub fn to_reqwest_proxy(&self) -> Result<reqwest::Proxy, reqwest::Error> {
58        reqwest::Proxy::all(&self.url)
59    }
60    
61    /// Calculate the success rate of this proxy.
62    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}