1use crate::provider::BoxedBlockingProvider;
7#[cfg(feature = "tokio")]
8use crate::provider::BoxedProvider;
9use crate::types::{BuiltinProvider, IpVersion, Protocol};
10use std::time::Duration;
11
12#[derive(Debug, Clone, Copy, Default)]
14#[non_exhaustive]
15pub enum Strategy {
16 #[default]
18 First,
19 Race,
21 Consensus {
26 min_agree: usize,
28 },
29}
30
31pub struct Config {
33 pub(crate) blocking_providers: Vec<BoxedBlockingProvider>,
35 #[cfg(feature = "tokio")]
37 pub(crate) providers: Vec<BoxedProvider>,
38 pub(crate) timeout: Duration,
40 pub(crate) version: IpVersion,
42 pub(crate) strategy: Strategy,
44}
45
46impl Default for Config {
47 fn default() -> Self {
48 Self::builder().build()
49 }
50}
51
52impl Config {
53 pub fn builder() -> ConfigBuilder {
55 ConfigBuilder::new()
56 }
57}
58
59pub struct ConfigBuilder {
64 #[cfg(feature = "tokio")]
65 custom_providers: Vec<BoxedProvider>,
66 custom_blocking_providers: Vec<BoxedBlockingProvider>,
67 timeout: Duration,
68 version: IpVersion,
69 strategy: Strategy,
70 provider_filter: Option<ProviderFilter>,
71}
72
73#[derive(Clone)]
75enum ProviderFilter {
76 Protocols(Vec<Protocol>),
78 Select(Vec<BuiltinProvider>),
80}
81
82impl ConfigBuilder {
83 pub fn new() -> Self {
85 Self {
86 #[cfg(feature = "tokio")]
87 custom_providers: Vec::new(),
88 custom_blocking_providers: Vec::new(),
89 timeout: Duration::from_secs(10),
90 version: IpVersion::Any,
91 strategy: Strategy::First,
92 provider_filter: None,
93 }
94 }
95
96 pub fn protocols(mut self, protocols: &[Protocol]) -> Self {
107 self.provider_filter = Some(ProviderFilter::Protocols(protocols.to_vec()));
108 self
109 }
110
111 pub fn providers(mut self, providers: &[BuiltinProvider]) -> Self {
125 self.provider_filter = Some(ProviderFilter::Select(providers.to_vec()));
126 self
127 }
128
129 #[cfg(feature = "tokio")]
133 pub fn add_provider(mut self, provider: BoxedProvider) -> Self {
134 self.custom_providers.push(provider);
135 self
136 }
137
138 pub fn add_blocking_provider(mut self, provider: BoxedBlockingProvider) -> Self {
140 self.custom_blocking_providers.push(provider);
141 self
142 }
143
144 pub fn timeout(mut self, timeout: Duration) -> Self {
146 self.timeout = timeout;
147 self
148 }
149
150 pub fn version(mut self, version: IpVersion) -> Self {
152 self.version = version;
153 self
154 }
155
156 pub fn strategy(mut self, strategy: Strategy) -> Self {
160 self.strategy = match strategy {
161 Strategy::Consensus { min_agree } => Strategy::Consensus {
162 min_agree: min_agree.max(2),
163 },
164 other => other,
165 };
166 self
167 }
168
169 pub fn build(mut self) -> Config {
171 let filter = self.provider_filter.take();
172 #[cfg(feature = "tokio")]
173 let has_custom_providers =
174 !self.custom_blocking_providers.is_empty() || !self.custom_providers.is_empty();
175 #[cfg(not(feature = "tokio"))]
176 let has_custom_providers = !self.custom_blocking_providers.is_empty();
177
178 let mut blocking_providers: Vec<BoxedBlockingProvider> = match &filter {
180 Some(ProviderFilter::Protocols(protocols)) => BuiltinProvider::ALL
181 .iter()
182 .filter(|p| protocols.contains(&p.protocol()))
183 .map(|p| p.to_boxed_blocking())
184 .collect(),
185 Some(ProviderFilter::Select(selected)) => {
186 selected.iter().map(|p| p.to_boxed_blocking()).collect()
187 }
188 None if !has_custom_providers => BuiltinProvider::ALL
189 .iter()
190 .map(|p| p.to_boxed_blocking())
191 .collect(),
192 None => Vec::new(),
193 };
194 blocking_providers.append(&mut self.custom_blocking_providers);
195
196 #[cfg(feature = "tokio")]
198 let mut providers: Vec<BoxedProvider> = match filter {
199 Some(ProviderFilter::Protocols(protocols)) => BuiltinProvider::ALL
200 .iter()
201 .filter(|p| protocols.contains(&p.protocol()))
202 .map(|p| p.to_boxed())
203 .collect(),
204 Some(ProviderFilter::Select(selected)) => {
205 selected.into_iter().map(|p| p.to_boxed()).collect()
206 }
207 None if !has_custom_providers => {
208 BuiltinProvider::ALL.iter().map(|p| p.to_boxed()).collect()
209 }
210 None => Vec::new(),
211 };
212 #[cfg(feature = "tokio")]
213 providers.append(&mut self.custom_providers);
214
215 Config {
216 blocking_providers,
217 #[cfg(feature = "tokio")]
218 providers,
219 timeout: self.timeout,
220 version: self.version,
221 strategy: self.strategy,
222 }
223 }
224}
225
226impl Default for ConfigBuilder {
227 fn default() -> Self {
228 Self::new()
229 }
230}