/ src / base / leave.rs
leave.rs
 1  use crate::base::kit::{DIRECTORY, path_is_valid};
 2  use axum::{
 3      BoxError,
 4      body::Bytes,
 5      extract::{Multipart, Path, Request},
 6      http::StatusCode,
 7      response::Redirect,
 8  };
 9  use futures::{Stream, TryStreamExt};
10  use std::io;
11  
12  use tokio::{fs::File, io::BufWriter};
13  
14  use tokio_util::io::StreamReader;
15  
16  pub async fn save_request_body(
17      Path(file_name): Path<String>,
18      request: Request,
19  ) -> Result<(), (StatusCode, String)> {
20      stream_to_item(&file_name, request.into_body().into_data_stream()).await
21  }
22  
23  pub async fn accept_items(
24      mut multipart: Multipart,
25  ) -> Result<Redirect, (StatusCode, String)> {
26      while let Ok(Some(field)) = multipart.next_field().await {
27          let file_name = if let Some(file_name) = field.file_name() {
28              file_name.to_owned()
29          } else {
30              continue;
31          };
32  
33          stream_to_item(&file_name, field).await?;
34      }
35  
36      Ok(Redirect::to("/done"))
37  }
38  
39  async fn stream_to_item<S, E>(
40      path: &str,
41      stream: S,
42  ) -> Result<(), (StatusCode, String)>
43  where
44      S: Stream<Item = Result<Bytes, E>>,
45      E: Into<BoxError>,
46  {
47      if !path_is_valid(path) {
48          return Err((StatusCode::BAD_REQUEST, "Invalid path".to_owned()));
49      }
50  
51      async {
52          let body_with_io_error = stream.map_err(|err| io::Error::other(err));
53          let body_reader = StreamReader::new(body_with_io_error);
54          futures::pin_mut!(body_reader);
55  
56          let path = std::path::Path::new(DIRECTORY).join(path);
57          let mut file = BufWriter::new(File::create(path).await?);
58  
59          tokio::io::copy(&mut body_reader, &mut file).await?;
60          tracing::info!("File uploaded");
61          Ok::<_, io::Error>(())
62      }
63      .await
64      .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))
65  }