use std::collections::HashMap;
use std::future::Future;
use heck::ToKebabCase;
use http::{HeaderMap, HeaderName, Method, header};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::body::ZeroBody;
use crate::error::Result;
use crate::ops::common::{EncodingType, ServerSideEncryption, StorageClass};
use crate::response::BodyResponseProcessor;
use crate::ser::OnlyKeyField;
use crate::{Client, Ops, Prepared, Request};
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Default)]
#[serde(rename_all = "kebab-case")]
pub struct InitiateMultipartUploadParams {
uploads: OnlyKeyField,
pub encoding_type: Option<EncodingType>,
}
impl InitiateMultipartUploadParams {
pub fn new() -> Self {
Self {
uploads: OnlyKeyField,
encoding_type: None,
}
}
pub fn encoding_type(mut self, encoding_type: EncodingType) -> Self {
self.encoding_type = Some(encoding_type);
self
}
}
#[derive(Debug, Clone, Default)]
pub struct InitiateMultipartUploadOptions {
pub cache_control: Option<String>,
pub content_disposition: Option<String>,
pub content_encoding: Option<String>,
pub content_type: Option<String>,
pub expires: Option<String>,
pub forbid_overwrite: Option<bool>,
pub server_side_encryption: Option<ServerSideEncryption>,
pub server_side_data_encryption: Option<String>,
pub server_side_encryption_key_id: Option<String>,
pub storage_class: Option<StorageClass>,
pub tagging: Option<String>,
pub user_meta: HashMap<String, String>,
}
impl InitiateMultipartUploadOptions {
fn into_headers(self) -> Result<HeaderMap> {
let mut headers = HeaderMap::new();
if let Some(cache_control) = self.cache_control {
headers.insert(header::CACHE_CONTROL, cache_control.parse()?);
}
if let Some(content_type) = self.content_type {
headers.insert(header::CONTENT_TYPE, content_type.parse()?);
}
if let Some(content_disposition) = self.content_disposition {
headers.insert(header::CONTENT_DISPOSITION, content_disposition.parse()?);
}
if let Some(content_encoding) = self.content_encoding {
headers.insert(header::CONTENT_ENCODING, content_encoding.parse()?);
}
if let Some(expires) = self.expires {
headers.insert(header::EXPIRES, expires.parse()?);
}
if let Some(forbid_overwrite) = self.forbid_overwrite {
headers.insert(
HeaderName::from_static("x-oss-forbid-overwrite"),
forbid_overwrite.to_string().parse()?,
);
}
if let Some(server_side_encryption) = self.server_side_encryption {
headers.insert(
HeaderName::from_static("x-oss-server-side-encryption"),
server_side_encryption.as_ref().parse()?,
);
}
if let Some(server_side_data_encryption) = self.server_side_data_encryption {
headers.insert(
HeaderName::from_static("x-oss-server-side-data-encryption"),
server_side_data_encryption.parse()?,
);
}
if let Some(server_side_encryption_key_id) = self.server_side_encryption_key_id {
headers.insert(
HeaderName::from_static("x-oss-server-side-encryption-key-id"),
server_side_encryption_key_id.parse()?,
);
}
if let Some(storage_class) = self.storage_class {
headers.insert(HeaderName::from_static("x-oss-storage-class"), storage_class.as_ref().parse()?);
}
if let Some(tagging) = self.tagging {
headers.insert(HeaderName::from_static("x-oss-tagging"), tagging.parse()?);
}
for (key, value) in self.user_meta {
let key = key.to_kebab_case().to_lowercase();
let header_name = format!("x-oss-meta-{key}");
headers.insert(HeaderName::from_bytes(header_name.as_bytes())?, value.parse()?);
}
Ok(headers)
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct InitiateMultipartUploadResult {
pub bucket: String,
pub key: String,
pub upload_id: String,
pub encoding_type: Option<String>,
}
pub struct InitiateMultipartUpload {
pub object_key: String,
pub params: InitiateMultipartUploadParams,
pub options: InitiateMultipartUploadOptions,
}
impl Ops for InitiateMultipartUpload {
type Response = BodyResponseProcessor<InitiateMultipartUploadResult>;
type Body = ZeroBody;
type Query = InitiateMultipartUploadParams;
fn prepare(self) -> Result<Prepared<InitiateMultipartUploadParams>> {
Ok(Prepared {
method: Method::POST,
key: Some(self.object_key),
query: Some(self.params),
headers: Some(self.options.into_headers()?),
body: Some(()),
..Default::default()
})
}
}
pub trait InitiateMultipartUploadOperations {
fn initiate_multipart_upload(
&self,
object_key: impl Into<String>,
options: Option<InitiateMultipartUploadOptions>,
) -> impl Future<Output = Result<InitiateMultipartUploadResult>>;
}
impl InitiateMultipartUploadOperations for Client {
async fn initiate_multipart_upload(
&self,
object_key: impl Into<String>,
options: Option<InitiateMultipartUploadOptions>,
) -> Result<InitiateMultipartUploadResult> {
let ops = InitiateMultipartUpload {
object_key: object_key.into(),
params: InitiateMultipartUploadParams::new(),
options: options.unwrap_or_default(),
};
self.request(ops).await
}
}
#[derive(Debug, Clone, Default)]
pub struct InitiateMultipartUploadRequestBuilder {
options: InitiateMultipartUploadOptions,
}
impl InitiateMultipartUploadRequestBuilder {
pub fn new() -> Self {
Self {
options: InitiateMultipartUploadOptions::default(),
}
}
pub fn cache_control(mut self, cache_control: impl Into<String>) -> Self {
self.options.cache_control = Some(cache_control.into());
self
}
pub fn content_disposition(mut self, content_disposition: impl Into<String>) -> Self {
self.options.content_disposition = Some(content_disposition.into());
self
}
pub fn content_encoding(mut self, content_encoding: impl Into<String>) -> Self {
self.options.content_encoding = Some(content_encoding.into());
self
}
pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
self.options.content_type = Some(content_type.into());
self
}
pub fn expires(mut self, expires: impl Into<String>) -> Self {
self.options.expires = Some(expires.into());
self
}
pub fn forbid_overwrite(mut self, forbid: bool) -> Self {
self.options.forbid_overwrite = Some(forbid);
self
}
pub fn server_side_encryption(mut self, encryption: ServerSideEncryption) -> Self {
self.options.server_side_encryption = Some(encryption);
self
}
pub fn server_side_data_encryption(mut self, encryption: impl Into<String>) -> Self {
self.options.server_side_data_encryption = Some(encryption.into());
self
}
pub fn server_side_encryption_key_id(mut self, key_id: impl Into<String>) -> Self {
self.options.server_side_encryption_key_id = Some(key_id.into());
self
}
pub fn storage_class(mut self, storage_class: StorageClass) -> Self {
self.options.storage_class = Some(storage_class);
self
}
pub fn tagging(mut self, tagging: impl Into<String>) -> Self {
self.options.tagging = Some(tagging.into());
self
}
pub fn user_meta(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.options.user_meta.insert(key.into(), value.into());
self
}
pub fn build(self) -> InitiateMultipartUploadOptions {
self.options
}
}