You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2023/03/26 11:59:14 UTC
[incubator-opendal] branch main updated: feat(bindings/nodejs): Support presign (#1772)
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/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 970e3bfe feat(bindings/nodejs): Support presign (#1772)
970e3bfe is described below
commit 970e3bfe2ff12838932e28360757d091177b9dd2
Author: Suyan <su...@gmail.com>
AuthorDate: Sun Mar 26 19:59:09 2023 +0800
feat(bindings/nodejs): Support presign (#1772)
* feat(bindings/nodejs): support presign
Signed-off-by: suyanhanx <su...@gmail.com>
* change header value to string
Signed-off-by: suyanhanx <su...@gmail.com>
* presign example
Signed-off-by: suyanhanx <su...@gmail.com>
---------
Signed-off-by: suyanhanx <su...@gmail.com>
---
bindings/nodejs/README.md | 4 --
bindings/nodejs/examples/presign.js | 49 ++++++++++++++++++++++++
bindings/nodejs/generated.js | 9 ++++-
bindings/nodejs/index.d.ts | 30 +++++++++++++++
bindings/nodejs/src/lib.rs | 74 +++++++++++++++++++++++++++++++++++++
5 files changed, 161 insertions(+), 5 deletions(-)
diff --git a/bindings/nodejs/README.md b/bindings/nodejs/README.md
index 58d084ad..f57fe91c 100644
--- a/bindings/nodejs/README.md
+++ b/bindings/nodejs/README.md
@@ -42,7 +42,6 @@ corepack enable
`corepack` is distributed with Node.js, so you do not need to specifically look for a way to install it.
-
### Build
```bash
@@ -62,9 +61,6 @@ yarn test
We use [`Cucumber`](https://cucumber.io/) for behavior testing. Refer to [here](https://cucumber.io/docs/guides/overview/) for more information about `Cucumber`.
-
-
## License
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
-
diff --git a/bindings/nodejs/examples/presign.js b/bindings/nodejs/examples/presign.js
new file mode 100644
index 00000000..b5826794
--- /dev/null
+++ b/bindings/nodejs/examples/presign.js
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+const http = require('node:http')
+const url = require('node:url')
+const { Operator } = require('../index')
+
+const op = new Operator('s3', {
+ root: '/',
+ bucket: 'example-bucket',
+})
+
+const server = http.createServer(async (req, res) => {
+ res.setHeader('Content-Type', 'text/json; charset=utf-8')
+
+ if (req.url.startsWith('/presign') && req.method === 'GET') {
+ const urlParts = url.parse(req.url, true)
+ const path = urlParts.query.path
+ const expires = urlParts.query.expires
+
+ const presignedRequest = op.presignRead(path, parseInt(expires))
+
+ res.statusCode = 200
+ res.end(JSON.stringify({ url: presignedRequest.uri }))
+ } else {
+ res.statusCode = 404
+ res.end('Not Found')
+ }
+})
+
+server.listen(3000, () => {
+ console.log('Server is listening on port 3000.')
+})
diff --git a/bindings/nodejs/generated.js b/bindings/nodejs/generated.js
index c3c427b3..03d6bf6e 100644
--- a/bindings/nodejs/generated.js
+++ b/bindings/nodejs/generated.js
@@ -17,6 +17,12 @@
* under the License.
*/
+/* tslint:disable */
+/* eslint-disable */
+/* prettier-ignore */
+
+/* auto-generated by NAPI-RS */
+
const { existsSync, readFileSync } = require('fs')
const { join } = require('path')
@@ -265,10 +271,11 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
-const { Operator, Entry, Metadata, Lister, BlockingLister } = nativeBinding
+const { Operator, Entry, Metadata, Lister, BlockingLister, PresignedRequest } = nativeBinding
module.exports.Operator = Operator
module.exports.Entry = Entry
module.exports.Metadata = Metadata
module.exports.Lister = Lister
module.exports.BlockingLister = BlockingLister
+module.exports.PresignedRequest = PresignedRequest
diff --git a/bindings/nodejs/index.d.ts b/bindings/nodejs/index.d.ts
index 4516d193..34cdbae3 100644
--- a/bindings/nodejs/index.d.ts
+++ b/bindings/nodejs/index.d.ts
@@ -64,6 +64,24 @@ export class Operator {
* An error will be returned if given path doesn't end with `/`.
*/
listSync(path: string): BlockingLister
+ /**
+ * Get a presigned request for read.
+ *
+ * Unit of expires is seconds.
+ */
+ presignRead(path: string, expires: number): PresignedRequest
+ /**
+ * Get a presigned request for write.
+ *
+ * Unit of expires is seconds.
+ */
+ presignWrite(path: string, expires: number): PresignedRequest
+ /**
+ * Get a presigned request for stat.
+ *
+ * Unit of expires is seconds.
+ */
+ presignStat(path: string, expires: number): PresignedRequest
}
export class Entry {
/** Return the path of this entry. */
@@ -101,3 +119,15 @@ export class Lister {
export class BlockingLister {
next(): Entry | null
}
+export class PresignedRequest {
+ /** Returns the HTTP method of this request. */
+ get method(): string
+ /** Returns the URI of this request. */
+ get uri(): string
+ /**
+ * Returns the headers of this request.
+ *
+ * The key of the map is the header name, and the value is the header value AS bytes.
+ */
+ headers(): Record<string, string>
+}
diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs
index 2f062cdb..be3f7393 100644
--- a/bindings/nodejs/src/lib.rs
+++ b/bindings/nodejs/src/lib.rs
@@ -24,6 +24,7 @@ use std::str::FromStr;
use futures::TryStreamExt;
use napi::bindgen_prelude::*;
use time::format_description::well_known::Rfc3339;
+use time::Duration;
fn build_operator(
scheme: opendal::Scheme,
@@ -206,6 +207,42 @@ impl Operator {
self.0.blocking().scan(&path).map_err(format_napi_error)?,
))
}
+
+ /// Get a presigned request for read.
+ ///
+ /// Unit of expires is seconds.
+ #[napi]
+ pub fn presign_read(&self, path: String, expires: u32) -> Result<PresignedRequest> {
+ let res = self
+ .0
+ .presign_read(&path, Duration::seconds(expires as i64))
+ .map_err(format_napi_error)?;
+ Ok(PresignedRequest(res))
+ }
+
+ /// Get a presigned request for write.
+ ///
+ /// Unit of expires is seconds.
+ #[napi]
+ pub fn presign_write(&self, path: String, expires: u32) -> Result<PresignedRequest> {
+ let res = self
+ .0
+ .presign_write(&path, Duration::seconds(expires as i64))
+ .map_err(format_napi_error)?;
+ Ok(PresignedRequest(res))
+ }
+
+ /// Get a presigned request for stat.
+ ///
+ /// Unit of expires is seconds.
+ #[napi]
+ pub fn presign_stat(&self, path: String, expires: u32) -> Result<PresignedRequest> {
+ let res = self
+ .0
+ .presign_stat(&path, Duration::seconds(expires as i64))
+ .map_err(format_napi_error)?;
+ Ok(PresignedRequest(res))
+ }
}
#[napi]
@@ -318,6 +355,43 @@ impl BlockingLister {
}
}
+#[napi]
+pub struct PresignedRequest(opendal::raw::PresignedRequest);
+
+#[napi]
+impl PresignedRequest {
+ /// Returns the HTTP method of this request.
+ #[napi(getter)]
+ pub fn method(&self) -> String {
+ self.0.method().to_string()
+ }
+
+ /// Returns the URI of this request.
+ #[napi(getter)]
+ pub fn uri(&self) -> String {
+ self.0.uri().to_string()
+ }
+
+ /// Returns the headers of this request.
+ ///
+ /// The key of the map is the header name, and the value is the header value.
+ #[napi]
+ pub fn headers(&self) -> HashMap<String, String> {
+ self.0
+ .header()
+ .iter()
+ .map(|(k, v)| {
+ (
+ k.as_str().to_string(),
+ v.to_str()
+ .expect("header value contains non visible ascii characters")
+ .to_string(),
+ )
+ })
+ .collect()
+ }
+}
+
fn format_napi_error(err: opendal::Error) -> Error {
Error::from_reason(format!("{}", err))
}