use crate::state::AppState; use std::{sync::Arc, time::Duration}; use tokio::time::timeout; use tokio_stream::StreamExt; pub async fn spawn_download_task(url: &str, state: Arc) { state.reset().await; let url = url.to_string(); tokio::spawn(async move { if let Err(e) = download_stream(&url, state).await { eprintln!("Download failed: {e:?}"); } }); } async fn download_stream(url: &str, state: Arc) -> Result<(), reqwest::Error> { println!("Starting download from: {url}"); let response = reqwest::Client::new().get(url).send().await?; let mut stream = response.bytes_stream(); loop { let Ok(bytes) = timeout(Duration::from_secs(5), stream.next()).await else { println!("Error fetching stream, trying again..."); continue; }; if handle_bytes(bytes, state.clone()).await { break; } } state.mark_complete().await; println!("Download complete!"); Ok(()) } /// Returns if the end (= no more bytes) has been received async fn handle_bytes( bytes: Option>, state: Arc, ) -> bool { // TODO: switch checks, such that `.transpose()` is not needed anymore let bytes = match bytes.transpose() { Ok(bytes) => bytes, Err(e) => { println!("Error fetching chunk from stream: {e:?}"); return false; } }; if let Some(bytes) = bytes { state.add_chunk(bytes).await; false } else { true } }