use std::cell::Cell; use std::fs; use std::io::Write; 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: web::MultipartField) -> impl Future { let file_path_string = "upload.png"; let mut file = match fs::File::create(file_path_string) { Ok(file) => file, Err(e) => return Either::A(err(error::ErrorInternalServerError(e))), }; Either::B( field .fold(0i64, move |acc, bytes| { println!("CHUNK: {:?}", bytes.len()); file.write_all(bytes.as_ref()) .map(|_| acc + bytes.len() as i64) .map_err(|e| { println!("file.write_all failed: {:?}", e); error::MultipartError::Payload(error::PayloadError::Io(e)) }) }) .map_err(|e| { println!("save_file failed, {:?}", e); error::ErrorInternalServerError(e) }), ) } pub fn handle_multipart_item( item: web::MultipartItem, ) -> Box> { match item { web::MultipartItem::Field(field) => Box::new(save_file(field).into_stream()), web::MultipartItem::Nested(mp) => Box::new( mp.map_err(error::ErrorInternalServerError) .map(handle_multipart_item) .flatten(), ), } } pub fn upload( multipart: web::Multipart, counter: web::Data>, ) -> impl Future { counter.set(counter.get() + 1); println!("{:?}", counter.get()); multipart .map_err(error::ErrorInternalServerError) .map(handle_multipart_item) .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() }