use crate::constants::EMPTY_PAYLOAD_SHA; use crate::types::Multipart; use serde::Serialize; use sha2::{Digest, Sha256}; use std::fmt; #[derive(Debug, Serialize)] pub struct Part { #[serde(rename = "PartNumber")] pub part_number: u32, #[serde(rename = "ETag")] pub etag: String, } impl fmt::Display for Part { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}{}", self.part_number, self.etag ) } } #[derive(Debug)] pub struct CompleteMultipartUploadData { pub parts: Vec, } impl fmt::Display for CompleteMultipartUploadData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "")?; for part in &self.parts { write!(f, "{}", part)?; } write!(f, "") } } impl CompleteMultipartUploadData { pub fn len(&self) -> usize { self.to_string().as_bytes().len() } #[allow(dead_code)] pub fn is_empty(&self) -> bool { self.to_string().as_bytes().is_empty() } } #[allow(dead_code)] #[derive(Debug)] pub(crate) enum Command<'a> { HeadObject, CopyObject { from: &'a str, }, DeleteObject, DeleteObjectTagging, GetObject, GetObjectRange { start: u64, end: Option, }, GetObjectTagging, PutObject { content: &'a [u8], content_type: &'a str, multipart: Option>, }, PutObjectTagging { tags: &'a str, }, ListMultipartUploads { prefix: Option<&'a str>, delimiter: Option<&'a str>, key_marker: Option, max_uploads: Option, }, ListObjects { prefix: &'a str, delimiter: Option<&'a str>, marker: Option, max_keys: Option, }, ListObjectsV2 { prefix: &'a str, delimiter: Option<&'a str>, continuation_token: Option, start_after: Option, max_keys: Option, }, GetBucketLocation, // PresignGet { // expiry_secs: u32, // custom_queries: Option>, // }, // PresignPut { // expiry_secs: u32, // custom_headers: Option, // }, // PresignPost { // expiry_secs: u32, // post_policy: String, // }, // PresignDelete { // expiry_secs: u32, // }, InitiateMultipartUpload { content_type: &'a str, }, UploadPart { part_number: u32, content: &'a [u8], upload_id: &'a str, }, AbortMultipartUpload { upload_id: &'a str, }, CompleteMultipartUpload { upload_id: &'a str, data: CompleteMultipartUploadData, }, } impl<'a> Command<'a> { pub(crate) fn http_method(&self) -> http::Method { match *self { Command::GetObject | Command::GetObjectRange { .. } | Command::ListObjects { .. } | Command::ListObjectsV2 { .. } | Command::GetBucketLocation | Command::GetObjectTagging | Command::ListMultipartUploads { .. } => http::Method::GET, Command::PutObject { .. } | Command::CopyObject { from: _ } | Command::PutObjectTagging { .. } | Command::UploadPart { .. } => http::Method::PUT, Command::DeleteObject | Command::DeleteObjectTagging | Command::AbortMultipartUpload { .. } => http::Method::DELETE, Command::InitiateMultipartUpload { .. } | Command::CompleteMultipartUpload { .. } => { http::Method::POST } Command::HeadObject => http::Method::HEAD, } } pub(crate) fn content_length(&self) -> usize { match &self { Command::PutObject { content, .. } => content.len(), Command::PutObjectTagging { tags } => tags.len(), Command::UploadPart { content, .. } => content.len(), Command::CompleteMultipartUpload { data, .. } => data.len(), _ => 0, } } pub(crate) fn content_type(&self) -> &str { match self { Command::InitiateMultipartUpload { content_type } => content_type, Command::PutObject { content_type, .. } => content_type, Command::CompleteMultipartUpload { .. } => "application/xml", _ => "text/plain", } } pub(crate) fn sha256(&self) -> String { match &self { Command::PutObject { content, .. } => { let mut sha = Sha256::default(); sha.update(content); hex::encode(sha.finalize().as_slice()) } Command::PutObjectTagging { tags } => { let mut sha = Sha256::default(); sha.update(tags.as_bytes()); hex::encode(sha.finalize().as_slice()) } Command::CompleteMultipartUpload { data, .. } => { let mut sha = Sha256::default(); sha.update(data.to_string().as_bytes()); hex::encode(sha.finalize().as_slice()) } _ => EMPTY_PAYLOAD_SHA.into(), } } }