1use crate::{BoxLoadBalancer, LoadBalancer, interval::IntervalLoadBalancer};
2use async_trait::async_trait;
3use get_if_addrs::get_if_addrs;
4use reqwest::{Client, ClientBuilder};
5use std::{net::IpAddr, sync::Arc, time::Duration};
6
7#[derive(Clone)]
10pub struct IPClientLoadBalancer {
11 inner: IntervalLoadBalancer<Client>,
12}
13
14impl IPClientLoadBalancer {
15 pub fn new(entries: Vec<(Duration, Client)>) -> Self {
17 Self {
18 inner: IntervalLoadBalancer::new(entries),
19 }
20 }
21
22 pub fn with_ip(ip: Vec<IpAddr>, interval: Duration) -> Self {
24 Self {
25 inner: IntervalLoadBalancer::new(
26 ip.into_iter()
27 .map(|v| {
28 (
29 interval,
30 ClientBuilder::new().local_address(v).build().unwrap(),
31 )
32 })
33 .collect(),
34 ),
35 }
36 }
37
38 pub fn with_timeout(ip: Vec<IpAddr>, interval: Duration, timeout: Duration) -> Self {
40 Self {
41 inner: IntervalLoadBalancer::new(
42 ip.into_iter()
43 .map(|v| {
44 (
45 interval,
46 ClientBuilder::new()
47 .local_address(v)
48 .timeout(timeout)
49 .build()
50 .unwrap(),
51 )
52 })
53 .collect(),
54 ),
55 }
56 }
57
58 pub async fn update<F, R>(&self, handle: F) -> anyhow::Result<()>
60 where
61 F: Fn(Arc<std::sync::RwLock<Vec<crate::interval::Entry<Client>>>>) -> R,
62 R: std::future::Future<Output = anyhow::Result<()>>,
63 {
64 self.inner.update(handle).await
65 }
66}
67
68impl LoadBalancer<Client> for IPClientLoadBalancer {
69 fn alloc(&self) -> impl std::future::Future<Output = Client> + Send {
70 LoadBalancer::alloc(&self.inner)
71 }
72
73 fn try_alloc(&self) -> Option<Client> {
74 LoadBalancer::try_alloc(&self.inner)
75 }
76}
77
78#[async_trait]
79impl BoxLoadBalancer<Client> for IPClientLoadBalancer {
80 async fn alloc(&self) -> Client {
81 LoadBalancer::alloc(self).await
82 }
83
84 fn try_alloc(&self) -> Option<Client> {
85 LoadBalancer::try_alloc(self)
86 }
87}
88
89pub fn get_ip_list() -> anyhow::Result<Vec<IpAddr>> {
91 Ok(get_if_addrs()?
92 .into_iter()
93 .filter(|v| !v.is_loopback())
94 .map(|v| v.ip())
95 .collect::<Vec<_>>())
96}
97
98pub fn get_ipv4_list() -> anyhow::Result<Vec<IpAddr>> {
100 Ok(get_if_addrs()?
101 .into_iter()
102 .filter(|v| !v.is_loopback() && v.ip().is_ipv4())
103 .map(|v| v.ip())
104 .collect::<Vec<_>>())
105}
106
107pub fn get_ipv6_list() -> anyhow::Result<Vec<IpAddr>> {
109 Ok(get_if_addrs()?
110 .into_iter()
111 .filter(|v| !v.is_loopback() && v.ip().is_ipv6())
112 .map(|v| v.ip())
113 .collect::<Vec<_>>())
114}