With Tokio suppose I have a StreamReader which implements AyncRead, and I want to do something with it, e.g. save it to a file:
async fn save(save_to: &Path, mut stream_reader: impl AsyncRead + Unpin) -> Result<()> {
let mut file = tokio::fs::File::create(&save_to).await?;
tokio::io::copy(&mut stream_reader, &mut file).await?;
Ok(())
}
async fn download_response(
response: reqwest::Response,
save_to: &Path,
) {
let bytes_stream = response.bytes_stream().unwrap();
let stream_reader = tokio_util::io::StreamReader::new(bytes_stream);
save(save_to, stream_reader).await.unwrap();
}
That works fine. Now what if I want to do two things with it simultaneously, e.g. saving it to two different files (not my actual use case but for simplicity):
async fn download_response(
response: reqwest::Response,
save_to_0: &Path,
save_to_1: &Path,
) {
let bytes_stream = response.bytes_stream().unwrap();
let stream_reader = tokio_util::io::StreamReader::new(bytes_stream);
let f0 = save(save_to_0, stream_reader);
let f1 = save(save_to_1, stream_reader);
join!(f0, f1);
}
This obviously doesn't work because there's only one stream_reader. How do I "duplicate" it so that it can be sent to multiple consumers? Ideally with a limit on the size of its internal buffer, to avoid the slow consumer problem (i.e. if saving to one file is very slow then you'll end up with the entire stream in memory).
Googling suggests maybe tokio_stream::wrappers::BroadcastStream could help, but I'm not sure how. Also I found fork_stream which seems like it might help but again I'm not sure (also I'd prefer a first-party solution if there is one).