use std::future::Future;
use http::{HeaderMap, HeaderName, Method};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::body::XMLBody;
use crate::error::Result;
use crate::response::BodyResponseProcessor;
use crate::{Client, Ops, Prepared, Request};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CompleteMultipartUploadParams {
pub upload_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub encoding_type: Option<String>,
}
impl CompleteMultipartUploadParams {
pub fn new(upload_id: impl Into<String>) -> Self {
Self {
upload_id: upload_id.into(),
encoding_type: None,
}
}
pub fn encoding_type(mut self, encoding_type: impl Into<String>) -> Self {
self.encoding_type = Some(encoding_type.into());
self
}
}
#[derive(Debug, Clone, Default)]
pub struct CompleteMultipartUploadOptions {
pub forbid_overwrite: Option<bool>,
pub complete_all: Option<bool>,
pub object_acl: Option<String>,
}
impl CompleteMultipartUploadOptions {
pub fn new() -> Self {
Self {
forbid_overwrite: None,
complete_all: None,
object_acl: None,
}
}
}
impl CompleteMultipartUploadOptions {
fn into_headers(self) -> Result<HeaderMap> {
let mut headers = HeaderMap::new();
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(object_acl) = self.object_acl {
headers.insert(HeaderName::from_static("x-oss-object-acl"), object_acl.parse()?);
}
if let Some(complete_all) = self.complete_all {
headers.insert(HeaderName::from_static("x-oss-complete-all"), complete_all.to_string().parse()?);
}
Ok(headers)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub struct Part {
pub part_number: u32,
#[serde(rename = "ETag")]
pub etag: String,
}
impl Part {
pub fn new(part_number: u32, etag: impl Into<String>) -> Self {
Self {
part_number,
etag: etag.into(),
}
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Default)]
#[serde(rename = "CompleteMultipartUpload")]
pub struct CompleteMultipartUploadBody {
#[serde(rename = "Part", default)]
pub parts: Vec<Part>,
}
impl CompleteMultipartUploadBody {
pub fn new(parts: Vec<Part>) -> Self {
Self { parts }
}
pub fn add_part(&mut self, part: Part) {
self.parts.push(part);
self.parts.sort_by_key(|p| p.part_number);
}
pub fn add_parts(&mut self, mut parts: Vec<Part>) {
self.parts.append(&mut parts);
self.parts.sort_by_key(|p| p.part_number);
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct CompleteMultipartUploadResult {
pub bucket: String,
pub key: String,
#[serde(rename = "ETag")]
pub etag: String,
pub location: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub encoding_type: Option<String>,
}
pub struct CompleteMultipartUpload {
pub object_key: String,
pub params: CompleteMultipartUploadParams,
pub body: Option<CompleteMultipartUploadBody>,
pub options: CompleteMultipartUploadOptions,
}
impl Ops for CompleteMultipartUpload {
type Response = BodyResponseProcessor<CompleteMultipartUploadResult>;
type Body = XMLBody<CompleteMultipartUploadBody>;
type Query = CompleteMultipartUploadParams;
fn prepare(self) -> Result<Prepared<CompleteMultipartUploadParams, CompleteMultipartUploadBody>> {
Ok(Prepared {
method: Method::POST,
key: Some(self.object_key),
query: Some(self.params),
headers: Some(self.options.into_headers()?),
body: self.body,
..Default::default()
})
}
}
pub trait CompleteMultipartUploadOperations {
fn complete_multipart_upload(
&self,
object_key: impl Into<String>,
upload_id: impl Into<String>,
parts: Vec<Part>,
options: Option<CompleteMultipartUploadOptions>,
) -> impl Future<Output = Result<CompleteMultipartUploadResult>>;
fn complete_multipart_upload_auto(
&self,
object_key: impl Into<String>,
upload_id: impl Into<String>,
options: Option<CompleteMultipartUploadOptions>,
) -> impl Future<Output = Result<CompleteMultipartUploadResult>>;
}
impl CompleteMultipartUploadOperations for Client {
async fn complete_multipart_upload(
&self,
object_key: impl Into<String>,
upload_id: impl Into<String>,
parts: Vec<Part>,
options: Option<CompleteMultipartUploadOptions>,
) -> Result<CompleteMultipartUploadResult> {
let mut sorted_parts = parts;
sorted_parts.sort_by_key(|p| p.part_number);
let ops = CompleteMultipartUpload {
object_key: object_key.into(),
params: CompleteMultipartUploadParams::new(upload_id),
body: Some(CompleteMultipartUploadBody::new(sorted_parts)),
options: options.unwrap_or_default(),
};
self.request(ops).await
}
async fn complete_multipart_upload_auto(
&self,
object_key: impl Into<String>,
upload_id: impl Into<String>,
options: Option<CompleteMultipartUploadOptions>,
) -> Result<CompleteMultipartUploadResult> {
let mut auto_options = options.unwrap_or_default();
auto_options.complete_all = Some(true);
let ops = CompleteMultipartUpload {
object_key: object_key.into(),
params: CompleteMultipartUploadParams::new(upload_id),
body: None, options: auto_options,
};
self.request(ops).await
}
}
#[derive(Debug, Clone, Default)]
pub struct CompleteMultipartUploadRequestBuilder {
options: CompleteMultipartUploadOptions,
}
impl CompleteMultipartUploadRequestBuilder {
pub fn new() -> Self {
Self {
options: CompleteMultipartUploadOptions::default(),
}
}
pub fn forbid_overwrite(mut self, forbid: bool) -> Self {
self.options.forbid_overwrite = Some(forbid);
self
}
pub fn complete_all(mut self, complete_all: bool) -> Self {
self.options.complete_all = Some(complete_all);
self
}
pub fn object_acl(mut self, acl: impl Into<String>) -> Self {
self.options.object_acl = Some(acl.into());
self
}
pub fn build(self) -> CompleteMultipartUploadOptions {
self.options
}
}