1
0
mirror of https://github.com/actix/examples synced 2024-12-03 18:22:14 +01:00
examples/forms/multipart-s3/src/main.rs

123 lines
3.4 KiB
Rust
Raw Normal View History

2022-08-01 02:17:59 +02:00
use std::fs;
2022-02-18 03:13:08 +01:00
2020-02-05 04:53:33 +01:00
use actix_multipart::Multipart;
use actix_web::{
2022-08-28 19:39:28 +02:00
body::SizedStream, delete, error, get, middleware::Logger, post, web, App, Error, HttpResponse,
HttpServer, Responder,
};
2022-08-28 19:39:28 +02:00
use actix_web_lab::{extract::Path, respond::Html};
2022-08-01 02:17:59 +02:00
use aws_config::meta::region::RegionProviderChain;
2020-02-06 02:06:41 +01:00
use dotenv::dotenv;
2020-04-01 11:53:59 +02:00
use serde::{Deserialize, Serialize};
use serde_json::json;
2020-04-01 11:53:59 +02:00
mod client;
mod temp_file;
mod upload_file;
2020-04-01 11:53:59 +02:00
mod utils;
2022-08-01 02:17:59 +02:00
2022-08-28 19:39:28 +02:00
use self::{client::Client, temp_file::TempFile, upload_file::UploadedFile, utils::split_payload};
2020-02-06 02:06:41 +01:00
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UploadMeta {
namespace: String,
2020-02-05 04:53:33 +01:00
}
2020-02-06 02:06:41 +01:00
impl Default for UploadMeta {
fn default() -> Self {
Self {
namespace: "default".to_owned(),
}
}
}
#[post("/")]
async fn upload_to_s3(
2022-08-01 02:17:59 +02:00
s3_client: web::Data<Client>,
mut payload: Multipart,
) -> Result<impl Responder, Error> {
let (data, files) = split_payload(&mut payload).await;
log::info!("bytes = {data:?}");
2022-08-01 02:17:59 +02:00
let upload_meta = serde_json::from_slice::<UploadMeta>(&data).unwrap_or_default();
log::info!("converter_struct = {upload_meta:?}");
log::info!("tmp_files = {files:?}");
2022-08-01 02:17:59 +02:00
// make key prefix (make sure it ends with a forward slash)
let s3_key_prefix = format!("uploads/{}/", upload_meta.namespace);
2022-08-01 02:17:59 +02:00
// create tmp file and upload s3 and remove tmp file
let uploaded_files = s3_client.upload_files(files, &s3_key_prefix).await?;
2022-08-01 02:17:59 +02:00
Ok(HttpResponse::Ok().json(json!({
"uploadedFiles": uploaded_files,
"meta": upload_meta,
})))
2020-02-05 04:53:33 +01:00
}
#[get("/file/{s3_key}*")]
async fn fetch_from_s3(
s3_client: web::Data<Client>,
Path((s3_key,)): Path<(String,)>,
) -> Result<impl Responder, Error> {
let (file_size, file_stream) = s3_client
.fetch_file(&s3_key)
.await
.ok_or_else(|| error::ErrorNotFound("file with specified key not found"))?;
Ok(HttpResponse::Ok().body(SizedStream::new(file_size, file_stream)))
}
#[delete("/file/{s3_key}*")]
async fn delete_from_s3(
s3_client: web::Data<Client>,
Path((s3_key,)): Path<(String,)>,
) -> Result<impl Responder, Error> {
if s3_client.delete_file(&s3_key).await {
Ok(HttpResponse::NoContent().finish())
} else {
Err(error::ErrorNotFound("file with specified key not found"))
}
}
#[get("/")]
2022-08-01 02:17:59 +02:00
async fn index() -> impl Responder {
Html(include_str!("./index.html").to_owned())
2020-02-05 04:53:33 +01:00
}
2020-09-12 17:49:45 +02:00
#[actix_web::main]
2020-02-05 04:53:33 +01:00
async fn main() -> std::io::Result<()> {
2020-02-06 02:06:41 +01:00
dotenv().ok();
2022-02-18 03:13:08 +01:00
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
2022-08-01 02:17:59 +02:00
log::info!("creating temporary upload directory");
fs::create_dir_all("./tmp").unwrap();
2020-02-06 02:06:41 +01:00
2022-08-01 02:17:59 +02:00
log::info!("configuring S3 client");
let aws_region = RegionProviderChain::default_provider().or_else("us-east-1");
let aws_config = aws_config::from_env().region(aws_region).load().await;
// create singleton S3 client
2022-08-01 02:17:59 +02:00
let s3_client = Client::new(&aws_config);
2020-02-06 02:06:41 +01:00
2022-08-01 02:17:59 +02:00
log::info!("using AWS region: {}", aws_config.region().unwrap());
2020-02-05 04:53:33 +01:00
2022-02-18 03:13:08 +01:00
log::info!("starting HTTP server at http://localhost:8080");
2020-02-05 04:53:33 +01:00
2022-08-01 02:17:59 +02:00
HttpServer::new(move || {
2022-02-18 03:13:08 +01:00
App::new()
.service(index)
.service(upload_to_s3)
.service(fetch_from_s3)
.service(delete_from_s3)
2022-02-18 03:13:08 +01:00
.wrap(Logger::default())
2022-08-01 02:17:59 +02:00
.app_data(web::Data::new(s3_client.clone()))
2020-02-05 04:53:33 +01:00
})
2022-08-01 02:17:59 +02:00
.workers(2)
2022-02-18 03:13:08 +01:00
.bind(("127.0.0.1", 8080))?
2020-02-05 04:53:33 +01:00
.run()
.await
}