Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add docs for azblob's public structs #230

Merged
merged 1 commit into from
Apr 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/service_test_azblob.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ jobs:
--name test \
--connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"


- name: Test
shell: bash
run: cargo test azblob --all-features -- --nocapture
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ OpenDAL is in **alpha** stage and has been early adopted by [databend](https://g

## Supported Services

- [azblob](https://docs.rs/opendal/latest/opendal/services/azblob/index.html): Azure Storage Blob services.
- [fs](https://docs.rs/opendal/latest/opendal/services/fs/index.html): POSIX alike file system.
- [memory](https://docs.rs/opendal/latest/opendal/services/memory/index.html): In memory backend support.
- [memory](https://docs.rs/opendal/latest/opendal/services/memory/index.html): In memory backend.
- [s3](https://docs.rs/opendal/latest/opendal/services/s3/index.html): AWS S3 alike services.

## Quickstart
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//!
//! | Services | Description |
//! | -------- | ----------- |
//! | [azblob][crate::services::azblob] | Azure Storage Blob services. |
//! | [fs][crate::services::fs] | POSIX alike file system. |
//! | [memory][crate::services::memory] | In memory backend support. |
//! | [s3][crate::services::s3] | AWS S3 alike services. |
Expand Down
38 changes: 33 additions & 5 deletions src/services/azblob/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ use crate::BytesWriter;
use crate::ObjectMode;
use crate::ObjectStreamer;

pub const X_MS_BLOB_TYPE: &str = "x-ms-blob-type";
const X_MS_BLOB_TYPE: &str = "x-ms-blob-type";

/// Builder for azblob services
#[derive(Default, Clone)]
pub struct Builder {
root: Option<String>,
Expand Down Expand Up @@ -93,6 +94,9 @@ impl Debug for Builder {
}

impl Builder {
/// Set root of this backend.
///
/// All operations will happen under this root.
pub fn root(&mut self, root: &str) -> &mut Self {
if !root.is_empty() {
self.root = Some(root.to_string())
Expand All @@ -101,25 +105,43 @@ impl Builder {
self
}

/// Set container name of this backend.
pub fn container(&mut self, container: &str) -> &mut Self {
self.container = container.to_string();

self
}

/// Set endpoint of this backend.
///
/// Endpoint must be full uri, e.g.
///
/// - Azblob: `https://accountname.blob.core.windows.net`
/// - Azurite: `http://127.0.0.1:10000/devstoreaccount1`
pub fn endpoint(&mut self, endpoint: &str) -> &mut Self {
if !endpoint.is_empty() {
self.endpoint = Some(endpoint.to_string());
}

self
}

/// Set account_name of this backend.
///
/// - If account_name is set, we will take user's input first.
/// - If not, we will try to load it from environment.
pub fn account_name(&mut self, account_name: &str) -> &mut Self {
if !account_name.is_empty() {
self.account_name = Some(account_name.to_string());
}

self
}

/// Set account_key of this backend.
///
/// - If account_key is set, we will take user's input first.
/// - If not, we will try to load it from environment.
pub fn account_key(&mut self, account_key: &str) -> &mut Self {
if !account_key.is_empty() {
self.account_key = Some(account_key.to_string());
Expand All @@ -128,6 +150,7 @@ impl Builder {
self
}

/// Consume builder to build an azblob backend.
pub async fn finish(&mut self) -> Result<Arc<dyn Accessor>> {
info!("backend build started: {:?}", &self);

Expand Down Expand Up @@ -163,9 +186,13 @@ impl Builder {
debug!("backend use container {}", &container);

let endpoint = match &self.endpoint {
Some(endpoint) => endpoint.clone(),
None => "https://blob.core.windows.net".to_string(),
};
Some(endpoint) => Ok(endpoint.clone()),
None => Err(other(BackendError::new(
HashMap::from([("endpoint".to_string(), "".to_string())]),
anyhow!("endpoint is empty"),
))),
}?;
debug!("backend use endpoint {}", &container);

let context = HashMap::from([
("container".to_string(), container.to_string()),
Expand Down Expand Up @@ -195,7 +222,7 @@ impl Builder {
}))
}
}

/// Backend for azblob services.
#[derive(Debug, Clone)]
pub struct Backend {
container: String,
Expand Down Expand Up @@ -233,6 +260,7 @@ impl Backend {
}
}
}

#[async_trait]
impl Accessor for Backend {
#[trace("read")]
Expand Down
61 changes: 61 additions & 0 deletions src/services/azblob/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,67 @@
// 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.

//! Azure Storage Blob services support.
//!
//! # Example
//!
//! This example works on [Azurite](https://github.com/Azure/Azurite) for local developments.
//!
//! ## Start local blob service
//!
//! ```shell
//! docker run -p 10000:10000 mcr.microsoft.com/azure-storage/azurite
//! az storage container create --name test --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
//! ```
//!
//! ## Init OpenDAL Operator
//!
//! ```no_run
//! use std::sync::Arc;
//!
//! use anyhow::Result;
//! use opendal::services::azblob;
//! use opendal::services::azblob::Builder;
//! use opendal::Accessor;
//! use opendal::Object;
//! use opendal::Operator;
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! // Create azblob backend builder.
//! let mut builder: Builder = azblob::Backend::build();
//! // Set the root for azblob, all operations will happen under this root.
//! //
//! // NOTE: the root must be absolute path.
//! builder.root("/path/to/dir");
//! // Set the container name, this is required.
//! builder.container("test");
//! // Set the endpoint, this is required.
//! //
//! // For examples:
//! // - "http://127.0.0.1:10000/devstoreaccount1"
//! // - "https://accountname.blob.core.windows.net"
//! builder.endpoint("http://127.0.0.1:10000/devstoreaccount1");
//! // Set the account_name and account_key.
//! //
//! // OpenDAL will try load credential from the env.
//! // If credential not set and no valid credential in env, OpenDAL will
//! // send request without signing like anonymous user.
//! builder.account_name("devstoreaccount1");
//! builder.account_key("Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");
//! // Build the `Accessor`.
//! let accessor: Arc<dyn Accessor> = builder.finish().await?;
//!
//! // `Accessor` provides the low level APIs, we will use `Operator` normally.
//! let op: Operator = Operator::new(accessor);
//!
//! // Create an object handle to start operation on object.
//! let _: Object = op.object("test_file");
//!
//! Ok(())
//! }
//! ```
mod backend;
pub use backend::Backend;
pub use backend::Builder;
Expand Down
10 changes: 7 additions & 3 deletions src/services/azblob/object_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ pub struct AzblobObjectStream {
done: bool,
state: State,
}

enum State {
Idle,
Sending(BoxFuture<'static, Result<bytes::Bytes>>),
Listing((Output, usize, usize)),
}

impl AzblobObjectStream {
pub fn new(backend: Backend, path: String) -> Self {
Self {
Expand Down Expand Up @@ -177,11 +179,13 @@ struct Blobs {
blob: Vec<Blob>,
blob_prefix: Option<Vec<BlobPrefix>>,
}

#[derive(Default, Debug, Deserialize)]
#[serde(default, rename_all = "PascalCase")]
struct BlobPrefix {
name: String,
}

#[derive(Default, Debug, Deserialize)]
#[serde(default, rename_all = "PascalCase")]
struct Blob {
Expand All @@ -199,13 +203,13 @@ struct Properties {
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_parse_xml() {
let bs = bytes::Bytes::from(
r#"
\xef\xbb\xbf
r#"
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ServiceEndpoint="https://d2lark.blob.core.windows.net/" ContainerName="myazurebucket">
<EnumerationResults ServiceEndpoint="https://test.blob.core.windows.net/" ContainerName="myazurebucket">
<Prefix>dir1/</Prefix>
<Delimiter>/</Delimiter>
<Blobs>
Expand Down