From 751a48cfcdf82f3a63a2a93713e10cc242ef52b3 Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 8 Jul 2024 11:05:09 -0700 Subject: [PATCH] feat(bindings/nodejs): better error code Signed-off-by: tison --- bin/ofs/Cargo.lock | 18 +++++-- bindings/nodejs/CONTRIBUTING.md | 12 +++-- bindings/nodejs/src/lib.rs | 86 ++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/bin/ofs/Cargo.lock b/bin/ofs/Cargo.lock index 2268a79e692..54f45c64b6c 100644 --- a/bin/ofs/Cargo.lock +++ b/bin/ofs/Cargo.lock @@ -1011,7 +1011,7 @@ dependencies = [ "md-5", "once_cell", "percent-encoding", - "quick-xml", + "quick-xml 0.31.0", "rand", "reqsign", "reqwest", @@ -1101,6 +1101,16 @@ dependencies = [ "serde", ] +[[package]] +name = "quick-xml" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86e446ed58cef1bbfe847bc2fda0e2e4ea9f0e57b90c507d4781292590d72a4e" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quinn" version = "0.11.2" @@ -1218,9 +1228,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqsign" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70fe66d4cd0b5ed9b1abbfe639bf6baeaaf509f7da2d51b31111ba945be59286" +checksum = "03dd4ba7c3901dd43e6b8c7446a760d45bc1ea4301002e1a6fa48f97c3a796fa" dependencies = [ "anyhow", "async-trait", @@ -1234,7 +1244,7 @@ dependencies = [ "http", "log", "percent-encoding", - "quick-xml", + "quick-xml 0.35.0", "rand", "reqwest", "rust-ini", diff --git a/bindings/nodejs/CONTRIBUTING.md b/bindings/nodejs/CONTRIBUTING.md index 01d49424b85..d304ec88054 100644 --- a/bindings/nodejs/CONTRIBUTING.md +++ b/bindings/nodejs/CONTRIBUTING.md @@ -79,11 +79,11 @@ Contains the following tools: ```bash # Install dependencies. -> pnpm install +pnpm install # Build from source. -> pnpm build +pnpm build # Build from source with debug info. -> pnpm build:debug +pnpm build:debug ``` ## Test @@ -92,8 +92,12 @@ We are using our own developed behavior testing framework. Taking 'service-memory' as an example, you can use the following command to run it. ```bash -> OPENDAL_TEST=memory pnpm test +OPENDAL_TEST=memory pnpm test +``` + +which will output: +``` ✓ |opendal| tests/service.test.mjs (8 tests | 2 skipped) 40ms Test Files 1 passed (1) diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs index dcc45f15c9c..fd3d2143ae5 100644 --- a/bindings/nodejs/src/lib.rs +++ b/bindings/nodejs/src/lib.rs @@ -30,6 +30,8 @@ use napi::bindgen_prelude::*; mod capability; +type Result = napi::Result; + #[napi] pub struct Operator(opendal::Operator); @@ -755,13 +757,30 @@ pub struct Reader { impl Reader { /// # Safety /// - /// > &mut self in async napi methods should be marked as unsafe + /// `&mut self` in async napi methods should be marked as unsafe /// /// Read bytes from this reader into given buffer. #[napi] pub async unsafe fn read(&mut self, mut buf: Buffer) -> Result { let buf = buf.as_mut(); - let n = self.inner.read(buf).await.map_err(format_napi_error)?; + let n = self + .inner + .read(buf) + .await + .map_err(|e| { + opendal::Error::new( + match e.kind() { + std::io::ErrorKind::NotFound => opendal::ErrorKind::NotFound, + std::io::ErrorKind::PermissionDenied => { + opendal::ErrorKind::PermissionDenied + } + _ => opendal::ErrorKind::Unexpected, + }, + "failed to read bytes", + ) + .set_source(e) + }) + .map_err(format_napi_error)?; Ok(n) } } @@ -1144,9 +1163,64 @@ impl RetryLayer { } } +#[repr(i32)] +#[non_exhaustive] +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +enum ErrorCode { + Unexpected = 1001, + Unsupported = 1002, + ConfigInvalid = 1003, + NotFound = 1004, + PermissionDenied = 1005, + IsADirectory = 1006, + NotADirectory = 1007, + AlreadyExists = 1008, + RateLimited = 1009, + IsSameFile = 1010, + ConditionNotMatch = 1011, + RangeNotSatisfied = 1012, +} + +impl AsRef for ErrorCode { + fn as_ref(&self) -> &str { + match self { + ErrorCode::Unexpected => "Unexpected", + ErrorCode::Unsupported => "Unsupported", + ErrorCode::ConfigInvalid => "ConfigInvalid", + ErrorCode::NotFound => "NotFound", + ErrorCode::PermissionDenied => "PermissionDenied", + ErrorCode::IsADirectory => "IsADirectory", + ErrorCode::NotADirectory => "NotADirectory", + ErrorCode::AlreadyExists => "AlreadyExists", + ErrorCode::RateLimited => "RateLimited", + ErrorCode::IsSameFile => "IsSameFile", + ErrorCode::ConditionNotMatch => "ConditionNotMatch", + ErrorCode::RangeNotSatisfied => "RangeNotSatisfied", + } + } +} + +impl From for ErrorCode { + fn from(err: opendal::Error) -> Self { + match err.kind() { + opendal::ErrorKind::Unexpected => ErrorCode::Unexpected, + opendal::ErrorKind::Unsupported => ErrorCode::Unsupported, + opendal::ErrorKind::ConfigInvalid => ErrorCode::ConfigInvalid, + opendal::ErrorKind::NotFound => ErrorCode::NotFound, + opendal::ErrorKind::PermissionDenied => ErrorCode::PermissionDenied, + opendal::ErrorKind::IsADirectory => ErrorCode::IsADirectory, + opendal::ErrorKind::NotADirectory => ErrorCode::NotADirectory, + opendal::ErrorKind::AlreadyExists => ErrorCode::AlreadyExists, + opendal::ErrorKind::RateLimited => ErrorCode::RateLimited, + opendal::ErrorKind::IsSameFile => ErrorCode::IsSameFile, + opendal::ErrorKind::ConditionNotMatch => ErrorCode::ConditionNotMatch, + opendal::ErrorKind::RangeNotSatisfied => ErrorCode::RangeNotSatisfied, + kind => unimplemented!("error kind not supported: {:?}", kind), + } + } +} + /// Format opendal error to napi error. -/// -/// FIXME: handle error correctly. -fn format_napi_error(err: impl Display) -> Error { - Error::from_reason(format!("{}", err)) +fn format_napi_error(err: opendal::Error) -> Error { + Error::new(err.kind().into(), err.to_string()) }