use std::collections::VecDeque;
use std::net::SocketAddr;
#[derive(Clone, Debug)]
pub struct EndpointList {
endpoints: Vec<String>,
pending_endpoints: VecDeque<SocketAddr>,
current_endpoint: usize,
}
impl EndpointList {
pub fn single(addr: String) -> Self {
Self::new(addr, &[])
}
pub fn new(addr: String, fail_overs_list: &[String]) -> Self {
let mut endpoints = vec![addr];
endpoints.extend_from_slice(fail_overs_list);
Self {
endpoints,
pending_endpoints: VecDeque::new(),
current_endpoint: 0,
}
}
pub fn add(&mut self, addr: String) {
self.endpoints.push(addr);
}
pub fn main_addr(&self) -> &str {
self.endpoints.first().unwrap()
}
pub(crate) fn reset(&mut self) {
self.pending_endpoints.clear();
self.current_endpoint = 0;
}
pub(crate) async fn next_address(&mut self) -> Option<SocketAddr> {
if let Some(endpoint) = self.pending_endpoints.pop_front() {
return Some(endpoint);
}
let start_idx = self.current_endpoint;
loop {
let endpoint_idx = self.current_endpoint;
self.current_endpoint = (self.current_endpoint + 1) % self.endpoints.len();
if let Ok(endpoints) = tokio::net::lookup_host(&self.endpoints[endpoint_idx]).await {
self.pending_endpoints = endpoints.collect();
if let Some(endpoint) = self.pending_endpoints.pop_front() {
return Some(endpoint);
}
} else {
tracing::warn!("unable to resolve \"{}\"", &self.endpoints[endpoint_idx]);
}
if start_idx == self.current_endpoint {
return None;
}
}
}
}