#[cfg(features = "deflate")]
mod inner {
use async_zip::write::ZipFileWriter;
use async_zip::{Compression, ZipEntryBuilder};
use std::path::Path;
use actix_multipart::Multipart;
use actix_web::{web, App, HttpServer, Responder, ResponseError, Result};
use derive_more::{Display, Error};
use futures::StreamExt;
use futures_util::io::AsyncWriteExt;
use tokio::fs::File;
use uuid::Uuid;
const TMP_DIR: &str = "./tmp/";
#[derive(Debug, Display, Error)]
#[display(fmt = "An error occurred during ZIP creation which was logged to stderr.")]
struct CreationError;
impl ResponseError for CreationError {}
async fn do_main() -> std::io::Result<()> {
let tmp_path = Path::new(TMP_DIR);
if !tmp_path.exists() {
tokio::fs::create_dir(tmp_path).await?;
}
let factory = || App::new().route("/", web::post().to(handler));
HttpServer::new(factory).bind(("127.0.0.1", 8080))?.run().await
}
async fn handler(multipart: Multipart) -> Result<impl Responder, CreationError> {
match create_archive(multipart).await {
Ok(name) => Ok(format!("Successfully created archive: {}", name)),
Err(err) => {
eprintln!("[ERROR] {:?}", err);
Err(CreationError)
}
}
}
async fn create_archive(mut body: Multipart) -> Result<String, anyhow::Error> {
let archive_name = format!("tmp/{}", Uuid::new_v4());
let mut archive = File::create(archive_name.clone()).await?;
let mut writer = ZipFileWriter::new(&mut archive);
while let Some(item) = body.next().await {
let mut field = item?;
let filename = match field.content_disposition().get_filename() {
Some(filename) => sanitize_filename::sanitize(filename),
None => Uuid::new_v4().to_string(),
};
let builder = ZipEntryBuilder::new(filename, Compression::Deflate);
let mut entry_writer = writer.write_entry_stream(builder).await.unwrap();
while let Some(chunk) = field.next().await {
entry_writer.write_all_buf(&mut chunk?).await?;
}
entry_writer.close().await.unwrap();
}
writer.close().await.unwrap();
archive.shutdown().await.unwrap();
Ok(archive_name)
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
#[cfg(features = "deflate")]
{
inner::do_main().await?;
}
Ok(())
}