diff --git a/core/src/types/operator/operator.rs b/core/src/types/operator/operator.rs index 08f8e492f26a..196d332218dd 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("".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 { + 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 { + 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>> { + 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>> { + opts: options::ReadOptions, + ) -> Result { 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 { + 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>> { + 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>> { + opts: options::WriteOptions, + ) -> Result { 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 { + 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 { + 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 { + 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 056d6e7ab424..ef263fd24fd6 100644 --- a/core/src/types/operator/operator_futures.rs +++ b/core/src/types/operator/operator_futures.rs @@ -70,14 +70,6 @@ impl>> OperatorFuture { } } -impl>> OperatorFuture { - /// Change the operation's args. - pub(crate) fn map(mut self, f: impl FnOnce(I) -> I) -> Self { - self.args = f(self.args); - self - } -} - impl IntoFuture for OperatorFuture where F: Future>, @@ -140,98 +132,116 @@ impl>> FutureStat { /// Future that generated by [`Operator::presign_stat_with`]. /// /// Users can add more options by public functions provided by this struct. -pub type FuturePresignStat = OperatorFuture<(OpStat, Duration), PresignedRequest, F>; +pub type FuturePresignStat = + OperatorFuture<(options::StatOptions, Duration), PresignedRequest, F>; impl>> FuturePresignStat { - /// 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 = OperatorFuture<(OpDelete, Duration), PresignedRequest, F>; +pub type FuturePresignDelete = + OperatorFuture<(options::DeleteOptions, Duration), PresignedRequest, F>; impl>> FuturePresignDelete {} /// Future that generated by [`Operator::presign_read_with`]. /// /// Users can add more options by public functions provided by this struct. -pub type FuturePresignRead = OperatorFuture<(OpRead, Duration), PresignedRequest, F>; +pub type FuturePresignRead = + OperatorFuture<(options::ReadOptions, Duration), PresignedRequest, F>; impl>> FuturePresignRead { - /// 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 = OperatorFuture<(OpWrite, Duration), PresignedRequest, F>; +pub type FuturePresignWrite = + OperatorFuture<(options::WriteOptions, Duration), PresignedRequest, F>; impl>> FuturePresignWrite { - /// 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 } }