use std::cell::Cell; use std::fs; use std::io::Write; 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, } pub fn save_file(field: Field) -> impl Future { 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| { 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>, ) -> impl Future { 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 }) } fn index() -> HttpResponse { let html = r#" Upload Test
"#; HttpResponse::Ok().body(html) } fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); env_logger::init(); 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)), ) }) .bind("127.0.0.1:8080")? .run() }