use crate::clients::Exchanger;
use crate::Message;
use crate::clients::stats::StatsBuilder;
use std::io::Read;
use std::io::Write;
use std::net::SocketAddr;
use std::net::TcpStream;
use std::net::ToSocketAddrs;
use std::time::Duration;
pub const GOOGLE_IPV4_PRIMARY: &str = "8.8.8.8:53";
pub const GOOGLE_IPV4_SECONDARY: &str = "8.8.4.4:53";
pub const GOOGLE_IPV6_PRIMARY: &str = "2001:4860:4860::8888:53";
pub const GOOGLE_IPV6_SECONDARY: &str = "2001:4860:4860::8844:53";
pub const GOOGLE: [&str; 4] = [
GOOGLE_IPV4_PRIMARY,
GOOGLE_IPV4_SECONDARY,
GOOGLE_IPV6_PRIMARY,
GOOGLE_IPV6_SECONDARY,
];
pub struct Client {
servers: Vec<SocketAddr>,
connect_timeout: Duration,
read_timeout: Option<Duration>,
write_timeout: Option<Duration>,
}
impl Default for Client {
fn default() -> Self {
Client {
servers: Vec::default(),
connect_timeout: Duration::new(5, 0),
read_timeout: Some(Duration::new(5, 0)),
write_timeout: Some(Duration::new(5, 0)),
}
}
}
impl Client {
pub fn new<A: ToSocketAddrs>(servers: A) -> Result<Self, crate::Error> {
let servers = servers.to_socket_addrs()?.collect();
Ok(Self {
servers,
..Default::default()
})
}
}
impl Exchanger for Client {
fn exchange(&self, query: &Message) -> Result<Message, crate::Error> {
let mut stream = TcpStream::connect_timeout(&self.servers[0], self.connect_timeout)?;
stream.set_nodelay(true)?; stream.set_read_timeout(self.read_timeout)?;
stream.set_write_timeout(self.write_timeout)?;
let message = query.to_vec()?;
let stats = StatsBuilder::start(message.len() + 2);
stream.write_all(&(message.len() as u16).to_be_bytes())?;
stream.write_all(&message)?;
let buf = &mut [0; 2];
stream.read_exact(buf)?;
let len = u16::from_be_bytes(*buf);
let mut buf = vec![0; len.into()];
stream.read_exact(&mut buf)?;
let mut resp = Message::from_slice(&buf)?;
resp.stats = Some(stats.end(stream.peer_addr()?, (len + 2).into()));
Ok(resp)
}
}