diff --git a/src/ops.rs b/src/ops/bytes_range.rs similarity index 53% rename from src/ops.rs rename to src/ops/bytes_range.rs index 2e4075b1eae..cc801356a7e 100644 --- a/src/ops.rs +++ b/src/ops/bytes_range.rs @@ -12,407 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Operations used by [`Accessor`][crate::Accessor]. -//! -//! Users should not use struct or functions here, use [`Operator`][crate::Operator] instead - -use std::collections::Bound; -use std::fmt::Display; -use std::fmt::Formatter; use std::io::Error; use std::io::ErrorKind; use std::io::Result; +use std::ops::Bound; use std::ops::Range; use std::ops::RangeBounds; use anyhow::anyhow; -use time::Duration; - -use crate::error::other; -use crate::error::ObjectError; -use crate::ObjectMode; - -/// Operation is the name for APIs in `Accessor`. -#[derive(Debug, Copy, Clone)] -pub enum Operation { - /// Operation for [`crate::Accessor::metadata`] - Metadata, - /// Operation for [`crate::Accessor::create`] - Create, - /// Operation for [`crate::Accessor::read`] - Read, - /// Operation for [`crate::Accessor::write`] - Write, - /// Operation for [`crate::Accessor::stat`] - Stat, - /// Operation for [`crate::Accessor::delete`] - Delete, - /// Operation for [`crate::Accessor::list`] - List, - /// Operation for [`crate::Accessor::presign`] - Presign, -} - -impl Operation { - /// Convert self into static str. - pub fn into_static(self) -> &'static str { - self.into() - } -} - -impl Default for Operation { - fn default() -> Self { - Operation::Metadata - } -} - -impl Display for Operation { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Operation::Metadata => write!(f, "metadata"), - Operation::Create => write!(f, "create"), - Operation::Read => write!(f, "read"), - Operation::Write => write!(f, "write"), - Operation::Stat => write!(f, "stat"), - Operation::Delete => write!(f, "delete"), - Operation::List => write!(f, "list"), - Operation::Presign => write!(f, "presign"), - } - } -} - -impl From for &'static str { - fn from(v: Operation) -> &'static str { - match v { - Operation::Metadata => "metadata", - Operation::Create => "create", - Operation::Read => "read", - Operation::Write => "write", - Operation::Stat => "stat", - Operation::Delete => "delete", - Operation::List => "list", - Operation::Presign => "presign", - } - } -} - -/// Args for `create` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpCreate { - path: String, - mode: ObjectMode, -} - -impl OpCreate { - /// Create a new `OpCreate`. - /// - /// If input path is not match with object mode, an error will be returned. - pub fn new(path: &str, mode: ObjectMode) -> Result { - match mode { - ObjectMode::FILE => { - if path.ends_with('/') { - return Err(other(ObjectError::new( - "create", - path, - anyhow!("Is a directory"), - ))); - } - Ok(Self { - path: path.to_string(), - mode, - }) - } - ObjectMode::DIR => { - if !path.ends_with('/') { - return Err(other(ObjectError::new( - "create", - path, - anyhow!("Not a directory"), - ))); - } - - Ok(Self { - path: path.to_string(), - mode, - }) - } - ObjectMode::Unknown => Err(other(ObjectError::new( - "create", - path, - anyhow!("create unknown object mode is not supported"), - ))), - } - } - - /// Get path from option. - pub fn path(&self) -> &str { - &self.path - } - - /// Get object mode from option. - pub fn mode(&self) -> ObjectMode { - self.mode - } -} - -/// Args for `read` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpRead { - path: String, - offset: Option, - size: Option, -} - -impl OpRead { - /// Create a new `OpRead`. - /// - /// If input path is not a file path, an error will be returned. - pub fn new(path: &str, range: impl RangeBounds) -> Result { - if path.ends_with('/') { - return Err(other(ObjectError::new( - "read", - path, - anyhow!("Is a directory"), - ))); - } - - let br = BytesRange::from(range); - - Ok(Self { - path: path.to_string(), - offset: br.offset(), - size: br.size(), - }) - } - - pub(crate) fn new_with_offset( - path: &str, - offset: Option, - size: Option, - ) -> Result { - if path.ends_with('/') { - return Err(other(ObjectError::new( - "read", - path, - anyhow!("Is a directory"), - ))); - } - - Ok(Self { - path: path.to_string(), - offset, - size, - }) - } - - /// Get path from option. - pub fn path(&self) -> &str { - &self.path - } - - /// Get offset from option. - pub fn offset(&self) -> Option { - self.offset - } - - /// Get size from option. - pub fn size(&self) -> Option { - self.size - } -} - -/// Args for `stat` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpStat { - path: String, -} - -impl OpStat { - /// Create a new `OpStat`. - pub fn new(path: &str) -> Result { - Ok(Self { - path: path.to_string(), - }) - } - - /// Get path from option. - pub fn path(&self) -> &str { - &self.path - } -} - -/// Args for `write` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpWrite { - path: String, - size: u64, -} - -impl OpWrite { - /// Create a new `OpWrite`. - /// - /// If input path is not a file path, an error will be returned. - pub fn new(path: &str, size: u64) -> Result { - if path.ends_with('/') { - return Err(other(ObjectError::new( - "write", - path, - anyhow!("Is a directory"), - ))); - } - - Ok(Self { - path: path.to_string(), - size, - }) - } - - /// Get path from option. - pub fn path(&self) -> &str { - &self.path - } - - /// Get size from option. - pub fn size(&self) -> u64 { - self.size - } -} - -/// Args for `delete` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpDelete { - path: String, -} - -impl OpDelete { - /// Create a new `OpDelete`. - pub fn new(path: &str) -> Result { - Ok(Self { - path: path.to_string(), - }) - } - - /// Get path from option. - pub fn path(&self) -> &str { - &self.path - } -} - -/// Args for `list` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpList { - path: String, -} - -impl OpList { - /// Create a new `OpList`. - /// - /// If input path is not a dir path, an error will be returned. - pub fn new(path: &str) -> Result { - if !path.ends_with('/') { - return Err(other(ObjectError::new( - "list", - path, - anyhow!("Not a directory"), - ))); - } - - Ok(Self { - path: path.to_string(), - }) - } - - /// Get path from option. - pub fn path(&self) -> &str { - &self.path - } -} - -/// Args for `presign` operation. -/// -/// The path must be normalized. -#[derive(Debug, Clone, Default)] -pub struct OpPresign { - path: String, - op: Operation, - expire: Duration, -} - -impl OpPresign { - /// Create a new `OpPresign`. - pub fn new(path: &str, op: Operation, expire: Duration) -> Result { - Ok(Self { - path: path.to_string(), - op, - expire, - }) - } - - /// Get path from op. - pub fn path(&self) -> &str { - &self.path - } - - /// Get operation from op. - pub fn operation(&self) -> Operation { - self.op - } - - /// Get expire from op. - pub fn expire(&self) -> Duration { - self.expire - } -} - -/// PresignedRequest is a presigned request return by `presign`. -/// -/// # TODO -/// -/// Add signed headers -#[derive(Debug, Clone)] -pub struct PresignedRequest { - method: http::Method, - uri: http::Uri, - headers: http::HeaderMap, -} - -impl PresignedRequest { - /// Create a new PresignedRequest - pub fn new(method: http::Method, uri: http::Uri, headers: http::HeaderMap) -> Self { - Self { - method, - uri, - headers, - } - } - - /// Return request's method. - pub fn method(&self) -> &http::Method { - &self.method - } - - /// Return request's uri. - pub fn uri(&self) -> &http::Uri { - &self.uri - } - - /// Return request's header. - pub fn header(&self) -> &http::HeaderMap { - &self.headers - } -} /// BytesRange(offset, size) carries a range of content. /// diff --git a/src/ops/mod.rs b/src/ops/mod.rs new file mode 100644 index 00000000000..a1c56981470 --- /dev/null +++ b/src/ops/mod.rs @@ -0,0 +1,44 @@ +// Copyright 2022 Datafuse Labs. +// +// 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. + +//! Operations and help utils used by [`Accessor`][crate::Accessor]. +//! +//! # Notes +//! +//! Users should not use struct or functions here except the following cases: +//! +//! - Implement a new service support. +//! - Implement a new Layer. + +mod operation; +pub use operation::Operation; + +mod op_create; +pub use op_create::OpCreate; +mod op_delete; +pub use op_delete::OpDelete; +mod op_list; +pub use op_list::OpList; +mod op_presign; +pub use op_presign::OpPresign; +pub use op_presign::PresignedRequest; +mod op_read; +pub use op_read::OpRead; +mod op_stat; +pub use op_stat::OpStat; +mod op_write; +pub use op_write::OpWrite; + +mod bytes_range; +pub use bytes_range::BytesRange; diff --git a/src/ops/op_create.rs b/src/ops/op_create.rs new file mode 100644 index 00000000000..100b0314926 --- /dev/null +++ b/src/ops/op_create.rs @@ -0,0 +1,82 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; + +use anyhow::anyhow; + +use crate::error::other; +use crate::error::ObjectError; +use crate::ObjectMode; + +/// Args for `create` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpCreate { + path: String, + mode: ObjectMode, +} + +impl OpCreate { + /// Create a new `OpCreate`. + /// + /// If input path is not match with object mode, an error will be returned. + pub fn new(path: &str, mode: ObjectMode) -> Result { + match mode { + ObjectMode::FILE => { + if path.ends_with('/') { + return Err(other(ObjectError::new( + "create", + path, + anyhow!("Is a directory"), + ))); + } + Ok(Self { + path: path.to_string(), + mode, + }) + } + ObjectMode::DIR => { + if !path.ends_with('/') { + return Err(other(ObjectError::new( + "create", + path, + anyhow!("Not a directory"), + ))); + } + + Ok(Self { + path: path.to_string(), + mode, + }) + } + ObjectMode::Unknown => Err(other(ObjectError::new( + "create", + path, + anyhow!("create unknown object mode is not supported"), + ))), + } + } + + /// Get path from option. + pub fn path(&self) -> &str { + &self.path + } + + /// Get object mode from option. + pub fn mode(&self) -> ObjectMode { + self.mode + } +} diff --git a/src/ops/op_delete.rs b/src/ops/op_delete.rs new file mode 100644 index 00000000000..347f15ba9ec --- /dev/null +++ b/src/ops/op_delete.rs @@ -0,0 +1,37 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; + +/// Args for `delete` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpDelete { + path: String, +} + +impl OpDelete { + /// Create a new `OpDelete`. + pub fn new(path: &str) -> Result { + Ok(Self { + path: path.to_string(), + }) + } + + /// Get path from option. + pub fn path(&self) -> &str { + &self.path + } +} diff --git a/src/ops/op_list.rs b/src/ops/op_list.rs new file mode 100644 index 00000000000..d87c3f7188f --- /dev/null +++ b/src/ops/op_list.rs @@ -0,0 +1,52 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; + +use anyhow::anyhow; + +use crate::error::other; +use crate::error::ObjectError; + +/// Args for `list` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpList { + path: String, +} + +impl OpList { + /// Create a new `OpList`. + /// + /// If input path is not a dir path, an error will be returned. + pub fn new(path: &str) -> Result { + if !path.ends_with('/') { + return Err(other(ObjectError::new( + "list", + path, + anyhow!("Not a directory"), + ))); + } + + Ok(Self { + path: path.to_string(), + }) + } + + /// Get path from option. + pub fn path(&self) -> &str { + &self.path + } +} diff --git a/src/ops/op_presign.rs b/src/ops/op_presign.rs new file mode 100644 index 00000000000..8c2112537c1 --- /dev/null +++ b/src/ops/op_presign.rs @@ -0,0 +1,89 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; + +use time::Duration; + +use super::Operation; + +/// Args for `presign` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpPresign { + path: String, + op: Operation, + expire: Duration, +} + +impl OpPresign { + /// Create a new `OpPresign`. + pub fn new(path: &str, op: Operation, expire: Duration) -> Result { + Ok(Self { + path: path.to_string(), + op, + expire, + }) + } + + /// Get path from op. + pub fn path(&self) -> &str { + &self.path + } + + /// Get operation from op. + pub fn operation(&self) -> Operation { + self.op + } + + /// Get expire from op. + pub fn expire(&self) -> Duration { + self.expire + } +} + +/// PresignedRequest is a presigned request return by `presign`. +#[derive(Debug, Clone)] +pub struct PresignedRequest { + method: http::Method, + uri: http::Uri, + headers: http::HeaderMap, +} + +impl PresignedRequest { + /// Create a new PresignedRequest + pub fn new(method: http::Method, uri: http::Uri, headers: http::HeaderMap) -> Self { + Self { + method, + uri, + headers, + } + } + + /// Return request's method. + pub fn method(&self) -> &http::Method { + &self.method + } + + /// Return request's uri. + pub fn uri(&self) -> &http::Uri { + &self.uri + } + + /// Return request's header. + pub fn header(&self) -> &http::HeaderMap { + &self.headers + } +} diff --git a/src/ops/op_read.rs b/src/ops/op_read.rs new file mode 100644 index 00000000000..b33970874e6 --- /dev/null +++ b/src/ops/op_read.rs @@ -0,0 +1,90 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; +use std::ops::RangeBounds; + +use anyhow::anyhow; + +use super::BytesRange; +use crate::error::other; +use crate::error::ObjectError; + +/// Args for `read` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpRead { + path: String, + offset: Option, + size: Option, +} + +impl OpRead { + /// Create a new `OpRead`. + /// + /// If input path is not a file path, an error will be returned. + pub fn new(path: &str, range: impl RangeBounds) -> Result { + if path.ends_with('/') { + return Err(other(ObjectError::new( + "read", + path, + anyhow!("Is a directory"), + ))); + } + + let br = BytesRange::from(range); + + Ok(Self { + path: path.to_string(), + offset: br.offset(), + size: br.size(), + }) + } + + pub(crate) fn new_with_offset( + path: &str, + offset: Option, + size: Option, + ) -> Result { + if path.ends_with('/') { + return Err(other(ObjectError::new( + "read", + path, + anyhow!("Is a directory"), + ))); + } + + Ok(Self { + path: path.to_string(), + offset, + size, + }) + } + + /// Get path from option. + pub fn path(&self) -> &str { + &self.path + } + + /// Get offset from option. + pub fn offset(&self) -> Option { + self.offset + } + + /// Get size from option. + pub fn size(&self) -> Option { + self.size + } +} diff --git a/src/ops/op_stat.rs b/src/ops/op_stat.rs new file mode 100644 index 00000000000..ce5f7a13093 --- /dev/null +++ b/src/ops/op_stat.rs @@ -0,0 +1,37 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; + +/// Args for `stat` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpStat { + path: String, +} + +impl OpStat { + /// Create a new `OpStat`. + pub fn new(path: &str) -> Result { + Ok(Self { + path: path.to_string(), + }) + } + + /// Get path from option. + pub fn path(&self) -> &str { + &self.path + } +} diff --git a/src/ops/op_write.rs b/src/ops/op_write.rs new file mode 100644 index 00000000000..0db71d94bd5 --- /dev/null +++ b/src/ops/op_write.rs @@ -0,0 +1,59 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::io::Result; + +use anyhow::anyhow; + +use crate::error::other; +use crate::error::ObjectError; + +/// Args for `write` operation. +/// +/// The path must be normalized. +#[derive(Debug, Clone, Default)] +pub struct OpWrite { + path: String, + size: u64, +} + +impl OpWrite { + /// Create a new `OpWrite`. + /// + /// If input path is not a file path, an error will be returned. + pub fn new(path: &str, size: u64) -> Result { + if path.ends_with('/') { + return Err(other(ObjectError::new( + "write", + path, + anyhow!("Is a directory"), + ))); + } + + Ok(Self { + path: path.to_string(), + size, + }) + } + + /// Get path from option. + pub fn path(&self) -> &str { + &self.path + } + + /// Get size from option. + pub fn size(&self) -> u64 { + self.size + } +} diff --git a/src/ops/operation.rs b/src/ops/operation.rs new file mode 100644 index 00000000000..d576a980476 --- /dev/null +++ b/src/ops/operation.rs @@ -0,0 +1,80 @@ +// Copyright 2022 Datafuse Labs. +// +// 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 std::fmt::Display; +use std::fmt::Formatter; + +/// Operation is the name for APIs in `Accessor`. +#[derive(Debug, Copy, Clone)] +pub enum Operation { + /// Operation for [`crate::Accessor::metadata`] + Metadata, + /// Operation for [`crate::Accessor::create`] + Create, + /// Operation for [`crate::Accessor::read`] + Read, + /// Operation for [`crate::Accessor::write`] + Write, + /// Operation for [`crate::Accessor::stat`] + Stat, + /// Operation for [`crate::Accessor::delete`] + Delete, + /// Operation for [`crate::Accessor::list`] + List, + /// Operation for [`crate::Accessor::presign`] + Presign, +} + +impl Operation { + /// Convert self into static str. + pub fn into_static(self) -> &'static str { + self.into() + } +} + +impl Default for Operation { + fn default() -> Self { + Operation::Metadata + } +} + +impl Display for Operation { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Operation::Metadata => write!(f, "metadata"), + Operation::Create => write!(f, "create"), + Operation::Read => write!(f, "read"), + Operation::Write => write!(f, "write"), + Operation::Stat => write!(f, "stat"), + Operation::Delete => write!(f, "delete"), + Operation::List => write!(f, "list"), + Operation::Presign => write!(f, "presign"), + } + } +} + +impl From for &'static str { + fn from(v: Operation) -> &'static str { + match v { + Operation::Metadata => "metadata", + Operation::Create => "create", + Operation::Read => "read", + Operation::Write => "write", + Operation::Stat => "stat", + Operation::Delete => "delete", + Operation::List => "list", + Operation::Presign => "presign", + } + } +} diff --git a/src/services/obs/backend.rs b/src/services/obs/backend.rs index 3f52ec47e52..b63ae16bf45 100644 --- a/src/services/obs/backend.rs +++ b/src/services/obs/backend.rs @@ -13,29 +13,41 @@ // limitations under the License. use std::collections::HashMap; +use std::fmt::Debug; use std::io::Result; -use std::{fmt::Debug, sync::Arc}; +use std::sync::Arc; use anyhow::anyhow; use async_trait::async_trait; -use http::{StatusCode, Uri}; +use http::StatusCode; +use http::Uri; use log::debug; use log::info; use reqsign::services::huaweicloud::obs::Signer; use super::error::parse_error; -use crate::error::{other, BackendError}; -use crate::http_util::{ - new_request_build_error, new_request_send_error, new_request_sign_error, parse_error_response, - percent_encode_path, -}; +use crate::error::other; +use crate::error::BackendError; +use crate::http_util::new_request_build_error; +use crate::http_util::new_request_send_error; +use crate::http_util::new_request_sign_error; +use crate::http_util::parse_error_response; +use crate::http_util::percent_encode_path; +use crate::http_util::HttpClient; use crate::ops::BytesRange; +use crate::ops::OpCreate; +use crate::ops::OpDelete; +use crate::ops::OpList; +use crate::ops::OpRead; +use crate::ops::OpStat; +use crate::ops::OpWrite; +use crate::Accessor; +use crate::AccessorMetadata; +use crate::BytesReader; +use crate::BytesWriter; +use crate::DirStreamer; +use crate::ObjectMetadata; use crate::Scheme; -use crate::{ - http_util::HttpClient, - ops::{OpCreate, OpDelete, OpList, OpRead, OpStat, OpWrite}, - Accessor, AccessorMetadata, BytesReader, BytesWriter, DirStreamer, ObjectMetadata, -}; /// Builder for Huaweicloud OBS services #[derive(Default, Clone)]