Skip to main content

ufile_rus3/api/
multipart_init.rs

1use anyhow::Error;
2use chrono::Local;
3use reqwest::{
4    Method,
5    header::{HeaderMap, HeaderName},
6};
7
8use crate::{
9    AuthorizationService,
10    api::{ApiOperation, ObjectOptAuthParamBuilder, object::InitMultipartState},
11    define_api_request, define_operation_struct,
12};
13
14define_operation_struct!(MultipartInitOperation);
15
16define_api_request!(
17    MultipartInitRequest,
18    MultipartInitOperationBuilder,
19    InitMultipartState,
20    {
21    /// Required: Key name
22    #[builder(setter(into))]
23    pub key_name: String,
24
25    /// Required: Content type
26    #[builder(setter(into))]
27    pub mime_type: String,
28
29    /// Required: Bucket name
30    #[builder(setter(into))]
31    pub bucket_name: String,
32
33    /// Optional: Metadata
34    #[builder(setter(into, strip_option), default)]
35    pub metadata: ::std::option::Option<::std::collections::HashMap<String, String>>,
36
37    /// Optional: Storage type
38    #[builder(setter(into, strip_option), default)]
39    pub storage_type: ::std::option::Option<String>,
40
41    /// Optional: Security token
42    #[builder(setter(into, strip_option), default)]
43    pub security_token: ::std::option::Option<String>,
44    }
45);
46
47#[async_trait::async_trait]
48impl ApiOperation for MultipartInitOperation {
49    type Request = MultipartInitRequest;
50    type Response = InitMultipartState;
51    type Error = Error;
52
53    async fn execute(&self, request: Self::Request) -> Result<Self::Response, Self::Error> {
54        let MultipartInitRequest {
55            key_name,
56            mime_type,
57            bucket_name,
58            metadata,
59            storage_type,
60            security_token,
61            ..
62        } = request;
63        let date = Local::now().format("&Y%m%d%H%M%S").to_string();
64        let auth_object = ObjectOptAuthParamBuilder::default()
65            .method(Method::POST)
66            .bucket(bucket_name.as_str())
67            .key_name(key_name.as_str())
68            .content_type(mime_type.as_str())
69            .date(date.as_str())
70            .build()?;
71        let authorization =
72            AuthorizationService.authorization(auth_object, self.object_config.clone())?;
73        let mut headers = HeaderMap::new();
74        headers.insert("Content-Type", mime_type.parse().unwrap());
75        headers.insert("Accept", "*/*".parse().unwrap());
76        headers.insert("Date", date.parse().unwrap());
77        headers.insert("Authorization", authorization.parse().unwrap());
78        if let Some(ref storage_type) = storage_type
79            && !storage_type.is_empty()
80        {
81            headers.insert("X-Ufile-Storage-Class", storage_type.parse().unwrap());
82        }
83        if let Some(ref security_token) = security_token
84            && !security_token.is_empty()
85        {
86            headers.insert("SecurityToken", security_token.parse().unwrap());
87        }
88        // We must add metadata to headers if metadata is not empty.
89        if let Some(ref metadata) = metadata
90            && !metadata.is_empty()
91        {
92            for (k, v) in metadata {
93                headers.insert(
94                    format!("X-Ufile-Meta-{k}").parse::<HeaderName>().unwrap(),
95                    v.parse().unwrap(),
96                );
97            }
98        }
99        let url = self
100            .object_config
101            .generate_final_host(bucket_name.as_str(), key_name.as_str());
102        let url = format!("{url}?uploads");
103        // do request to remote server to create initialization of the multipart upload task.
104        let resp = self
105            .client
106            .get_client()
107            .post(url)
108            .headers(headers)
109            .json("")
110            .send()
111            .await?;
112        ::tracing::debug!("Init multipart file response: {:?}", resp);
113        if resp.status().is_success() {
114            let mut resp: InitMultipartState = resp.json().await?;
115            resp.mime_type.replace(mime_type.clone());
116            return Ok(resp);
117        }
118        Err(Error::msg("Failed to init multipart file"))
119    }
120}