retrieve.rs
1 use crate::base::kit::{DIRECTORY, path_is_valid}; 2 use crate::base::kit::{format_size, get_mime_type, show_usage}; 3 use axum::{ 4 body::Body, 5 extract::Path, 6 http::{Response, StatusCode, header}, 7 response::{Html, IntoResponse}, 8 }; 9 10 use tokio_util::io::ReaderStream; 11 12 pub async fn list_items() -> Result<Html<String>, (StatusCode, String)> { 13 use crate::base::templates::items_list_page; 14 15 let mut entries = tokio::fs::read_dir(DIRECTORY) 16 .await 17 .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; 18 19 let mut files_html = String::from("<ul class='file-list'>"); 20 while let Some(entry) = entries 21 .next_entry() 22 .await 23 .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))? 24 { 25 let filename = entry.file_name().to_string_lossy().to_string(); 26 files_html.push_str(&format!( 27 "<li><a href='/download/{}'>{}</a></li>", 28 filename, filename 29 )); 30 } 31 files_html.push_str("</ul>"); 32 33 let stats_html = match show_usage().await { 34 Ok((total_size, file_count)) => { 35 let size_str = format_size(total_size); 36 Some(format!( 37 "<p class='stats'>Total: {} files, {}</p>", 38 file_count, size_str 39 )) 40 } 41 Err(_) => None, 42 }; 43 44 Ok(items_list_page(files_html, stats_html).await) 45 } 46 47 pub async fn get_item( 48 Path(filename): Path<String>, 49 ) -> Result<impl IntoResponse, (StatusCode, String)> { 50 if !path_is_valid(&filename) { 51 return Err((StatusCode::BAD_REQUEST, "Invalid path".to_owned())); 52 } 53 54 let path = std::path::Path::new(DIRECTORY).join(&filename); 55 let file = tokio::fs::File::open(path) 56 .await 57 .map_err(|e| (StatusCode::NOT_FOUND, e.to_string()))?; 58 59 let stream = ReaderStream::new(file); 60 61 let body = Body::from_stream(stream); 62 63 let mime_type = get_mime_type(&filename); 64 let response = Response::builder() 65 .status(StatusCode::OK) 66 .header(header::CONTENT_TYPE, mime_type) 67 .header( 68 header::CONTENT_DISPOSITION, 69 format!("attachment; filename=\"{}\"", filename), 70 ) 71 .body(body) 72 .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; 73 74 Ok(response) 75 }