use futures::{
failed,
future::{select_ok, SelectOk},
try_ready,
Async::{self, Ready},
Failed, Future, Poll,
};
use tokio::net::{tcp::ConnectFuture, TcpStream};
use tokio_codec::Framed;
use std::{io, net::ToSocketAddrs};
use crate::{
error::*,
io::{packet_codec::PacketCodec, Stream},
};
steps! {
ConnectingTcpStream {
WaitForStream(SelectOk<ConnectFuture>),
Fail(Failed<(), Error>),
}
}
pub struct ConnectingTcpStream {
step: Step,
}
pub fn new<S>(addr: S) -> ConnectingTcpStream
where
S: ToSocketAddrs,
{
match addr.to_socket_addrs() {
Ok(addresses) => {
let mut streams = Vec::new();
for address in addresses {
streams.push(TcpStream::connect(&address));
}
if !streams.is_empty() {
ConnectingTcpStream {
step: Step::WaitForStream(select_ok(streams)),
}
} else {
let err = io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any address",
);
ConnectingTcpStream {
step: Step::Fail(failed(err.into())),
}
}
}
Err(err) => ConnectingTcpStream {
step: Step::Fail(failed(err.into())),
},
}
}
impl Future for ConnectingTcpStream {
type Item = Stream;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match try_ready!(self.either_poll()) {
Out::WaitForStream((stream, _)) => Ok(Ready(Stream {
closed: false,
codec: Box::new(Framed::new(stream.into(), PacketCodec::new())).into(),
})),
Out::Fail(_) => unreachable!(),
}
}
}