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_ipv4(interval: Duration) -> Self {
24 Self {
25 inner: IntervalLoadBalancer::new(
26 get_ipv4_list()
27 .into_iter()
28 .map(|v| {
29 (
30 interval,
31 ClientBuilder::new().local_address(v).build().unwrap(),
32 )
33 })
34 .collect(),
35 ),
36 }
37 }
38
39 pub fn with_ipv6(interval: Duration) -> Self {
41 Self {
42 inner: IntervalLoadBalancer::new(
43 get_ipv6_list()
44 .into_iter()
45 .map(|v| {
46 (
47 interval,
48 ClientBuilder::new().local_address(v).build().unwrap(),
49 )
50 })
51 .collect(),
52 ),
53 }
54 }
55
56 pub fn with_ipv4_timeout(interval: Duration, timeout: Duration) -> Self {
58 Self {
59 inner: IntervalLoadBalancer::new(
60 get_ipv4_list()
61 .into_iter()
62 .map(|v| {
63 (
64 interval,
65 ClientBuilder::new()
66 .local_address(v)
67 .timeout(timeout)
68 .build()
69 .unwrap(),
70 )
71 })
72 .collect(),
73 ),
74 }
75 }
76
77 pub fn with_ipv6_timeout(interval: Duration, timeout: Duration) -> Self {
79 Self {
80 inner: IntervalLoadBalancer::new(
81 get_ipv6_list()
82 .into_iter()
83 .map(|v| {
84 (
85 interval,
86 ClientBuilder::new()
87 .local_address(v)
88 .timeout(timeout)
89 .build()
90 .unwrap(),
91 )
92 })
93 .collect(),
94 ),
95 }
96 }
97
98 pub async fn update<F, R>(&self, handle: F) -> anyhow::Result<()>
100 where
101 F: Fn(Arc<std::sync::RwLock<Vec<crate::interval::Entry<Client>>>>) -> R,
102 R: std::future::Future<Output = anyhow::Result<()>>,
103 {
104 self.inner.update(handle).await
105 }
106}
107
108impl LoadBalancer<Client> for IPClientLoadBalancer {
109 fn alloc(&self) -> impl std::future::Future<Output = Client> + Send {
110 LoadBalancer::alloc(&self.inner)
111 }
112
113 fn try_alloc(&self) -> Option<Client> {
114 LoadBalancer::try_alloc(&self.inner)
115 }
116}
117
118#[async_trait]
119impl BoxLoadBalancer<Client> for IPClientLoadBalancer {
120 async fn alloc(&self) -> Client {
121 LoadBalancer::alloc(self).await
122 }
123
124 fn try_alloc(&self) -> Option<Client> {
125 LoadBalancer::try_alloc(self)
126 }
127}
128
129pub fn get_ip_list() -> Vec<IpAddr> {
131 get_if_addrs()
132 .unwrap()
133 .into_iter()
134 .filter(|v| !v.is_loopback())
135 .map(|v| v.ip())
136 .collect::<Vec<_>>()
137}
138
139pub fn get_ipv4_list() -> Vec<IpAddr> {
141 get_if_addrs()
142 .unwrap()
143 .into_iter()
144 .filter(|v| !v.is_loopback() && v.ip().is_ipv4())
145 .map(|v| v.ip())
146 .collect::<Vec<_>>()
147}
148
149pub fn get_ipv6_list() -> Vec<IpAddr> {
151 get_if_addrs()
152 .unwrap()
153 .into_iter()
154 .filter(|v| !v.is_loopback() && v.ip().is_ipv6())
155 .map(|v| v.ip())
156 .collect::<Vec<_>>()
157}