ve-tos-rust-sdk 2.0.0

volcengine offical tos rust sdk
Documentation
/*
 * Copyright (2024) Volcengine
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use serde::Deserialize;

use ve_tos_generic::{AclHeader, RequestInfo};

use crate::common::{Meta, Owner, RequestInfo};
use crate::constant::{HEADER_AZ_REDUNDANCY, HEADER_BUCKET_REGION, HEADER_LOCATION, HEADER_PROJECT_NAME, HEADER_STORAGE_CLASS};
use crate::enumeration::HttpMethodType::{HttpMethodDelete, HttpMethodGet, HttpMethodHead};
use crate::internal::{get_header_value_str, InputDescriptor, map_insert, set_acl_header};

use super::enumeration::{ACLType, AzRedundancyType, HttpMethodType::HttpMethodPut, StorageClassType};
use super::error::TosError;
use super::http::{HttpRequest, HttpResponse};
use super::internal::{get_header_value, InputTranslator, OutputParser, parse_json};

pub trait BucketAPI {
    fn create_bucket(&self, input: &CreateBucketInput) -> Result<CreateBucketOutput, TosError>;
    fn head_bucket(&self, input: &HeadBucketInput) -> Result<HeadBucketOutput, TosError>;
    fn delete_bucket(&self, input: &DeleteBucketInput) -> Result<DeleteBucketOutput, TosError>;
    fn list_buckets(&self, input: &ListBucketsInput) -> Result<ListBucketsOutput, TosError>;
}


#[derive(Debug, Clone, PartialEq, Default, AclHeader)]
#[enable_grant_write]
pub struct CreateBucketInput {
    pub(crate) bucket: String,
    pub(crate) acl: Option<ACLType>,
    pub(crate) grant_full_control: String,
    pub(crate) grant_read: String,
    pub(crate) grant_read_acp: String,
    pub(crate) grant_write: String,
    pub(crate) grant_write_acp: String,
    pub(crate) storage_class: Option<StorageClassType>,
    pub(crate) az_redundancy: Option<AzRedundancyType>,
}

impl CreateBucketInput {
    pub fn new(bucket: impl Into<String>) -> Self {
        let mut input = Self::default();
        input.bucket = bucket.into();
        input
    }

    pub fn bucket(&self) -> &str {
        &self.bucket
    }
    pub fn storage_class(&self) -> &Option<StorageClassType> {
        &self.storage_class
    }
    pub fn az_redundancy(&self) -> &Option<AzRedundancyType> {
        &self.az_redundancy
    }
    pub fn set_bucket(&mut self, bucket: impl Into<String>) {
        self.bucket = bucket.into();
    }
    pub fn set_storage_class(&mut self, storage_class: impl Into<StorageClassType>) {
        self.storage_class = Some(storage_class.into());
    }
    pub fn set_az_redundancy(&mut self, az_redundancy: impl Into<AzRedundancyType>) {
        self.az_redundancy = Some(az_redundancy.into());
    }
}


impl InputDescriptor for CreateBucketInput {
    fn operation(&self) -> &str {
        "CreateBucket"
    }

    fn bucket(&self) -> Result<&str, TosError> {
        Ok(&self.bucket)
    }
}

impl<B> InputTranslator<B> for CreateBucketInput {
    fn trans(&self) -> Result<HttpRequest<B>, TosError> {
        let mut request = self.trans_bucket()?;
        request.method = HttpMethodPut;
        let header = &mut request.header;
        set_acl_header(header, self);
        if let Some(x) = &self.storage_class {
            header.insert(HEADER_STORAGE_CLASS, x.as_str().to_string());
        }

        if let Some(x) = &self.az_redundancy {
            header.insert(HEADER_AZ_REDUNDANCY, x.as_str().to_string());
        }

        Ok(request)
    }
}


#[derive(Debug, Clone, PartialEq, Default, RequestInfo)]
pub struct CreateBucketOutput {
    pub(crate) request_info: RequestInfo,
    pub(crate) location: String,
}

impl CreateBucketOutput {
    pub fn location(&self) -> &str {
        &self.location
    }
}

impl OutputParser for CreateBucketOutput {
    fn parse_by_ref<B>(_: &HttpRequest<B>, response: &mut HttpResponse, request_info: RequestInfo, _: Meta) -> Result<Self, TosError> {
        let location = get_header_value(response.headers(), HEADER_LOCATION);
        Ok(Self { request_info, location })
    }
}

#[derive(Debug, Clone, PartialEq, Default)]
pub struct HeadBucketInput {
    pub(crate) bucket: String,
}

impl HeadBucketInput {
    pub fn new(bucket: impl Into<String>) -> Self {
        let mut input = Self::default();
        input.bucket = bucket.into();
        input
    }

    pub fn bucket(&self) -> &str {
        &self.bucket
    }
    pub fn set_bucket(&mut self, bucket: impl Into<String>) {
        self.bucket = bucket.into();
    }
}

impl InputDescriptor for HeadBucketInput {
    fn operation(&self) -> &str {
        "HeadBucket"
    }

    fn bucket(&self) -> Result<&str, TosError> {
        Ok(&self.bucket)
    }
}

impl<B> InputTranslator<B> for HeadBucketInput {
    fn trans(&self) -> Result<HttpRequest<B>, TosError> {
        let mut request = self.trans_bucket()?;
        request.method = HttpMethodHead;
        Ok(request)
    }
}


#[derive(Debug, Clone, PartialEq, Default, RequestInfo)]
pub struct HeadBucketOutput {
    pub(crate) request_info: RequestInfo,
    pub(crate) region: String,
    pub(crate) storage_class: Option<StorageClassType>,
    pub(crate) az_redundancy: Option<AzRedundancyType>,
    pub(crate) project_name: String,
}


impl HeadBucketOutput {
    pub fn region(&self) -> &str {
        &self.region
    }
    pub fn storage_class(&self) -> &Option<StorageClassType> {
        &self.storage_class
    }
    pub fn az_redundancy(&self) -> &Option<AzRedundancyType> {
        &self.az_redundancy
    }
    pub fn project_name(&self) -> &str {
        &self.project_name
    }
}

impl OutputParser for HeadBucketOutput {
    fn parse_by_ref<B>(_: &HttpRequest<B>, response: &mut HttpResponse, request_info: RequestInfo, _: Meta) -> Result<Self, TosError> {
        let region = get_header_value(response.headers(), HEADER_BUCKET_REGION);
        let storage_class = StorageClassType::from(get_header_value_str(response.headers(), HEADER_STORAGE_CLASS));
        let az_redundancy = AzRedundancyType::from(get_header_value_str(response.headers(), HEADER_AZ_REDUNDANCY));
        let project_name = get_header_value(response.headers(), HEADER_PROJECT_NAME);

        Ok(Self { request_info, region, storage_class, az_redundancy, project_name })
    }
}

#[derive(Debug, Clone, PartialEq, Default)]
pub struct DeleteBucketInput {
    pub(crate) bucket: String,
}

impl DeleteBucketInput {
    pub fn new(bucket: impl Into<String>) -> Self {
        let mut input = Self::default();
        input.bucket = bucket.into();
        input
    }

    pub fn bucket(&self) -> &str {
        &self.bucket
    }
    pub fn set_bucket(&mut self, bucket: impl Into<String>) {
        self.bucket = bucket.into();
    }
}

impl InputDescriptor for DeleteBucketInput {
    fn operation(&self) -> &str {
        "DeleteBucket"
    }

    fn bucket(&self) -> Result<&str, TosError> {
        Ok(&self.bucket)
    }
}

impl<B> InputTranslator<B> for DeleteBucketInput {
    fn trans(&self) -> Result<HttpRequest<B>, TosError> {
        let mut request = self.trans_bucket()?;
        request.method = HttpMethodDelete;
        Ok(request)
    }
}

#[derive(Debug, Clone, PartialEq, Default, RequestInfo)]
pub struct DeleteBucketOutput {
    pub(crate) request_info: RequestInfo,
}

impl OutputParser for DeleteBucketOutput {
    fn parse_by_ref<B>(_: &HttpRequest<B>, _: &mut HttpResponse, request_info: RequestInfo, _: Meta) -> Result<Self, TosError> {
        Ok(Self { request_info })
    }
}

#[derive(Debug, Clone, PartialEq, Default)]
pub struct ListBucketsInput {
    pub(crate) project_name: String,
}

impl ListBucketsInput {
    pub fn new() -> Self {
        Self::default()
    }
    pub fn project_name(&self) -> &str {
        &self.project_name
    }
    pub fn set_project_name(&mut self, project_name: impl Into<String>) {
        self.project_name = project_name.into();
    }
}

impl InputDescriptor for ListBucketsInput {
    fn operation(&self) -> &str {
        "ListBuckets"
    }

    fn bucket(&self) -> Result<&str, TosError> {
        Err(TosError::client_error("unsupported"))
    }
}

impl<B> InputTranslator<B> for ListBucketsInput {
    fn trans(&self) -> Result<HttpRequest<B>, TosError> {
        let mut request = HttpRequest::default();
        request.operation = self.operation();
        request.method = HttpMethodGet;
        map_insert(&mut request.header, HEADER_PROJECT_NAME, &self.project_name);
        Ok(request)
    }
}

#[derive(Debug, Clone, PartialEq, Default, RequestInfo, Deserialize)]
pub struct ListBucketsOutput {
    #[serde(skip)]
    pub(crate) request_info: RequestInfo,
    #[serde(default)]
    #[serde(rename = "Buckets")]
    pub(crate) buckets: Vec<ListedBucket>,
    #[serde(default)]
    #[serde(rename = "Owner")]
    pub(crate) owner: Owner,
}

#[derive(Debug, Clone, PartialEq, Default, Deserialize)]
pub struct ListedBucket {
    #[serde(default)]
    #[serde(rename = "CreationDate")]
    pub(crate) creation_date: String,
    #[serde(default)]
    #[serde(rename = "Name")]
    pub(crate) name: String,
    #[serde(default)]
    #[serde(rename = "Location")]
    pub(crate) location: String,
    #[serde(default)]
    #[serde(rename = "ExtranetEndpoint")]
    pub(crate) extranet_endpoint: String,
    #[serde(default)]
    #[serde(rename = "IntranetEndpoint")]
    pub(crate) intranet_endpoint: String,
    #[serde(default)]
    #[serde(rename = "ProjectName")]
    pub(crate) project_name: String,
}


impl ListBucketsOutput {
    pub fn buckets(&self) -> &Vec<ListedBucket> {
        &self.buckets
    }
    pub fn owner(&self) -> &Owner {
        &self.owner
    }
}

impl OutputParser for ListBucketsOutput {
    fn parse_by_ref<B>(_: &HttpRequest<B>, response: &mut HttpResponse, request_info: RequestInfo, _: Meta) -> Result<Self, TosError> {
        let mut result = parse_json::<Self>(response)?;
        result.request_info = request_info;
        Ok(result)
    }
}

impl ListedBucket {
    pub fn creation_date(&self) -> &str {
        &self.creation_date
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn location(&self) -> &str {
        &self.location
    }
    pub fn extranet_endpoint(&self) -> &str {
        &self.extranet_endpoint
    }
    pub fn intranet_endpoint(&self) -> &str {
        &self.intranet_endpoint
    }
    pub fn project_name(&self) -> &str {
        &self.project_name
    }
}