This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 03d6c7734 feat(core): Expose presign_xxx_options API (#6273)
03d6c7734 is described below
commit 03d6c77341ab82f0fc0bd6aacc139d0bd13da0a1
Author: Drew Gallardo <[email protected]>
AuthorDate: Tue Jun 10 03:14:12 2025 -0700
feat(core): Expose presign_xxx_options API (#6273)
* Expose presign_xxx_options API
* remove presign option tests
* remove options change to s3
---
core/src/types/operator/operator.rs | 324 +++++++++++++++++++---------
core/src/types/operator/operator_futures.rs | 118 +++++-----
2 files changed, 281 insertions(+), 161 deletions(-)
diff --git a/core/src/types/operator/operator.rs
b/core/src/types/operator/operator.rs
index 08f8e492f..196d33221 100644
--- a/core/src/types/operator/operator.rs
+++ b/core/src/types/operator/operator.rs
@@ -1652,15 +1652,63 @@ impl Operator {
OperatorFuture::new(
self.inner().clone(),
path,
- (OpStat::default(), expire),
- |inner, path, (args, dur)| async move {
- let op = OpPresign::new(args, dur);
- let rp = inner.presign(&path, op).await?;
- Ok(rp.into_presigned_request())
- },
+ (options::StatOptions::default(), expire),
+ Self::presign_stat_inner,
)
}
+ /// Presign an operation for stat(head) with additional options.
+ ///
+ /// # Options
+ ///
+ /// Visit [`options::StatOptions`] for all available options.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use anyhow::Result;
+ /// use opendal::Operator;
+ /// use opendal::options;
+ /// use std::time::Duration;
+ ///
+ /// async fn test(op: Operator) -> Result<()> {
+ /// let signed_req = op.presign_stat_options(
+ /// "test",
+ /// Duration::from_secs(3600),
+ /// options::StatOptions {
+ /// if_match: Some("<etag>".to_string()),
+ /// ..Default::default()
+ /// }
+ /// ).await?;
+ /// let req = http::Request::builder()
+ /// .method(signed_req.method())
+ /// .uri(signed_req.uri())
+ /// .body(())?;
+ ///
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub async fn presign_stat_options(
+ &self,
+ path: &str,
+ expire: Duration,
+ opts: options::StatOptions,
+ ) -> Result<PresignedRequest> {
+ let path = normalize_path(path);
+ Self::presign_stat_inner(self.inner().clone(), path, (opts,
expire)).await
+ }
+
+ #[inline]
+ async fn presign_stat_inner(
+ acc: Accessor,
+ path: String,
+ (opts, expire): (options::StatOptions, Duration),
+ ) -> Result<PresignedRequest> {
+ let op = OpPresign::new(OpStat::from(opts), expire);
+ let rp = acc.presign(&path, op).await?;
+ Ok(rp.into_presigned_request())
+ }
+
/// Presign an operation for read.
///
/// # Notes
@@ -1668,8 +1716,8 @@ impl Operator {
/// ## Extra Options
///
/// `presign_read` is a wrapper of [`Self::presign_read_with`] without any
options. To use
- /// extra options like `override_content_disposition`, please use
[`Self::presign_read_with`]
- /// instead.
+ /// extra options like `override_content_disposition`, please use
[`Self::presign_read_with`] or
+ /// [`Self::presign_read_options] instead.
///
/// # Example
///
@@ -1707,80 +1755,91 @@ impl Operator {
///
/// # Options
///
- /// ## `override_content_disposition`
+ /// Visit [`options::ReadOptions`] for all available options.
///
- /// Override the
[`content-disposition`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
header returned by storage services.
+ /// # Example
///
/// ```
/// use std::time::Duration;
///
/// use anyhow::Result;
+ /// use futures::io;
/// use opendal::Operator;
///
/// async fn test(op: Operator) -> Result<()> {
/// let signed_req = op
/// .presign_read_with("test.txt", Duration::from_secs(3600))
- /// .override_content_disposition("attachment;
filename=\"othertext.txt\"")
+ /// .override_content_type("text/plain")
/// .await?;
/// Ok(())
/// }
/// ```
+ pub fn presign_read_with(
+ &self,
+ path: &str,
+ expire: Duration,
+ ) -> FuturePresignRead<impl Future<Output = Result<PresignedRequest>>> {
+ let path = normalize_path(path);
+
+ OperatorFuture::new(
+ self.inner().clone(),
+ path,
+ (options::ReadOptions::default(), expire),
+ Self::presign_read_inner,
+ )
+ }
+
+ /// Presign an operation for read with additional options.
///
- /// ## `override_cache_control`
- ///
- /// Override the
[`cache-control`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
header returned by storage services.
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// use anyhow::Result;
- /// use opendal::Operator;
- ///
- /// async fn test(op: Operator) -> Result<()> {
- /// let signed_req = op
- /// .presign_read_with("test.txt", Duration::from_secs(3600))
- /// .override_cache_control("no-store")
- /// .await?;
- /// Ok(())
- /// }
- /// ```
+ /// # Options
///
- /// ## `override_content_type`
+ /// Visit [`options::ReadOptions`] for all available options.
///
- /// Override the
[`content-type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)
header returned by storage services.
+ /// # Example
///
/// ```
- /// use std::time::Duration;
- ///
/// use anyhow::Result;
- /// use futures::io;
/// use opendal::Operator;
+ /// use opendal::options;
+ /// use std::time::Duration;
///
/// async fn test(op: Operator) -> Result<()> {
- /// let signed_req = op
- /// .presign_read_with("test.txt", Duration::from_secs(3600))
- /// .override_content_type("text/plain")
- /// .await?;
- /// Ok(())
- /// }
+ /// let signed_req = op.presign_read_options(
+ /// "file",
+ /// Duration::from_secs(3600),
+ /// options::ReadOptions {
+ /// override_content_disposition: Some("attachment;
filename=\"othertext.txt\"".to_string()),
+ /// ..Default::default()
+ /// }
+ /// ).await?;
+ /// let req = http::Request::builder()
+ /// .method(signed_req.method())
+ /// .uri(signed_req.uri())
+ /// .body(())?;
+ ///
+ /// # Ok(())
+ /// # }
/// ```
- pub fn presign_read_with(
+ pub async fn presign_read_options(
&self,
path: &str,
expire: Duration,
- ) -> FuturePresignRead<impl Future<Output = Result<PresignedRequest>>> {
+ opts: options::ReadOptions,
+ ) -> Result<PresignedRequest> {
let path = normalize_path(path);
+ Self::presign_read_inner(self.inner().clone(), path, (opts,
expire)).await
+ }
- OperatorFuture::new(
- self.inner().clone(),
- path,
- (OpRead::default(), expire),
- |inner, path, (args, dur)| async move {
- let op = OpPresign::new(args, dur);
- let rp = inner.presign(&path, op).await?;
- Ok(rp.into_presigned_request())
- },
- )
+ #[inline]
+ async fn presign_read_inner(
+ acc: Accessor,
+ path: String,
+ (opts, expire): (options::ReadOptions, Duration),
+ ) -> Result<PresignedRequest> {
+ let (op_read, _) = opts.into();
+ let op = OpPresign::new(op_read, expire);
+ let rp = acc.presign(&path, op).await?;
+ Ok(rp.into_presigned_request())
}
/// Presign an operation for write.
@@ -1790,7 +1849,8 @@ impl Operator {
/// ## Extra Options
///
/// `presign_write` is a wrapper of [`Self::presign_write_with`] without
any options. To use
- /// extra options like `content_type`, please use
[`Self::presign_write_with`] instead.
+ /// extra options like `content_type`, please use
[`Self::presign_write_with`] or
+ /// [`Self::presign_write_options`] instead.
///
/// # Example
///
@@ -1825,9 +1885,9 @@ impl Operator {
///
/// # Options
///
- /// ## `content_type`
+ /// Visit [`options::WriteOptions`] for all available options.
///
- /// Set the
[`content-type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)
header returned by storage services.
+ /// # Example
///
/// ```
/// use std::time::Duration;
@@ -1838,7 +1898,7 @@ impl Operator {
/// async fn test(op: Operator) -> Result<()> {
/// let signed_req = op
/// .presign_write_with("test", Duration::from_secs(3600))
- /// .content_type("text/csv")
+ /// .cache_control("no-store")
/// .await?;
/// let req = http::Request::builder()
/// .method(signed_req.method())
@@ -1848,71 +1908,74 @@ impl Operator {
/// Ok(())
/// }
/// ```
+ pub fn presign_write_with(
+ &self,
+ path: &str,
+ expire: Duration,
+ ) -> FuturePresignWrite<impl Future<Output = Result<PresignedRequest>>> {
+ let path = normalize_path(path);
+
+ OperatorFuture::new(
+ self.inner().clone(),
+ path,
+ (options::WriteOptions::default(), expire),
+ Self::presign_write_inner,
+ )
+ }
+
+ /// Presign an operation for write with additional options.
///
- /// ## `content_disposition`
- ///
- /// Set the
[`content-disposition`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
header returned by storage services.
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// use anyhow::Result;
- /// use opendal::Operator;
- ///
- /// async fn test(op: Operator) -> Result<()> {
- /// let signed_req = op
- /// .presign_write_with("test", Duration::from_secs(3600))
- /// .content_disposition("attachment; filename=\"cool.html\"")
- /// .await?;
- /// let req = http::Request::builder()
- /// .method(signed_req.method())
- /// .uri(signed_req.uri())
- /// .body(())?;
- ///
- /// Ok(())
- /// }
- /// ```
+ /// # Options
///
- /// ## `cache_control`
+ /// Check [`options::WriteOptions`] for all available options.
///
- /// Set the
[`cache-control`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
header returned by storage services.
+ /// # Example
///
/// ```
- /// use std::time::Duration;
- ///
/// use anyhow::Result;
/// use opendal::Operator;
+ /// use opendal::options;
+ /// use std::time::Duration;
///
/// async fn test(op: Operator) -> Result<()> {
- /// let signed_req = op
- /// .presign_write_with("test", Duration::from_secs(3600))
- /// .cache_control("no-store")
- /// .await?;
+ /// let signed_req = op.presign_write_options(
+ /// "file",
+ /// Duration::from_secs(3600),
+ /// options::WriteOptions {
+ /// content_type: Some("application/json".to_string()),
+ /// cache_control: Some("max-age=3600".to_string()),
+ /// if_not_exists: true,
+ /// ..Default::default()
+ /// }
+ /// ).await?;
/// let req = http::Request::builder()
/// .method(signed_req.method())
/// .uri(signed_req.uri())
/// .body(())?;
///
- /// Ok(())
- /// }
+ /// # Ok(())
+ /// # }
/// ```
- pub fn presign_write_with(
+ pub async fn presign_write_options(
&self,
path: &str,
expire: Duration,
- ) -> FuturePresignWrite<impl Future<Output = Result<PresignedRequest>>> {
+ opts: options::WriteOptions,
+ ) -> Result<PresignedRequest> {
let path = normalize_path(path);
+ Self::presign_write_inner(self.inner().clone(), path, (opts,
expire)).await
+ }
- OperatorFuture::new(
- self.inner().clone(),
- path,
- (OpWrite::default(), expire),
- |inner, path, (args, dur)| async move {
- let op = OpPresign::new(args, dur);
- let rp = inner.presign(&path, op).await?;
- Ok(rp.into_presigned_request())
- },
- )
+ #[inline]
+ async fn presign_write_inner(
+ acc: Accessor,
+ path: String,
+ (opts, expire): (options::WriteOptions, Duration),
+ ) -> Result<PresignedRequest> {
+ let (op_write, _) = opts.into();
+ let op = OpPresign::new(op_write, expire);
+ let rp = acc.presign(&path, op).await?;
+ Ok(rp.into_presigned_request())
}
/// Presign an operation for delete.
@@ -1963,12 +2026,59 @@ impl Operator {
OperatorFuture::new(
self.inner().clone(),
path,
- (OpDelete::default(), expire),
- |inner, path, (args, dur)| async move {
- let op = OpPresign::new(args, dur);
- let rp = inner.presign(&path, op).await?;
- Ok(rp.into_presigned_request())
- },
+ (options::DeleteOptions::default(), expire),
+ Self::presign_delete_inner,
)
}
+
+ /// Presign an operation for delete with additional options.
+ ///
+ /// # Options
+ ///
+ /// Visit [`options::DeleteOptions`] for all available options.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use anyhow::Result;
+ /// use opendal::Operator;
+ /// use opendal::options;
+ /// use std::time::Duration;
+ ///
+ /// async fn test(op: Operator) -> Result<()> {
+ /// let signed_req = op.presign_delete_options(
+ /// "path/to/file",
+ /// Duration::from_secs(3600),
+ /// options::DeleteOptions {
+ /// ..Default::default()
+ /// }
+ /// ).await?;
+ /// let req = http::Request::builder()
+ /// .method(signed_req.method())
+ /// .uri(signed_req.uri())
+ /// .body(())?;
+ ///
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub async fn presign_delete_options(
+ &self,
+ path: &str,
+ expire: Duration,
+ opts: options::DeleteOptions,
+ ) -> Result<PresignedRequest> {
+ let path = normalize_path(path);
+ Self::presign_delete_inner(self.inner().clone(), path, (opts,
expire)).await
+ }
+
+ #[inline]
+ async fn presign_delete_inner(
+ acc: Accessor,
+ path: String,
+ (opts, expire): (options::DeleteOptions, Duration),
+ ) -> Result<PresignedRequest> {
+ let op = OpPresign::new(OpDelete::from(opts), expire);
+ let rp = acc.presign(&path, op).await?;
+ Ok(rp.into_presigned_request())
+ }
}
diff --git a/core/src/types/operator/operator_futures.rs
b/core/src/types/operator/operator_futures.rs
index 056d6e7ab..ef263fd24 100644
--- a/core/src/types/operator/operator_futures.rs
+++ b/core/src/types/operator/operator_futures.rs
@@ -70,14 +70,6 @@ impl<I, O, F: Future<Output = Result<O>>> OperatorFuture<I,
O, F> {
}
}
-impl<I, O, F: Future<Output = Result<O>>> OperatorFuture<I, O, F> {
- /// Change the operation's args.
- pub(crate) fn map(mut self, f: impl FnOnce(I) -> I) -> Self {
- self.args = f(self.args);
- self
- }
-}
-
impl<I, O, F> IntoFuture for OperatorFuture<I, O, F>
where
F: Future<Output = Result<O>>,
@@ -140,98 +132,116 @@ impl<F: Future<Output = Result<Metadata>>> FutureStat<F>
{
/// Future that generated by [`Operator::presign_stat_with`].
///
/// Users can add more options by public functions provided by this struct.
-pub type FuturePresignStat<F> = OperatorFuture<(OpStat, Duration),
PresignedRequest, F>;
+pub type FuturePresignStat<F> =
+ OperatorFuture<(options::StatOptions, Duration), PresignedRequest, F>;
impl<F: Future<Output = Result<PresignedRequest>>> FuturePresignStat<F> {
- /// Sets the content-disposition header that should be sent back by the
remote read operation.
- pub fn override_content_disposition(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_override_content_disposition(v),
dur))
+ /// Refer to [`options::StatOptions::override_content_disposition`] for
more details.
+ pub fn override_content_disposition(mut self, v: &str) -> Self {
+ self.args.0.override_content_disposition = Some(v.to_string());
+ self
}
- /// Sets the cache-control header that should be sent back by the remote
read operation.
- pub fn override_cache_control(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_override_cache_control(v), dur))
+ /// Refer to [`options::StatOptions::override_cache_control`] for more
details.
+ pub fn override_cache_control(mut self, v: &str) -> Self {
+ self.args.0.override_cache_control = Some(v.to_string());
+ self
}
- /// Sets the content-type header that should be sent back by the remote
read operation.
- pub fn override_content_type(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_override_content_type(v), dur))
+ /// Refer to [`options::StatOptions::override_content_type`] for more
details.
+ pub fn override_content_type(mut self, v: &str) -> Self {
+ self.args.0.override_content_type = Some(v.to_string());
+ self
}
- /// Set the If-Match of the option
- pub fn if_match(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_if_match(v), dur))
+ /// Refer to [`options::StatOptions::if_match`] for more details.
+ pub fn if_match(mut self, v: &str) -> Self {
+ self.args.0.if_match = Some(v.to_string());
+ self
}
- /// Set the If-None-Match of the option
- pub fn if_none_match(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_if_none_match(v), dur))
+ /// Refer to [`options::StatOptions::if_none_match`] for more details.
+ pub fn if_none_match(mut self, v: &str) -> Self {
+ self.args.0.if_none_match = Some(v.to_string());
+ self
}
}
/// Future that generated by [`Operator::presign_delete_with`].
///
/// Users can add more options by public functions provided by this struct.
-pub type FuturePresignDelete<F> = OperatorFuture<(OpDelete, Duration),
PresignedRequest, F>;
+pub type FuturePresignDelete<F> =
+ OperatorFuture<(options::DeleteOptions, Duration), PresignedRequest, F>;
impl<F: Future<Output = Result<PresignedRequest>>> FuturePresignDelete<F> {}
/// Future that generated by [`Operator::presign_read_with`].
///
/// Users can add more options by public functions provided by this struct.
-pub type FuturePresignRead<F> = OperatorFuture<(OpRead, Duration),
PresignedRequest, F>;
+pub type FuturePresignRead<F> =
+ OperatorFuture<(options::ReadOptions, Duration), PresignedRequest, F>;
impl<F: Future<Output = Result<PresignedRequest>>> FuturePresignRead<F> {
- /// Sets the content-disposition header that should be sent back by the
remote read operation.
- pub fn override_content_disposition(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_override_content_disposition(v),
dur))
+ /// Refer to [`options::ReadOptions::override_content_disposition`] for
more details.
+ pub fn override_content_disposition(mut self, v: &str) -> Self {
+ self.args.0.override_content_disposition = Some(v.to_string());
+ self
}
- /// Sets the cache-control header that should be sent back by the remote
read operation.
- pub fn override_cache_control(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_override_cache_control(v), dur))
+ /// Refer to [`options::ReadOptions::override_cache_control`] for more
details.
+ pub fn override_cache_control(mut self, v: &str) -> Self {
+ self.args.0.override_cache_control = Some(v.to_string());
+ self
}
- /// Sets the content-type header that should be sent back by the remote
read operation.
- pub fn override_content_type(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_override_content_type(v), dur))
+ /// Refer to [`options::ReadOptions::override_content_type`] for more
details.
+ pub fn override_content_type(mut self, v: &str) -> Self {
+ self.args.0.override_content_type = Some(v.to_string());
+ self
}
- /// Set the If-Match of the option
- pub fn if_match(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_if_match(v), dur))
+ /// Refer to [`options::ReadOptions::if_match`] for more details.
+ pub fn if_match(mut self, v: &str) -> Self {
+ self.args.0.if_match = Some(v.to_string());
+ self
}
- /// Set the If-None-Match of the option
- pub fn if_none_match(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_if_none_match(v), dur))
+ /// Refer to [`options::ReadOptions::if_none_match`] for more details.
+ pub fn if_none_match(mut self, v: &str) -> Self {
+ self.args.0.if_none_match = Some(v.to_string());
+ self
}
}
/// Future that generated by [`Operator::presign_write_with`].
///
/// Users can add more options by public functions provided by this struct.
-pub type FuturePresignWrite<F> = OperatorFuture<(OpWrite, Duration),
PresignedRequest, F>;
+pub type FuturePresignWrite<F> =
+ OperatorFuture<(options::WriteOptions, Duration), PresignedRequest, F>;
impl<F: Future<Output = Result<PresignedRequest>>> FuturePresignWrite<F> {
- /// Set the content type of option
- pub fn content_type(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_content_type(v), dur))
+ /// Refer to [`options::WriteOptions::content_type`] for more details.
+ pub fn content_type(mut self, v: &str) -> Self {
+ self.args.0.content_type = Some(v.to_string());
+ self
}
- /// Set the content disposition of option
- pub fn content_disposition(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_content_disposition(v), dur))
+ /// Refer to [`options::WriteOptions::content_disposition`] for more
details.
+ pub fn content_disposition(mut self, v: &str) -> Self {
+ self.args.0.content_disposition = Some(v.to_string());
+ self
}
- /// Set the content encoding of the operation
- pub fn content_encoding(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_content_encoding(v), dur))
+ /// Refer to [`options::WriteOptions::content_encoding`] for more details.
+ pub fn content_encoding(mut self, v: &str) -> Self {
+ self.args.0.content_encoding = Some(v.to_string());
+ self
}
- /// Set the content type of option
- pub fn cache_control(self, v: &str) -> Self {
- self.map(|(args, dur)| (args.with_cache_control(v), dur))
+ /// Refer to [`options::WriteOptions::cache_control`] for more details.
+ pub fn cache_control(mut self, v: &str) -> Self {
+ self.args.0.cache_control = Some(v.to_string());
+ self
}
}