Skip to main content

reqwest_proxy_pool/
proxy.rs

1//! Proxy representation and status.
2
3use governor::{
4    clock::DefaultClock,
5    middleware::NoOpMiddleware,
6    state::{InMemoryState, NotKeyed},
7    Quota, RateLimiter,
8};
9use std::num::NonZeroU32;
10use std::sync::Arc;
11use std::time::Instant;
12
13/// Status of a proxy.
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum ProxyStatus {
16    /// The proxy has not been tested yet.
17    Unknown,
18    /// The proxy is healthy and can be used.
19    Healthy,
20    /// The proxy is unhealthy and should not be used.
21    Unhealthy,
22}
23
24/// Representation of a proxy server.
25#[derive(Debug, Clone)]
26pub struct Proxy {
27    /// The URL of the proxy (e.g. "socks5://127.0.0.1:1080").
28    pub url: String,
29    /// The current status of the proxy.
30    pub status: ProxyStatus,
31    /// Number of successful requests made through this proxy.
32    pub success_count: usize,
33    /// Number of failed requests made through this proxy.
34    pub failure_count: usize,
35    /// Time when this proxy was last checked.
36    pub last_check: Instant,
37    /// Average response time in seconds, if available.
38    pub response_time: Option<f64>,
39    /// Rate limiter to control requests per second.
40    pub limiter: Arc<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
41}
42
43impl Proxy {
44    /// Create a new proxy with the given URL and rate limit.
45    pub fn new(url: String, max_rps: f64) -> Self {
46        // Create a rate limiter for this proxy
47        let quota = Quota::per_second(
48            NonZeroU32::new(max_rps.ceil() as u32).unwrap_or(NonZeroU32::new(1).unwrap()),
49        );
50        let limiter = Arc::new(RateLimiter::direct(quota));
51
52        Self {
53            url,
54            status: ProxyStatus::Unknown,
55            success_count: 0,
56            failure_count: 0,
57            last_check: Instant::now(),
58            response_time: None,
59            limiter,
60        }
61    }
62
63    /// Convert the proxy URL to a reqwest::Proxy.
64    pub fn to_reqwest_proxy(&self) -> Result<reqwest::Proxy, reqwest::Error> {
65        reqwest::Proxy::all(&self.url)
66    }
67
68    /// Calculate the success rate of this proxy.
69    pub fn success_rate(&self) -> f64 {
70        let total = self.success_count + self.failure_count;
71        if total == 0 {
72            return 0.0;
73        }
74        self.success_count as f64 / total as f64
75    }
76}