1
0
mirror of https://github.com/actix/examples synced 2025-06-27 01:27:43 +02:00

Restructure folders (#411)

This commit is contained in:
Daniel T. Rodrigues
2021-02-25 21:57:58 -03:00
committed by GitHub
parent 9db98162b2
commit c3407627d0
334 changed files with 127 additions and 120 deletions

View File

@ -0,0 +1,104 @@
use actix_multipart::Multipart;
use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer};
use dotenv::dotenv;
use serde::{Deserialize, Serialize};
use std::borrow::BorrowMut;
use std::env;
use utils::upload::{save_file as upload_save_file, split_payload, UploadFile};
mod utils;
#[derive(Deserialize, Serialize, Debug)]
pub struct InpAdd {
pub text: String,
pub number: i32,
}
async fn save_file(mut payload: Multipart) -> Result<HttpResponse, Error> {
let pl = split_payload(payload.borrow_mut()).await;
println!("bytes={:#?}", pl.0);
let inp_info: InpAdd = serde_json::from_slice(&pl.0).unwrap();
println!("converter_struct={:#?}", inp_info);
println!("tmpfiles={:#?}", pl.1);
//make key
let s3_upload_key = format!("projects/{}/", "posts_id");
//create tmp file and upload s3 and remove tmp file
let upload_files: Vec<UploadFile> =
upload_save_file(pl.1, s3_upload_key).await.unwrap();
println!("upload_files={:#?}", upload_files);
Ok(HttpResponse::Ok().into())
}
fn index() -> HttpResponse {
let html = r#"<html>
<head><title>Upload Test</title></head>
<body>
<form target="/" method="post" enctype="multipart/form-data" id="myForm" >
<input type="text" id="text" name="text" value="test_text"/>
<input type="number" id="number" name="number" value="123123"/>
<input type="button" value="Submit" onclick="myFunction()"></button>
</form>
<input type="file" multiple name="file" id="myFile"/>
</body>
<script>
function myFunction(){
var myForm = document.getElementById('myForm');
var myFile = document.getElementById('myFile');
let formData = new FormData();
const obj = {
text: document.getElementById('text').value,
number: Number(document.getElementById('number').value)
};
const json = JSON.stringify(obj);
console.log(obj);
console.log(json);
formData.append("data", json);
formData.append("myFile", myFile.files[0]);
var request = new XMLHttpRequest();
request.open("POST", "");
request.send(formData);
}
</script>
</html>"#;
HttpResponse::Ok().body(html)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
let aws_access_key_id =
env::var("AWS_ACCESS_KEY_ID").expect("AWS_ACCESS_KEY_ID must be set");
let aws_secret_access_key =
env::var("AWS_SECRET_ACCESS_KEY").expect("AWS_SECRET_ACCESS_KEY must be set");
let aws_s3_bucket_name =
env::var("AWS_S3_BUCKET_NAME").expect("AWS_S3_BUCKET_NAME must be set");
println!("{}", aws_access_key_id);
println!("{}", aws_secret_access_key);
println!("{}", aws_s3_bucket_name);
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
std::fs::create_dir_all("./tmp").unwrap();
let ip = "0.0.0.0:3000";
HttpServer::new(|| {
App::new().wrap(middleware::Logger::default()).service(
web::resource("/")
.route(web::get().to(index))
.route(web::post().to(save_file)),
)
})
.bind(ip)?
.run()
.await
}

View File

@ -0,0 +1,2 @@
pub mod s3;
pub mod upload;

View File

@ -0,0 +1,66 @@
use rusoto_core::Region;
use rusoto_s3::S3;
use rusoto_s3::{DeleteObjectRequest, PutObjectRequest, S3Client};
use std::io::Read;
pub struct Client {
#[allow(dead_code)]
region: Region,
s3: S3Client,
bucket_name: String,
}
impl Client {
// construct S3 testing client
pub fn new() -> Client {
let region = Region::default();
Client {
region: region.to_owned(),
s3: S3Client::new(region),
bucket_name: std::env::var("AWS_S3_BUCKET_NAME").unwrap(),
}
}
pub fn url(&self, key: &str) -> String {
format!(
"https://{}.s3.{}.amazonaws.com/{}",
std::env::var("AWS_S3_BUCKET_NAME").unwrap(),
std::env::var("AWS_REGION").unwrap(),
key
)
}
pub async fn put_object(&self, localfilepath: &str, key: &str) -> String {
let mut file = std::fs::File::open(localfilepath).unwrap();
let mut contents: Vec<u8> = Vec::new();
let _ = file.read_to_end(&mut contents);
let put_request = PutObjectRequest {
bucket: self.bucket_name.to_owned(),
key: key.to_owned(),
body: Some(contents.into()),
..Default::default()
};
let _res = self
.s3
.put_object(put_request)
.await
.expect("Failed to put test object");
self.url(key)
}
pub async fn delete_object(&self, key: String) {
let delete_object_req = DeleteObjectRequest {
bucket: self.bucket_name.to_owned(),
key: key.to_owned(),
..Default::default()
};
let _res = self
.s3
.delete_object(delete_object_req)
.await
.expect("Couldn't delete object");
}
}

View File

@ -0,0 +1,124 @@
use crate::utils::s3::Client;
use actix_multipart::{Field, Multipart};
use actix_web::{web, Error};
use bytes::Bytes;
use futures::StreamExt;
use serde::{Deserialize, Serialize};
use std::convert::From;
use std::io::Write;
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct UploadFile {
pub filename: String,
pub key: String,
pub url: String,
}
impl From<Tmpfile> for UploadFile {
fn from(tmp_file: Tmpfile) -> Self {
UploadFile {
filename: tmp_file.name,
key: tmp_file.s3_key,
url: tmp_file.s3_url,
}
}
}
/*
1. savefile
2. s3 upload -> upload_data
3. deletefile
*/
#[derive(Debug, Clone)]
pub struct Tmpfile {
pub name: String,
pub tmp_path: String,
pub s3_key: String,
pub s3_url: String,
}
impl Tmpfile {
fn new(filename: &str) -> Tmpfile {
Tmpfile {
name: filename.to_string(),
tmp_path: format!("./tmp/{}", filename),
s3_key: "".to_string(),
s3_url: "".to_string(),
}
}
async fn s3_upload_and_tmp_remove(&mut self, s3_upload_key: String) {
self.s3_upload(s3_upload_key).await;
self.tmp_remove();
}
async fn s3_upload(&mut self, s3_upload_key: String) {
let key = format!("{}{}", &s3_upload_key, &self.name);
self.s3_key = key.clone();
let url: String = Client::new().put_object(&self.tmp_path, &key.clone()).await;
self.s3_url = url;
}
fn tmp_remove(&self) {
std::fs::remove_file(&self.tmp_path).unwrap();
}
}
pub async fn split_payload(payload: &mut Multipart) -> (bytes::Bytes, Vec<Tmpfile>) {
let mut tmp_files: Vec<Tmpfile> = Vec::new();
let mut data = Bytes::new();
while let Some(item) = payload.next().await {
let mut field: Field = item.expect(" split_payload err");
let content_type = field.content_disposition().unwrap();
let name = content_type.get_name().unwrap();
if name == "data" {
while let Some(chunk) = field.next().await {
data = chunk.expect(" split_payload err chunk");
}
} else {
match content_type.get_filename() {
Some(filename) => {
let tmp_file = Tmpfile::new(&sanitize_filename::sanitize(&filename));
let tmp_path = tmp_file.tmp_path.clone();
let mut f = web::block(move || std::fs::File::create(&tmp_path))
.await
.unwrap();
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
f = web::block(move || f.write_all(&data).map(|_| f))
.await
.unwrap();
}
tmp_files.push(tmp_file.clone());
}
None => {
println!("file none");
}
}
}
}
(data, tmp_files)
}
pub async fn save_file(
tmp_files: Vec<Tmpfile>,
s3_upload_key: String,
) -> Result<Vec<UploadFile>, Error> {
let mut arr: Vec<UploadFile> = Vec::with_capacity(tmp_files.len());
for item in tmp_files {
let mut tmp_file: Tmpfile = item.clone();
tmp_file
.s3_upload_and_tmp_remove(s3_upload_key.clone())
.await;
arr.push(UploadFile::from(tmp_file));
}
Ok(arr)
}
#[allow(unused)]
pub async fn delete_object(list: Vec<String>) {
for key in list {
Client::new().delete_object(key).await;
}
}