1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
// Copyright (c) 2022 FL33TW00D (https://github.com/FL33TW00D)
// Copyright (c) 2021 Harry [Majored] [hello@majored.pw]
// MIT License (https://github.com/Majored/rs-async-zip/blob/main/LICENSE
#[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_lite::io::AsyncWriteExt;
use tokio::fs::File;
use uuid::Uuid;
const TMP_DIR: &str = "./tmp/";
#[derive(Debug, Display, Error)]
#[display("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(())
}
|