1
0
mirror of https://github.com/actix/examples synced 2025-06-29 02:10:36 +02:00

Update Multipart example (#196)

* add async/await multipart example

* fix

* replace multipart

* make PR feedback changes

* remove port & heroku & update readme

* update cargo.toml to be correct

* update to alpha 3
This commit is contained in:
Bevan Hunt
2019-12-07 06:40:31 -08:00
committed by Nikolay Kim
parent 1f434406f3
commit 3552b29359
9 changed files with 75 additions and 117 deletions

View File

@ -1,67 +1,27 @@
use std::cell::Cell;
use std::fs;
use std::io::Write;
use actix_multipart::Multipart;
use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer};
use futures::{StreamExt};
use actix_multipart::{Field, Multipart, MultipartError};
use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer};
use futures::future::{err, Either};
use futures::{Future, Stream};
pub struct AppState {
pub counter: Cell<usize>,
}
pub fn save_file(field: Field) -> impl Future<Item = i64, Error = Error> {
let file_path_string = "upload.png";
let file = match fs::File::create(file_path_string) {
Ok(file) => file,
Err(e) => return Either::A(err(error::ErrorInternalServerError(e))),
};
Either::B(
field
.fold((file, 0i64), move |(mut file, mut acc), bytes| {
// fs operations are blocking, we have to execute writes
// on threadpool
web::block(move || {
file.write_all(bytes.as_ref()).map_err(|e| {
println!("file.write_all failed: {:?}", e);
MultipartError::Payload(error::PayloadError::Io(e))
})?;
acc += bytes.len() as i64;
Ok((file, acc))
})
.map_err(|e: error::BlockingError<MultipartError>| {
match e {
error::BlockingError::Error(e) => e,
error::BlockingError::Canceled => MultipartError::Incomplete,
}
})
})
.map(|(_, acc)| acc)
.map_err(|e| {
println!("save_file failed, {:?}", e);
error::ErrorInternalServerError(e)
}),
)
}
pub fn upload(
multipart: Multipart,
counter: web::Data<Cell<usize>>,
) -> impl Future<Item = HttpResponse, Error = Error> {
counter.set(counter.get() + 1);
println!("{:?}", counter.get());
multipart
.map_err(error::ErrorInternalServerError)
.map(|field| save_file(field).into_stream())
.flatten()
.collect()
.map(|sizes| HttpResponse::Ok().json(sizes))
.map_err(|e| {
println!("failed: {}", e);
e
})
async fn save_file(mut payload: Multipart) -> Result<HttpResponse, Error> {
// iterate over multipart stream
while let Some(item) = payload.next().await {
let mut field = item?;
let content_type = field.content_disposition().unwrap();
let filename = content_type.get_filename().unwrap();
let filepath = format!("./tmp/{}", filename);
let mut f = std::fs::File::create(filepath).unwrap();
// Field in turn is stream of *Bytes* object
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
let mut pos = 0;
while pos < data.len() {
let bytes_written = f.write(&data[pos..])?;
pos += bytes_written;
}
}
}
Ok(HttpResponse::Ok().into())
}
fn index() -> HttpResponse {
@ -69,7 +29,7 @@ fn index() -> HttpResponse {
<head><title>Upload Test</title></head>
<body>
<form target="/" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="file" multiple name="file"/>
<input type="submit" value="Submit"></button>
</form>
</body>
@ -80,18 +40,17 @@ fn index() -> HttpResponse {
fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
env_logger::init();
std::fs::create_dir_all("./tmp").unwrap();
let ip = "0.0.0.0:3000";
HttpServer::new(|| {
App::new()
.data(Cell::new(0usize))
.wrap(middleware::Logger::default())
.service(
web::resource("/")
.route(web::get().to(index))
.route(web::post().to_async(upload)),
)
App::new()
.wrap(middleware::Logger::default())
.service(
web::resource("/")
.route(web::get().to(index))
.route(web::post().to(save_file)),
)
})
.bind("127.0.0.1:8080")?
.bind(ip)?
.run()
}