Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
16cb3c3
commit 8859b5c
Showing
5 changed files
with
127 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use std::io; | ||
use std::mem; | ||
use std::time::Duration; | ||
|
||
use futures::{Async, Future, Poll}; | ||
use futures::stream::Stream; | ||
use tokio_core::reactor::{Handle, Timeout}; | ||
|
||
/// This wraps the underlying Stream in a timeout. | ||
/// | ||
/// Any `Ok(Async::Ready(_))` from the underlying Stream will reset the timeout. | ||
pub struct TimeoutStream<S> { | ||
stream: S, | ||
reactor_handle: Handle, | ||
timeout_duration: Duration, | ||
timeout: Timeout, | ||
} | ||
|
||
impl<S> TimeoutStream<S> { | ||
pub fn new(stream: S, timeout_duration: Duration, reactor_handle: Handle) -> io::Result<Self> { | ||
// store a Timeout for this message before sending | ||
let timeout = try!(Timeout::new(timeout_duration, &reactor_handle)); | ||
Ok(TimeoutStream{ stream: stream, reactor_handle: reactor_handle, timeout_duration: timeout_duration, timeout: timeout }) | ||
} | ||
} | ||
|
||
impl<S, I> Stream for TimeoutStream<S> | ||
where S: Stream<Item=I, Error=io::Error> { | ||
type Item = I; | ||
type Error = io::Error; | ||
|
||
// somehow insert a timeout here... | ||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { | ||
match self.stream.poll() { | ||
r @ Ok(Async::Ready(_)) | r @ Err(_) => { | ||
// reset the timeout to wait for the next request... | ||
let timeout = try!(Timeout::new(self.timeout_duration, &self.reactor_handle)); | ||
drop(mem::replace(&mut self.timeout, timeout)); | ||
|
||
return r | ||
}, | ||
Ok(Async::NotReady) => { | ||
// otherwise poll the timeout | ||
match try_ready!(self.timeout.poll()) { | ||
() => return Err(io::Error::new(io::ErrorKind::TimedOut, format!("nothing ready in {:?}", self.timeout_duration))), | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
extern crate futures; | ||
extern crate tokio_core; | ||
extern crate trust_dns_server; | ||
|
||
use std::io; | ||
use std::time::Duration; | ||
use futures::{Async, Poll}; | ||
use futures::stream::{iter, Stream}; | ||
use tokio_core::reactor::Core; | ||
|
||
use trust_dns_server::server::TimeoutStream; | ||
|
||
#[test] | ||
fn test_no_timeout() { | ||
let sequence = iter(vec![Ok(1), Err("error"), Ok(2)]).map_err(|e| io::Error::new(io::ErrorKind::Other, e)); | ||
let mut core = Core::new().expect("could not get core"); | ||
|
||
let timeout_stream = TimeoutStream::new(sequence, Duration::from_secs(360), core.handle()).expect("could not create timeout_stream"); | ||
|
||
let (val, timeout_stream) = core.run(timeout_stream.into_future()).ok().expect("first run failed"); | ||
assert_eq!(val, Some(1)); | ||
|
||
let error = core.run(timeout_stream.into_future()); | ||
assert!(error.is_err()); | ||
|
||
let (_, timeout_stream) = error.err().unwrap(); | ||
|
||
let (val, timeout_stream) = core.run(timeout_stream.into_future()).ok().expect("third run failed"); | ||
assert_eq!(val, Some(2)); | ||
|
||
let (val, _) = core.run(timeout_stream.into_future()).ok().expect("fourth run failed"); | ||
assert!(val.is_none()) | ||
} | ||
|
||
struct NeverStream {} | ||
|
||
impl Stream for NeverStream { | ||
type Item = (); | ||
type Error = io::Error; | ||
|
||
// somehow insert a timeout here... | ||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { | ||
Ok(Async::NotReady) | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_timeout() { | ||
let mut core = Core::new().expect("could not get core"); | ||
let timeout_stream = TimeoutStream::new(NeverStream{}, Duration::from_millis(1), core.handle()).expect("could not create timeout_stream"); | ||
|
||
assert!(core.run(timeout_stream.into_future()).is_err()); | ||
} |