reqwest_proxy_pool/
proxy.rs1use 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#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum ProxyStatus {
16 Unknown,
18 Healthy,
20 Unhealthy,
22}
23
24#[derive(Debug, Clone)]
26pub struct Proxy {
27 pub url: String,
29 pub status: ProxyStatus,
31 pub success_count: usize,
33 pub failure_count: usize,
35 pub last_check: Instant,
37 pub response_time: Option<f64>,
39 pub limiter: Arc<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
41}
42
43impl Proxy {
44 pub fn new(url: String, max_rps: f64) -> Self {
46 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 pub fn to_reqwest_proxy(&self) -> Result<reqwest::Proxy, reqwest::Error> {
65 reqwest::Proxy::all(&self.url)
66 }
67
68 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}