use std::{io, net::SocketAddr, time::Duration};
use lunatic::net::{TcpStream, ToSocketAddrs};
pub struct MyTcpBuilder<T> {
address: T,
bind_address: Option<SocketAddr>,
connect_timeout: Option<Duration>,
read_timeout: Option<Duration>,
write_timeout: Option<Duration>,
keepalive_time_ms: Option<u32>,
}
impl<T: ToSocketAddrs> MyTcpBuilder<T> {
pub fn keepalive_time_ms(&mut self, keepalive_time_ms: Option<u32>) -> &mut Self {
self.keepalive_time_ms = keepalive_time_ms;
self
}
pub fn write_timeout(&mut self, write_timeout: Option<Duration>) -> &mut Self {
self.write_timeout = write_timeout;
self
}
pub fn read_timeout(&mut self, read_timeout: Option<Duration>) -> &mut Self {
self.read_timeout = read_timeout;
self
}
pub fn bind_address<U>(&mut self, bind_address: Option<U>) -> &mut Self
where
U: Into<SocketAddr>,
{
self.bind_address = bind_address.map(Into::into);
self
}
pub fn connect_timeout(&mut self, timeout: Option<Duration>) -> &mut Self {
self.connect_timeout = timeout;
self
}
pub fn new(address: T) -> MyTcpBuilder<T> {
MyTcpBuilder {
address,
bind_address: None,
connect_timeout: None,
read_timeout: None,
write_timeout: None,
keepalive_time_ms: None,
}
}
pub fn connect(self) -> io::Result<TcpStream> {
let MyTcpBuilder {
address,
bind_address,
..
} = self;
let err_msg = if bind_address.is_none() {
"could not connect to any address"
} else {
"could not connect to any address with specified bind address"
};
let err = io::Error::new(io::ErrorKind::Other, err_msg);
let addrs = address.to_socket_addrs()?.collect::<Vec<_>>();
let socket = if let Some(bind_address) = bind_address {
let fold_fun = |prev, _sock_addr: &SocketAddr| match prev {
Ok(socket) => Ok(socket),
Err(_) => Ok(TcpStream::connect(bind_address).unwrap()),
};
if bind_address.is_ipv4() {
addrs
.iter()
.filter(|x| x.is_ipv4())
.fold(Err(err), fold_fun)
.or_else(|e| addrs.iter().filter(|x| x.is_ipv6()).fold(Err(e), fold_fun))
} else {
addrs
.iter()
.filter(|x| x.is_ipv6())
.fold(Err(err), fold_fun)
.or_else(|e| addrs.iter().filter(|x| x.is_ipv4()).fold(Err(e), fold_fun))
}
} else {
addrs
.into_iter()
.fold(Err(err), |prev, sock_addr| match prev {
Ok(socket) => Ok(socket),
Err(_) => Ok(TcpStream::connect(sock_addr).unwrap()),
})
}?;
Ok(socket)
}
}