From d116d8d70d7ee1ebffb3c0bc8ff95794edfbcdb6 Mon Sep 17 00:00:00 2001 From: Kould Date: Wed, 9 Oct 2024 11:32:39 +0800 Subject: [PATCH] feat: add `FsOptions::parse` to new `DynFs` --- fusio/Cargo.toml | 3 +- fusio/src/impls/remotes/aws/credential.rs | 2 +- fusio/src/impls/remotes/aws/mod.rs | 2 +- fusio/src/lib.rs | 2 + fusio/src/options.rs | 91 +++++++++++++++++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 fusio/src/options.rs diff --git a/fusio/Cargo.toml b/fusio/Cargo.toml index 3aeaf36..972a6f9 100644 --- a/fusio/Cargo.toml +++ b/fusio/Cargo.toml @@ -38,7 +38,7 @@ http = [ monoio = ["async-stream", "completion-based", "dep:monoio", "no-send"] monoio-http = ["h2", "http", "hyper"] no-send = [] -object_store = ["dep:object_store"] +object_store = ["dep:fusio-object-store", "dep:object_store"] tokio = ["async-stream", "dep:tokio"] tokio-http = ["dep:reqwest", "http"] tokio-uring = ["async-stream", "completion-based", "dep:tokio-uring", "no-send"] @@ -58,6 +58,7 @@ chrono = { version = "0.4", optional = true, default-features = false, features "now", "std", ] } +fusio-object-store = { version = "0.1.1", optional = true } futures-core = { version = "0.3" } futures-util = { version = "0.3", optional = true, default-features = false } h2 = { version = "0.4.6", optional = true } diff --git a/fusio/src/impls/remotes/aws/credential.rs b/fusio/src/impls/remotes/aws/credential.rs index 7ac19d2..9e49c60 100644 --- a/fusio/src/impls/remotes/aws/credential.rs +++ b/fusio/src/impls/remotes/aws/credential.rs @@ -48,7 +48,7 @@ const EMPTY_SHA256_HASH: &str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934 const UNSIGNED_PAYLOAD: &str = "UNSIGNED-PAYLOAD"; const STREAMING_PAYLOAD: &str = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AwsCredential { /// AWS_ACCESS_KEY_ID pub key_id: String, diff --git a/fusio/src/impls/remotes/aws/mod.rs b/fusio/src/impls/remotes/aws/mod.rs index 1574799..198060c 100644 --- a/fusio/src/impls/remotes/aws/mod.rs +++ b/fusio/src/impls/remotes/aws/mod.rs @@ -1,4 +1,4 @@ -mod credential; +pub(crate) mod credential; mod error; #[cfg(feature = "fs")] pub mod fs; diff --git a/fusio/src/lib.rs b/fusio/src/lib.rs index 1de65cd..42edbdb 100644 --- a/fusio/src/lib.rs +++ b/fusio/src/lib.rs @@ -5,6 +5,8 @@ mod error; #[cfg(feature = "fs")] pub mod fs; pub mod impls; +#[cfg(feature = "fs")] +pub mod options; pub mod path; use std::future::Future; diff --git a/fusio/src/options.rs b/fusio/src/options.rs new file mode 100644 index 0000000..af623c3 --- /dev/null +++ b/fusio/src/options.rs @@ -0,0 +1,91 @@ +use std::sync::Arc; + +use crate::{DynFs, Error}; + +#[derive(Clone)] +#[non_exhaustive] +pub enum FsOptions { + #[cfg(all(feature = "fs", any(feature = "tokio", feature = "monoio")))] + Local, + #[cfg(feature = "aws")] + S3 { + bucket: String, + credential: Option, + region: Option, + sign_payload: Option, + checksum: Option, + }, +} + +impl FsOptions { + pub fn parse(self) -> Result, Error> { + match self { + #[cfg(all(feature = "fs", any(feature = "tokio", feature = "monoio")))] + FsOptions::Local => Ok(Arc::new(crate::impls::disk::LocalFs {})), + #[cfg(all(feature = "aws", feature = "object_store"))] + FsOptions::S3 { + bucket, + credential, + region, + sign_payload, + checksum, + } => { + use fusio_object_store::fs::S3Store; + use object_store::aws::AmazonS3Builder; + + let mut builder = AmazonS3Builder::new().with_bucket_name(bucket); + + if let Some(credential) = credential { + builder = builder + .with_access_key_id(credential.key_id) + .with_secret_access_key(credential.secret_key); + + if let Some(token) = credential.token { + builder = builder.with_token(token); + } + } + if let Some(region) = region { + builder = builder.with_region(region); + } + if let Some(sign_payload) = sign_payload { + builder = builder.with_unsigned_payload(!sign_payload); + } + if matches!(checksum, Some(true)) { + builder = builder.with_checksum_algorithm(object_store::aws::Checksum::SHA256); + } + Ok(Arc::new(S3Store::new( + builder.build().map_err(crate::error::BoxedError::from)?, + ))) + } + #[cfg(feature = "aws")] + FsOptions::S3 { + bucket, + credential, + region, + sign_payload, + checksum, + } => { + use crate::remotes::aws::fs::AmazonS3Builder; + + let mut builder = AmazonS3Builder::new(bucket); + + if let Some(credential) = credential { + builder = builder.credential(credential); + } + if let Some(region) = region { + builder = builder.region(region); + } + if let Some(sign_payload) = sign_payload { + builder = builder.sign_payload(sign_payload); + } + if let Some(checksum) = checksum { + builder = builder.checksum(checksum); + } + Ok(Arc::new(builder.build())) + } + _ => Err(Error::Unsupported { + message: "no matching `DynFS`".to_string(), + }), + } + } +}