load_balancer/
proxy_pool.rs1use crate::{
2 LoadBalancer,
3 round_robin::{Entry, Inner, RoundRobin},
4};
5use reqwest::Proxy;
6use std::{
7 ops::Range,
8 sync::{Arc, atomic::Ordering},
9 time::Duration,
10};
11use tokio::{
12 spawn,
13 sync::Semaphore,
14 task::JoinHandle,
15 time::{Instant, sleep},
16};
17
18#[derive(Clone)]
21pub struct ProxyPool {
22 code_range: Range<u16>,
23 test_url: String,
24 timeout: Duration,
25 proxy: Option<Proxy>,
26 max_check_concurrency: usize,
27 lb: RoundRobin<Arc<str>>,
28}
29
30impl ProxyPool {
31 pub fn new<T: IntoIterator<Item = impl AsRef<str>>>(url: T) -> Self {
33 Self {
34 code_range: (200..300),
35 test_url: "https://apple.com".to_string(),
36 timeout: Duration::from_secs(5),
37 proxy: None,
38 max_check_concurrency: 1000,
39 lb: RoundRobin::new(url.into_iter().map(|v| v.as_ref().into()).collect()),
40 }
41 }
42
43 pub fn code_range(mut self, code_range: Range<u16>) -> Self {
45 self.code_range = code_range;
46 self
47 }
48
49 pub fn test_url(mut self, test_url: String) -> Self {
51 self.test_url = test_url;
52 self
53 }
54
55 pub fn timeout(mut self, timeout: Duration) -> Self {
57 self.timeout = timeout;
58 self
59 }
60
61 pub fn proxy(mut self, proxy: Proxy) -> Self {
63 self.proxy = Some(proxy);
64 self
65 }
66
67 pub fn max_check_concurrency(mut self, max_check_concurrency: usize) -> Self {
69 self.max_check_concurrency = max_check_concurrency;
70 self
71 }
72
73 pub async fn available_count(&self) -> usize {
75 self.lb
76 .update(async |v| Ok(v.entries.read().await.len()))
77 .await
78 .unwrap()
79 }
80
81 pub async fn available(&self) -> Vec<String> {
83 self.lb
84 .update(async |v| {
85 Ok(v.entries
86 .read()
87 .await
88 .iter()
89 .map(|v| v.value.to_string())
90 .collect::<Vec<_>>())
91 })
92 .await
93 .unwrap()
94 }
95
96 pub async fn extend<T: IntoIterator<Item = impl AsRef<str>>>(&self, urls: T) {
101 let new_entries = urls
102 .into_iter()
103 .map(|v| Entry {
104 value: Arc::from(v.as_ref()),
105 })
106 .collect::<Vec<_>>();
107
108 self.lb
109 .update(async |v| {
110 let mut lock = v.entries.write().await;
111
112 lock.extend(new_entries.clone());
113 v.cursor.store(0, Ordering::Relaxed);
114
115 Ok(())
116 })
117 .await
118 .unwrap();
119 }
120
121 pub async fn extend_check<T: IntoIterator<Item = impl AsRef<str>>>(
126 &self,
127 url: T,
128 retry_count: usize,
129 ) -> anyhow::Result<()> {
130 let new_entries = url
131 .into_iter()
132 .map(|v| Entry {
133 value: Arc::from(v.as_ref()),
134 })
135 .collect::<Vec<Entry<Arc<str>>>>();
136
137 self.lb
138 .update(async |v| {
139 let old_entries = {
140 let lock = v.entries.read().await;
141 let mut result = Vec::with_capacity(lock.len() + new_entries.len());
142
143 result.extend_from_slice(&new_entries);
144 result.extend(lock.iter().cloned());
145
146 result
147 };
148
149 let result = self.internal_check(&old_entries, retry_count).await?;
150
151 let mut new_entries = Vec::with_capacity(result.len());
152
153 for (index, _) in result {
154 new_entries.push(old_entries[index].clone());
155 }
156
157 let mut lock = v.entries.write().await;
158
159 *lock = new_entries;
160 v.cursor.store(0, Ordering::Relaxed);
161
162 Ok(())
163 })
164 .await
165 }
166
167 pub async fn check(&self, retry_count: usize) -> anyhow::Result<()> {
169 self.lb
170 .update(async |v| {
171 let old_entries = v.entries.read().await;
172
173 let result = self.internal_check(&old_entries, retry_count).await?;
174
175 let mut new_entries = Vec::with_capacity(result.len());
176
177 for (index, _) in result {
178 new_entries.push(old_entries[index].clone());
179 }
180
181 drop(old_entries);
182
183 let mut lock = v.entries.write().await;
184
185 *lock = new_entries;
186 v.cursor.store(0, Ordering::Relaxed);
187
188 Ok(())
189 })
190 .await
191 }
192
193 pub async fn spawn_check(
197 &self,
198 check_interval: Duration,
199 retry_count: usize,
200 ) -> anyhow::Result<JoinHandle<()>> {
201 self.check(retry_count).await?;
202
203 let this = self.clone();
204
205 Ok(spawn(async move {
206 loop {
207 sleep(check_interval).await;
208 _ = this.check(retry_count).await;
209 }
210 }))
211 }
212
213 pub async fn spawn_check_callback<F, R>(
219 &self,
220 check_interval: Duration,
221 retry_count: usize,
222 callback: F,
223 ) -> anyhow::Result<JoinHandle<anyhow::Result<()>>>
224 where
225 F: Fn() -> R + Send + 'static,
226 R: Future<Output = anyhow::Result<()>> + Send,
227 {
228 self.check(retry_count).await?;
229 callback().await?;
230
231 let this = self.clone();
232
233 Ok(spawn(async move {
234 loop {
235 sleep(check_interval).await;
236 _ = this.check(retry_count).await;
237 callback().await?;
238 }
239 }))
240 }
241
242 pub async fn update<F, R>(&self, handler: F) -> anyhow::Result<()>
244 where
245 F: Fn(Arc<Inner<Arc<str>>>) -> R,
246 R: Future<Output = anyhow::Result<()>>,
247 {
248 self.lb.update(handler).await
249 }
250
251 pub async fn update_timer<F, R>(
256 &self,
257 handler: F,
258 interval: Duration,
259 ) -> anyhow::Result<JoinHandle<()>>
260 where
261 F: Fn(Arc<Inner<Arc<str>>>) -> R + Send + Sync + 'static,
262 R: Future<Output = anyhow::Result<()>> + Send,
263 {
264 self.lb.update_timer(handler, interval).await
265 }
266
267 async fn internal_check(
268 &self,
269 entries: &Vec<Entry<Arc<str>>>,
270 retry_count: usize,
271 ) -> anyhow::Result<Vec<(usize, u128)>> {
272 let semaphore = Arc::new(Semaphore::new(self.max_check_concurrency));
273 let mut task = Vec::with_capacity(entries.len());
274
275 for (index, entry) in entries.iter().enumerate() {
276 let permit = semaphore.clone().acquire_owned().await.unwrap();
277 let entry = entry.clone();
278 let code_range = self.code_range.clone();
279 let test_url = self.test_url.clone();
280 let timeout = self.timeout;
281 let upstream_proxy = self.proxy.clone();
282 let entry_value = entry.value.clone();
283
284 task.push(tokio::spawn(async move {
285 let _permit = permit;
286 let mut latency = None;
287
288 for _ in 0..=retry_count {
289 let client = if let Some(proxy) = upstream_proxy.clone() {
290 reqwest::ClientBuilder::new()
291 .proxy(proxy)
292 .proxy(Proxy::all(&*entry_value)?)
293 .timeout(timeout)
294 .build()?
295 } else {
296 reqwest::ClientBuilder::new()
297 .proxy(Proxy::all(&*entry_value)?)
298 .timeout(timeout)
299 .build()?
300 };
301
302 let start = Instant::now();
303
304 if let Ok(v) = client.get(&test_url).send().await {
305 if code_range.contains(&v.status().as_u16()) {
306 latency = Some(start.elapsed().as_millis());
307 break;
308 }
309 }
310 }
311
312 anyhow::Ok(latency.map(|v| (index, v)))
313 }));
314 }
315
316 let mut result = Vec::new();
317
318 for i in task {
319 if let Ok(Ok(Some(r))) = i.await {
320 result.push(r);
321 }
322 }
323
324 result.sort_by_key(|(_, latency)| *latency);
325
326 Ok(result)
327 }
328}
329
330impl LoadBalancer<String> for ProxyPool {
331 async fn alloc(&self) -> String {
332 LoadBalancer::alloc(&self.lb).await.to_string()
333 }
334
335 fn try_alloc(&self) -> Option<String> {
336 LoadBalancer::try_alloc(&self.lb).map(|v| v.to_string())
337 }
338}