use crate::fat_error::{FatError, FatResult}; use crate::webserver::read_up_to_bytes_from_request; use crate::BOARD_ACCESS; use alloc::borrow::ToOwned; use alloc::format; use alloc::string::String; use edge_http::io::server::Connection; use edge_http::Method; use edge_nal::io::{Read, Write}; use log::info; pub(crate) async fn list_files( _request: &mut Connection<'_, T, N>, ) -> FatResult> { let mut board = BOARD_ACCESS.get().await.lock().await; let result = board.board_hal.get_esp().list_files().await?; let file_list_json = serde_json::to_string(&result)?; Ok(Some(file_list_json)) } pub(crate) async fn file_operations( conn: &mut Connection<'_, T, { N }>, method: Method, path: &&str, prefix: &&str, ) -> Result, FatError> where T: Read + Write, { let filename = &path[prefix.len()..]; info!("file request for {filename} with method {method}"); Ok(match method { Method::Delete => { let mut board = BOARD_ACCESS.get().await.lock().await; board .board_hal .get_esp() .delete_file(filename.to_owned()) .await?; conn.initiate_response( 200, Some("OK"), &[ ("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Headers", "*"), ("Access-Control-Allow-Methods", "*"), ], ) .await?; Some(200) } Method::Get => { let disposition = format!("attachment; filename=\"{filename}\""); let size = { let mut board = BOARD_ACCESS.get().await.lock().await; board .board_hal .get_esp() .get_size(filename.to_owned()) .await? }; conn.initiate_response( 200, Some("OK"), &[ ("Content-Type", "application/octet-stream"), ("Content-Disposition", disposition.as_str()), ("Content-Length", &format!("{size}")), ("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Headers", "*"), ("Access-Control-Allow-Methods", "*"), ], ) .await?; let mut chunk = 0; loop { let mut board = BOARD_ACCESS.get().await.lock().await; board.board_hal.progress(chunk).await; let read_chunk = board .board_hal .get_esp() .get_file(filename.to_owned(), chunk) .await?; let length = read_chunk.1; if length == 0 { info!("file request for {filename} finished"); break; } let data = &read_chunk.0[0..length]; conn.write_all(data).await?; if length < read_chunk.0.len() { info!("file request for {filename} finished"); break; } chunk += 1; } BOARD_ACCESS .get() .await .lock() .await .board_hal .clear_progress() .await; Some(200) } Method::Post => { { let mut board = BOARD_ACCESS.get().await.lock().await; //ensure the file is deleted first; otherwise we would need to truncate the file which will not work with streaming let _ = board .board_hal .get_esp() .delete_file(filename.to_owned()) .await; } let mut offset = 0_usize; let mut chunk = 0; loop { let buf = read_up_to_bytes_from_request(conn, Some(4096)).await?; if buf.is_empty() { info!("file request for {filename} finished"); break; } else { let mut board = BOARD_ACCESS.get().await.lock().await; board.board_hal.progress(chunk as u32).await; board .board_hal .get_esp() .write_file(filename.to_owned(), offset as u32, &buf) .await?; } offset += buf.len(); chunk += 1; } BOARD_ACCESS .get() .await .lock() .await .board_hal .clear_progress() .await; conn.initiate_response( 200, Some("OK"), &[ ("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Headers", "*"), ("Access-Control-Allow-Methods", "*"), ], ) .await?; Some(200) } _ => None, }) }