//! static file handling //! //! Reads files from the filesystem and prepares a `Response` for them. use axum::{body::Body, response::Response}; use tokio_util::io::ReaderStream; use crate::{ RuntimeError, fs::{self, Mimetype, RequestPath}, }; /// 5 MiB /// /// Files smaller than this size will be read into memory before being /// sent back to the client. const STREAM_AFTER: u64 = 1024 * 1024 * 5; pub async fn send_or_stream_file(path: RequestPath) -> Result { let meta = path.system_path().metadata()?; if meta.len() > STREAM_AFTER { tracing::trace!("File is large, Streaming"); stream_file(path).await } else { tracing::trace!("File is small, Sending"); send_file(path).await } } pub async fn send_file(path: RequestPath) -> Result { let mime = path.guess_mime(); let body = match mime.mimetype() { Mimetype::Text => { let text = fs::read_file_to_string(path.system_path()).await?; Body::from(text) } Mimetype::Media => { let data = fs::read_file(path.system_path()).await?; Body::from(data) } }; Response::builder() .status(200) .header("Content-Type", mime.as_ref()) .body(body) .map_err(|_| RuntimeError::unknown()) } pub async fn stream_file(path: RequestPath) -> Result { let mime = path.guess_mime(); let file = fs::open_file(path.system_path()).await?; let stream = ReaderStream::new(file); Response::builder() .status(200) .header("Content-Type", mime.as_ref()) .body(Body::from_stream(stream)) .map_err(|_| RuntimeError::unknown()) }