diff --git a/multipart/src/main.rs b/multipart/src/main.rs index f9e8919a..2945ab51 100644 --- a/multipart/src/main.rs +++ b/multipart/src/main.rs @@ -4,54 +4,101 @@ extern crate actix_web; extern crate env_logger; extern crate futures; -use actix::*; +use std::fs; +use std::io::Write; + use actix_web::{ - http, middleware, multipart, server, App, AsyncResponder, Error, HttpMessage, + error, http, middleware, multipart, server, App, Error, FutureResponse, HttpMessage, HttpRequest, HttpResponse, }; -use futures::future::{result, Either}; +use futures::future; use futures::{Future, Stream}; -fn index(req: HttpRequest) -> Box> { - println!("{:?}", req); +pub fn save_file( + field: multipart::Field, +) -> Box> { + let file_path_string = "upload.png"; + let mut file = match fs::File::create(file_path_string) { + Ok(file) => file, + Err(e) => return Box::new(future::err(error::ErrorInternalServerError(e))), + }; + Box::new( + field + .fold(0i64, move |acc, bytes| { + let rt = 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)) + }); + future::result(rt) + }) + .map_err(|e| { + println!("save_file failed, {:?}", e); + error::ErrorInternalServerError(e) + }), + ) +} - req.multipart() // <- get multipart stream for current request - .from_err() // <- convert multipart errors - .and_then(|item| { // <- iterate over multipart items - match item { - // Handle multipart Field - multipart::MultipartItem::Field(field) => { - println!("==== FIELD ==== {:?}", field); +pub fn handle_multipart_item( + item: multipart::MultipartItem, +) -> Box> { + match item { + multipart::MultipartItem::Field(field) => { + Box::new(save_file(field).into_stream()) + } + multipart::MultipartItem::Nested(mp) => Box::new( + mp.map_err(error::ErrorInternalServerError) + .map(handle_multipart_item) + .flatten(), + ), + } +} - // Field in turn is stream of *Bytes* object - Either::A( - field.map_err(Error::from) - .map(|chunk| { - println!("-- CHUNK: \n{}", - std::str::from_utf8(&chunk).unwrap());}) - .finish()) - }, - multipart::MultipartItem::Nested(mp) => { - // Or item could be nested Multipart stream - Either::B(result(Ok(()))) - } - } - }) - .finish() // <- Stream::finish() combinator from actix - .map(|_| HttpResponse::Ok().into()) - .responder() +pub fn upload(req: HttpRequest) -> FutureResponse { + Box::new( + req.clone() + .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(_req: HttpRequest) -> Result { + let html = r#" + Upload Test + +
+ + +
+ + "#; + + Ok(HttpResponse::Ok().body(html)) } fn main() { ::std::env::set_var("RUST_LOG", "actix_web=info"); - let _ = env_logger::init(); + env_logger::init(); let sys = actix::System::new("multipart-example"); server::new(|| { App::new() - .middleware(middleware::Logger::default()) // <- logger - .resource("/multipart", |r| r.method(http::Method::POST).a(index)) + .middleware(middleware::Logger::default()) + .resource("/", |r| { + r.method(http::Method::GET).with(index); + r.method(http::Method::POST).with(upload); + }) }).bind("127.0.0.1:8080") .unwrap() .start();