s3_signer/multipart_upload/
create.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize, Serialize)]
4pub struct CreateUploadQueryParameters {
5  pub bucket: String,
6  pub path: String,
7}
8
9#[derive(Debug, Deserialize, Serialize)]
10#[cfg_attr(feature = "server", derive(utoipa::ToSchema))]
11pub struct CreateUploadResponse {
12  pub upload_id: String,
13}
14
15#[cfg(feature = "server")]
16pub(crate) mod server {
17  use super::{CreateUploadQueryParameters, CreateUploadResponse};
18  use crate::{multipart_upload::S3Client, to_ok_json_response, Error, S3Configuration};
19  use rusoto_s3::{CreateMultipartUploadRequest, S3};
20  use std::convert::TryFrom;
21  use warp::{
22    hyper::{Body, Response},
23    Filter, Rejection, Reply,
24  };
25
26  /// Create multipart upload
27  #[utoipa::path(
28    post,
29    context_path = "/multipart-upload",
30    path = "",
31    tag = "Multipart upload",
32    responses(
33      (status = 200, description = "Successfully created multipart upload", body = CreateUploadResponse),
34    ),
35    params(
36      ("bucket" = String, Query, description = "Name of the bucket"),
37      ("path" = String, Query, description = "Key of the object to upload")
38    ),
39  )]
40  pub(crate) fn route(
41    s3_configuration: &S3Configuration,
42  ) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
43    let s3_configuration = s3_configuration.clone();
44    warp::path::end()
45      .and(warp::post())
46      .and(warp::query::<CreateUploadQueryParameters>())
47      .and(warp::any().map(move || s3_configuration.clone()))
48      .and_then(
49        |parameters: CreateUploadQueryParameters, s3_configuration: S3Configuration| async move {
50          handle_create_multipart_upload(&s3_configuration, parameters.bucket, parameters.path)
51            .await
52        },
53      )
54  }
55
56  async fn handle_create_multipart_upload(
57    s3_configuration: &S3Configuration,
58    bucket: String,
59    key: String,
60  ) -> Result<Response<Body>, Rejection> {
61    log::info!("Create multipart upload...");
62    let client = S3Client::try_from(s3_configuration)?;
63    client
64      .execute(|client: rusoto_s3::S3Client| async move {
65        let request = CreateMultipartUploadRequest {
66          bucket,
67          key,
68          ..Default::default()
69        };
70
71        client
72          .create_multipart_upload(request)
73          .await
74          .map_err(|error| warp::reject::custom(Error::MultipartUploadCreationError(error)))
75          .and_then(|output| {
76            output
77              .upload_id
78              .ok_or_else(|| {
79                warp::reject::custom(Error::MultipartUploadError(
80                  "Invalid multipart upload creation response".to_string(),
81                ))
82              })
83              .and_then(|upload_id| {
84                let body_response = CreateUploadResponse { upload_id };
85                to_ok_json_response(&body_response)
86              })
87          })
88      })
89      .await
90  }
91}