use std::io::{self, Read};
use std::time::Duration;
use brazen::Bytes;
pub(super) struct IdleChunkReader {
rx: std::sync::mpsc::Receiver<io::Result<Bytes>>,
idle: Duration,
done: bool,
}
impl IdleChunkReader {
pub(super) fn spawn<R: Read + Send + 'static>(reader: R, idle: Duration) -> Self {
let (tx, rx) = std::sync::mpsc::sync_channel::<io::Result<Bytes>>(0);
std::thread::spawn(move || {
let mut reader = reader;
loop {
let mut buf = vec![0u8; 8192];
let item = match reader.read(&mut buf) {
Ok(0) => break,
Ok(n) => {
buf.truncate(n);
Ok(buf)
}
Err(e) => Err(e),
};
let is_err = item.is_err();
if tx.send(item).is_err() || is_err {
break;
}
}
});
IdleChunkReader {
rx,
idle,
done: false,
}
}
}
impl Iterator for IdleChunkReader {
type Item = io::Result<Bytes>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
match self.rx.recv_timeout(self.idle) {
Ok(item) => {
self.done = item.is_err();
Some(item)
}
Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
self.done = true;
Some(Err(io::Error::new(
io::ErrorKind::TimedOut,
"stream stalled: no data within the idle-read timeout",
)))
}
Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
self.done = true;
None
}
}
}
}