Hi there,
I am currently working on a web project using actix-web, and I encountered a problem I have troubles solving. I implemented a function parse_multipart
returning HashMap. I get a value from that hashmap, create a struct from it and move it to a web::block
closure. And that's where things break: because it is a reference, value doesn't live long enough. I could try to clone the value, but then I get problems with ownerships or problems with lifetime because the block I create the copy in is to short-living. This is the code:
#[post("/pictures/{id}")]
pub async fn update(
ident: Identity,
pool: web::Data<DbPool>,
id: web::Path<i32>,
mut payload: Multipart,
) -> Result<HttpResponse, Error> {
if ident.identity().is_none() {
return Result::Err(error::ErrorForbidden("You have to be logged in to see this page"));
}
let params = parse_multipart(&mut payload).await?;
let metadata = match get_file(¶ms) {
Some((filename, file)) => {
let content_type = match new_mime_guess::from_path(&filename).first_raw() {
Some(s) => s,
None => "image/jpeg",
};
let len = file.metadata()?.len();
Some((filename.clone(), file, content_type.to_owned(), len as i32))
}
_ => None,
};
let form = form_from_params(¶ms, ident.identity().unwrap().parse::<i32>().unwrap(), &metadata);
let pool_ = pool.clone();
let picture = web::block(move || {
let conn = pool_.get()?;
actions::get_picture(id.into_inner(), &conn)
})
.await
.map_err(|e| error::ErrorInternalServerError(format!("Database error: {}", e)))?;
let mut data = form.clone();
data.author_id = Some(ident.identity().unwrap().parse::<i32>().unwrap());
let res = web::block(move || {
let conn = pool.get()?;
actions::update_picture(picture.id, &data, &metadata, &conn)
})
.await;
let res = Err(error::ErrorBadRequest("picture field is not a file"));
if let Ok(picture) = res {
Ok(HttpResponse::Found()
.header(header::LOCATION, picture_uri(&picture))
.finish())
} else {
let error = match res {
Err(cause) => Some(cause.to_string()),
Ok(_) => None,
};
let s = Edit {
title: Some(&format!("Edit picture #{}", picture.id)),
page_type: None,
page_image: None,
body_id: None,
logged_in: true,
picture: &picture,
form_data: &form,
error: &error,
}
.render()
.unwrap();
Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(s))
}
}
The error occurs for the params
hashmap: the file
I wrap into the tuple in the get_file
match is a reference. When I create a clone with file.try_clone()?
the value lives long enough, but I get ownership problems because form_from_params
overtakes ownership. When I try to store a reference of the clone, of course, it is not living long enough because it gets destroyed after the match
block.
What is a common strategy for dealing with these kind of problems?
Best regards,
CK