use std::collections::HashMap;
use std::io;
use std::mem;
use std::net::SocketAddr;
use std::time::Duration;
use futures::{Future, Stream, Async};
use tokio::net::{TcpListener, Incoming, TcpStream};
use tokio::clock;
use tokio::timer::Delay;
pub struct BindMany<S> {
addresses: S,
retry_interval: Duration,
retry_timer: Option<(Delay, Vec<SocketAddr>)>,
inputs: HashMap<SocketAddr, Incoming>,
}
impl<S> BindMany<S> {
pub fn new(s: S) -> BindMany<S>
{
BindMany {
addresses: s,
retry_interval: Duration::new(1, 0),
retry_timer: None,
inputs: HashMap::new(),
}
}
pub fn retry_interval(&mut self, interval: Duration) -> &mut Self {
self.retry_interval = interval;
self
}
}
impl<S> Stream for BindMany<S>
where S: Stream,
S::Item: IntoIterator<Item=SocketAddr>,
{
type Item = TcpStream;
type Error = io::Error;
fn poll(&mut self) -> Result<Async<Option<Self::Item>>, io::Error> {
loop {
match self.addresses.poll() {
Ok(Async::Ready(None)) => {
info!("Listening stream reached end-of-stream condition");
return Ok(Async::Ready(None));
}
Ok(Async::Ready(Some(new))) => {
let mut old = mem::replace(&mut self.inputs,
HashMap::new());
let mut backlog = Vec::new();
for addr in new {
if let Some(listener) = old.remove(&addr) {
self.inputs.insert(addr, listener);
} else {
match TcpListener::bind(&addr) {
Ok(l) => {
self.inputs.insert(addr, l.incoming());
}
Err(e) => {
backlog.push(addr);
error!("Error binding {:?}: {}, \
will retry in {:?}",
addr, e, self.retry_interval);
}
}
}
}
if backlog.len() > 0 {
self.retry_timer = Some((
Delay::new(clock::now() + self.retry_interval),
backlog));
} else {
self.retry_timer = None;
}
}
Ok(Async::NotReady) => break,
Err(_) => {
error!("Error in address stream");
return Ok(Async::Ready(None));
}
}
}
loop {
if let Some((ref mut timer, ref mut backlog)) = self.retry_timer {
match timer.poll().expect("deadline never fails") {
Async::Ready(()) => {
for addr in mem::replace(backlog, Vec::new()) {
match TcpListener::bind(&addr) {
Ok(l) => {
self.inputs.insert(addr, l.incoming());
}
Err(e) => {
backlog.push(addr);
debug!("Error binding {:?}: {}, \
will retry in {:?}",
addr, e, self.retry_interval);
}
}
}
if backlog.len() > 0 {
*timer = Delay::new(
clock::now() + self.retry_interval
);
continue; }
}
Async::NotReady => break,
}
}
self.retry_timer = None;
break;
}
for inp in self.inputs.values_mut() {
loop {
match inp.poll() {
Ok(Async::Ready(pair)) => {
return Ok(Async::Ready(pair));
}
Ok(Async::NotReady) => break,
Err(e) => return Err(e),
}
}
}
return Ok(Async::NotReady);
}
}