use crate::provider::BoxedProvider;
use crate::types::{BuiltinProvider, IpVersion, Protocol};
use std::time::Duration;
#[derive(Debug, Clone, Copy, Default)]
#[non_exhaustive]
pub enum Strategy {
#[default]
First,
Race,
Consensus {
min_agree: usize,
},
}
pub struct Config {
pub(crate) providers: Vec<BoxedProvider>,
pub(crate) timeout: Duration,
pub(crate) version: IpVersion,
pub(crate) strategy: Strategy,
}
impl Default for Config {
fn default() -> Self {
Self::builder().build()
}
}
impl Config {
pub fn builder() -> ConfigBuilder {
ConfigBuilder::new()
}
}
pub struct ConfigBuilder {
custom_providers: Vec<BoxedProvider>,
timeout: Duration,
version: IpVersion,
strategy: Strategy,
provider_filter: Option<ProviderFilter>,
}
enum ProviderFilter {
Protocols(Vec<Protocol>),
Select(Vec<BuiltinProvider>),
}
impl ConfigBuilder {
pub fn new() -> Self {
Self {
custom_providers: Vec::new(),
timeout: Duration::from_secs(10),
version: IpVersion::Any,
strategy: Strategy::First,
provider_filter: None,
}
}
pub fn protocols(mut self, protocols: &[Protocol]) -> Self {
self.provider_filter = Some(ProviderFilter::Protocols(protocols.to_vec()));
self
}
pub fn providers(mut self, providers: &[BuiltinProvider]) -> Self {
self.provider_filter = Some(ProviderFilter::Select(providers.to_vec()));
self
}
pub fn add_provider(mut self, provider: BoxedProvider) -> Self {
self.custom_providers.push(provider);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn version(mut self, version: IpVersion) -> Self {
self.version = version;
self
}
pub fn strategy(mut self, strategy: Strategy) -> Self {
self.strategy = match strategy {
Strategy::Consensus { min_agree } => Strategy::Consensus {
min_agree: min_agree.max(2),
},
other => other,
};
self
}
pub fn build(mut self) -> Config {
let mut providers: Vec<BoxedProvider> = match self.provider_filter.take() {
Some(ProviderFilter::Protocols(protocols)) => BuiltinProvider::ALL
.iter()
.filter(|p| protocols.contains(&p.protocol()))
.map(|p| p.to_boxed())
.collect(),
Some(ProviderFilter::Select(selected)) => {
selected.into_iter().map(|p| p.to_boxed()).collect()
}
None if self.custom_providers.is_empty() => {
BuiltinProvider::ALL.iter().map(|p| p.to_boxed()).collect()
}
None => Vec::new(),
};
providers.append(&mut self.custom_providers);
Config {
providers,
timeout: self.timeout,
version: self.version,
strategy: self.strategy,
}
}
}
impl Default for ConfigBuilder {
fn default() -> Self {
Self::new()
}
}