use crate::state::AppState; use axum::{body::Body, extract::State, response::Response}; use std::sync::Arc; use tokio_stream::Stream; pub async fn stream_handler(State(state): State>) -> Response { state.clone().check_update().await; let stream = create_chunk_stream(state); let body = Body::from_stream(stream); Response::builder() .header("Content-Type", "audio/mpeg") .header("Cache-Control", "no-cache, no-store, must-revalidate") .header("Pragma", "no-cache") .header("Expires", "0") .header("Accept-Ranges", "none") .header("Transfer-Encoding", "chunked") .header("X-Content-Duration", "infinity") .body(body) .unwrap() } fn create_chunk_stream( state: Arc, ) -> impl Stream> { async_stream::stream! { let mut position = 0; loop { // Send available chunks let chunks = state.chunks.read().await; while position < chunks.len() { yield Ok(chunks[position].clone()); position += 1; } drop(chunks); // Exit if download complete and all chunks sent if state.is_complete().await && position >= state.chunk_count().await { break; } // Wait for new chunks state.notify.notified().await; } } }