#![allow(clippy::map_entry)] // Copyright 2024 RustFS Team // // 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. #![allow(unused_imports)] #![allow(unused_variables)] #![allow(unused_mut)] #![allow(unused_assignments)] #![allow(unused_must_use)] #![allow(clippy::all)] use bytes::Bytes; use http::{HeaderMap, StatusCode}; use std::collections::HashMap; use crate::client::{ api_error_response::http_resp_to_error_response, api_s3_datatypes::{ ListBucketResult, ListBucketV2Result, ListMultipartUploadsResult, ListObjectPartsResult, ListVersionsResult, ObjectPart, }, credentials, transition_api::{ReaderImpl, RequestMetadata, TransitionClient}, }; use crate::store_api::BucketInfo; use rustfs_utils::hash::EMPTY_STRING_SHA256_HASH; impl TransitionClient { pub fn list_buckets(&self) -> Result, std::io::Error> { todo!(); } pub async fn list_objects_v2_query( &self, bucket_name: &str, object_prefix: &str, continuation_token: &str, fetch_owner: bool, metadata: bool, delimiter: &str, start_after: &str, max_keys: i64, headers: HeaderMap, ) -> Result { let mut url_values = HashMap::new(); url_values.insert("list-type".to_string(), "2".to_string()); if metadata { url_values.insert("metadata".to_string(), "true".to_string()); } if start_after != "" { url_values.insert("start-after".to_string(), start_after.to_string()); } url_values.insert("encoding-type".to_string(), "url".to_string()); url_values.insert("prefix".to_string(), object_prefix.to_string()); url_values.insert("delimiter".to_string(), delimiter.to_string()); if continuation_token != "" { url_values.insert("continuation-token".to_string(), continuation_token.to_string()); } if fetch_owner { url_values.insert("fetch-owner".to_string(), "true".to_string()); } if max_keys > 0 { url_values.insert("max-keys".to_string(), max_keys.to_string()); } let mut resp = self .execute_method( http::Method::GET, &mut RequestMetadata { bucket_name: bucket_name.to_string(), object_name: "".to_string(), query_values: url_values, content_sha256_hex: EMPTY_STRING_SHA256_HASH.to_string(), custom_header: headers, content_body: ReaderImpl::Body(Bytes::new()), content_length: 0, content_md5_base64: "".to_string(), stream_sha256: false, trailer: HeaderMap::new(), pre_sign_url: Default::default(), add_crc: Default::default(), extra_pre_sign_header: Default::default(), bucket_location: Default::default(), expires: Default::default(), }, ) .await?; if resp.status() != StatusCode::OK { return Err(std::io::Error::other(http_resp_to_error_response(resp, vec![], bucket_name, ""))); } //let mut list_bucket_result = ListBucketV2Result::default(); let b = resp.body_mut().store_all_unlimited().await.unwrap().to_vec(); let mut list_bucket_result = match serde_xml_rs::from_str::(&String::from_utf8(b).unwrap()) { Ok(result) => result, Err(err) => { return Err(std::io::Error::other(err.to_string())); } }; //println!("list_bucket_result: {:?}", list_bucket_result); if list_bucket_result.is_truncated && list_bucket_result.next_continuation_token == "" { return Err(std::io::Error::other(credentials::ErrorResponse { sts_error: credentials::STSError { r#type: "".to_string(), code: "NotImplemented".to_string(), message: "Truncated response should have continuation token set".to_string(), }, request_id: "".to_string(), })); } for (i, obj) in list_bucket_result.contents.iter_mut().enumerate() { obj.name = decode_s3_name(&obj.name, &list_bucket_result.encoding_type)?; //list_bucket_result.contents[i].mod_time = list_bucket_result.contents[i].mod_time.Truncate(time.Millisecond); } for (i, obj) in list_bucket_result.common_prefixes.iter_mut().enumerate() { obj.prefix = decode_s3_name(&obj.prefix, &list_bucket_result.encoding_type)?; } Ok(list_bucket_result) } pub fn list_object_versions_query( &self, bucket_name: &str, opts: &ListObjectsOptions, key_marker: &str, version_id_marker: &str, delimiter: &str, ) -> Result { /*if err := s3utils.CheckValidBucketName(bucketName); err != nil { return ListVersionsResult{}, err } if err := s3utils.CheckValidObjectNamePrefix(opts.Prefix); err != nil { return ListVersionsResult{}, err } urlValues := make(url.Values) urlValues.Set("versions", "") urlValues.Set("prefix", opts.Prefix) urlValues.Set("delimiter", delimiter) if keyMarker != "" { urlValues.Set("key-marker", keyMarker) } if opts.max_keys > 0 { urlValues.Set("max-keys", fmt.Sprintf("%d", opts.max_keys)) } if versionIDMarker != "" { urlValues.Set("version-id-marker", versionIDMarker) } if opts.WithMetadata { urlValues.Set("metadata", "true") } urlValues.Set("encoding-type", "url") let resp = self.executeMethod(http::Method::GET, &mut RequestMetadata{ bucketName: bucketName, queryValues: urlValues, contentSHA256Hex: emptySHA256Hex, customHeader: opts.headers, }).await?; defer closeResponse(resp) if err != nil { return ListVersionsResult{}, err } if resp != nil { if resp.StatusCode != http.StatusOK { return ListVersionsResult{}, httpRespToErrorResponse(resp, bucketName, "") } } listObjectVersionsOutput := ListVersionsResult{} err = xml_decoder(resp.Body, &listObjectVersionsOutput) if err != nil { return ListVersionsResult{}, err } for i, obj := range listObjectVersionsOutput.Versions { listObjectVersionsOutput.Versions[i].Key, err = decode_s3_name(obj.Key, listObjectVersionsOutput.EncodingType) if err != nil { return listObjectVersionsOutput, err } } for i, obj := range listObjectVersionsOutput.CommonPrefixes { listObjectVersionsOutput.CommonPrefixes[i].Prefix, err = decode_s3_name(obj.Prefix, listObjectVersionsOutput.EncodingType) if err != nil { return listObjectVersionsOutput, err } } if listObjectVersionsOutput.NextKeyMarker != "" { listObjectVersionsOutput.NextKeyMarker, err = decode_s3_name(listObjectVersionsOutput.NextKeyMarker, listObjectVersionsOutput.EncodingType) if err != nil { return listObjectVersionsOutput, err } } Ok(listObjectVersionsOutput)*/ todo!(); } pub fn list_objects_query( &self, bucket_name: &str, object_prefix: &str, object_marker: &str, delimiter: &str, max_keys: i64, headers: HeaderMap, ) -> Result { todo!(); } pub fn list_multipart_uploads_query( &self, bucket_name: &str, key_marker: &str, upload_id_marker: &str, prefix: &str, delimiter: &str, max_uploads: i64, ) -> Result { todo!(); } pub fn list_object_parts( &self, bucket_name: &str, object_name: &str, upload_id: &str, ) -> Result, std::io::Error> { todo!(); } pub fn find_upload_ids(&self, bucket_name: &str, object_name: &str) -> Result, std::io::Error> { todo!(); } pub async fn list_object_parts_query( &self, bucket_name: &str, object_name: &str, upload_id: &str, part_number_marker: i64, max_parts: i64, ) -> Result { todo!(); } } #[allow(dead_code)] pub struct ListObjectsOptions { reverse_versions: bool, with_versions: bool, with_metadata: bool, prefix: String, recursive: bool, max_keys: i64, start_after: String, use_v1: bool, headers: HeaderMap, } impl ListObjectsOptions { pub fn set(&mut self, key: &str, value: &str) { todo!(); } } fn decode_s3_name(name: &str, encoding_type: &str) -> Result { match encoding_type { "url" => { //return url::QueryUnescape(name); return Ok(name.to_string()); } _ => { return Ok(name.to_string()); } } }