From c28d79b72fc8783415a2afac548be44cf5f108e9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 13 Aug 2021 10:52:31 +0200 Subject: [PATCH 01/15] rewrite me --- examples/proc_macro.rs | 14 +++++++------- proc-macros/src/new/render_client.rs | 2 +- proc-macros/src/new/render_server.rs | 10 ++++------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/examples/proc_macro.rs b/examples/proc_macro.rs index 258611ac2b..52bbaf46f0 100644 --- a/examples/proc_macro.rs +++ b/examples/proc_macro.rs @@ -26,17 +26,17 @@ use jsonrpsee::{ proc_macros::rpc, - types::async_trait, + types::{async_trait, error::CallError}, ws_client::WsClientBuilder, ws_server::{RpcModule, SubscriptionSink, WsServerBuilder}, }; use std::net::SocketAddr; -#[rpc(client, server, namespace = "state")] +#[rpc(server, client, namespace = "state")] pub trait Rpc { /// Async method call example. #[method(name = "getPairs")] - async fn storage_pairs(&self, prefix: usize, hash: Option) -> Vec; + async fn storage_pairs(&self, prefix: usize, hash: Option) -> Result, CallError>; /// Subscription that take `Option>` as input and produces output `Vec`. #[subscription(name = "subscribeStorage", unsub = "unsubscribeStorage", item = Vec)] @@ -47,8 +47,8 @@ pub struct RpcServerImpl; #[async_trait] impl RpcServer for RpcServerImpl { - async fn storage_pairs(&self, _prefix: usize, _hash: Option) -> Vec { - vec![1, 2, 3, 4] + async fn storage_pairs(&self, _prefix: usize, _hash: Option) -> Result, CallError> { + Ok(vec![1, 2, 3, 4]) } fn subscribe_storage(&self, mut sink: SubscriptionSink, keys: Option>) { @@ -61,13 +61,13 @@ async fn main() -> anyhow::Result<()> { env_logger::init(); let server_addr = run_server().await?; - let url = format!("ws://{}", server_addr); + /*let url = format!("ws://{}", server_addr); let client = WsClientBuilder::default().build(&url).await?; assert_eq!(client.storage_pairs(10, None).await.unwrap(), vec![1, 2, 3, 4]); let mut sub = client.subscribe_storage(None).await.unwrap(); - assert_eq!(Some(vec![]), sub.next().await.unwrap()); + assert_eq!(Some(vec![]), sub.next().await.unwrap());*/ Ok(()) } diff --git a/proc-macros/src/new/render_client.rs b/proc-macros/src/new/render_client.rs index 0d2cff38ec..204f1af322 100644 --- a/proc-macros/src/new/render_client.rs +++ b/proc-macros/src/new/render_client.rs @@ -52,7 +52,7 @@ impl RpcDescription { // `returns` represent the return type of the *rust method* (`Result< <..>, jsonrpsee::Error`). let (called_method, returns) = if let Some(returns) = &method.returns { let called_method = quote::format_ident!("request"); - let returns = quote! { Result<#returns, #jrps_error> }; + let returns = quote! { Result<#returns> }; (called_method, returns) } else { diff --git a/proc-macros/src/new/render_server.rs b/proc-macros/src/new/render_server.rs index 0f4d152111..d59dac218f 100644 --- a/proc-macros/src/new/render_server.rs +++ b/proc-macros/src/new/render_server.rs @@ -25,8 +25,6 @@ impl RpcDescription { } }; - // panic!("{}", trait_impl); - Ok(trait_impl) } @@ -72,7 +70,7 @@ impl RpcDescription { let rpc_method_name = self.rpc_identifier(&method.name); // `parsing` is the code associated with parsing structure from the // provided `RpcParams` object. - // `params_seq` is the comma-delimited sequence of parametsrs. + // `params_seq` is the comma-delimited sequence of parameters. let (parsing, params_seq) = self.render_params_decoding(&method.params); check_name(rpc_method_name.clone(), rust_method_name.span()); @@ -82,7 +80,7 @@ impl RpcDescription { rpc.register_async_method(#rpc_method_name, |params, context| { let fut = async move { #parsing - Ok(context.as_ref().#rust_method_name(#params_seq).await) + context.as_ref().#rust_method_name(#params_seq).await }; Box::pin(fut) })?; @@ -91,7 +89,7 @@ impl RpcDescription { quote! { rpc.register_method(#rpc_method_name, |params, context| { #parsing - Ok(context.#rust_method_name(#params_seq)) + context.#rust_method_name(#params_seq) })?; } } @@ -110,7 +108,7 @@ impl RpcDescription { let rpc_unsub_name = self.rpc_identifier(&sub.unsub_method); // `parsing` is the code associated with parsing structure from the // provided `RpcParams` object. - // `params_seq` is the comma-delimited sequence of parametsrs. + // `params_seq` is the comma-delimited sequence of parameters. let (parsing, params_seq) = self.render_params_decoding(&sub.params); check_name(rpc_sub_name.clone(), rust_method_name.span()); From 4e40a886ff2e3f0cf234ceec12dc868a916fd286 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 13 Aug 2021 15:49:49 +0200 Subject: [PATCH 02/15] require proc macro API to return result --- examples/proc_macro.rs | 10 +++--- proc-macros/src/lib.rs | 14 ++++---- proc-macros/src/new/render_client.rs | 2 +- proc-macros/tests/rpc_example.rs | 5 +-- proc-macros/tests/ui/correct/basic.rs | 14 ++++---- proc-macros/tests/ui/correct/only_client.rs | 6 ++-- proc-macros/tests/ui/correct/only_server.rs | 14 ++++---- .../ui/incorrect/method/method_no_name.rs | 2 +- .../method/method_unexpected_field.rs | 2 +- .../tests/ui/incorrect/rpc/rpc_assoc_items.rs | 4 +-- .../ui/incorrect/rpc/rpc_name_conflict.rs | 6 ++-- .../ui/incorrect/rpc/rpc_name_conflict.stderr | 2 +- .../tests/ui/incorrect/rpc/rpc_no_impls.rs | 2 +- .../ui/incorrect/rpc/rpc_not_qualified.rs | 2 +- .../ui/incorrect/rpc/rpc_not_qualified.stderr | 4 +-- tests/tests/proc_macros.rs | 34 +++++++++++-------- types/src/lib.rs | 3 ++ utils/src/server/rpc_module.rs | 33 +++++++++--------- ws-server/src/tests.rs | 8 +++-- 19 files changed, 89 insertions(+), 78 deletions(-) diff --git a/examples/proc_macro.rs b/examples/proc_macro.rs index 52bbaf46f0..b9f1706d01 100644 --- a/examples/proc_macro.rs +++ b/examples/proc_macro.rs @@ -26,7 +26,7 @@ use jsonrpsee::{ proc_macros::rpc, - types::{async_trait, error::CallError}, + types::{async_trait, error::Error}, ws_client::WsClientBuilder, ws_server::{RpcModule, SubscriptionSink, WsServerBuilder}, }; @@ -36,7 +36,7 @@ use std::net::SocketAddr; pub trait Rpc { /// Async method call example. #[method(name = "getPairs")] - async fn storage_pairs(&self, prefix: usize, hash: Option) -> Result, CallError>; + async fn storage_pairs(&self, prefix: usize, hash: Option) -> Result, Error>; /// Subscription that take `Option>` as input and produces output `Vec`. #[subscription(name = "subscribeStorage", unsub = "unsubscribeStorage", item = Vec)] @@ -47,7 +47,7 @@ pub struct RpcServerImpl; #[async_trait] impl RpcServer for RpcServerImpl { - async fn storage_pairs(&self, _prefix: usize, _hash: Option) -> Result, CallError> { + async fn storage_pairs(&self, _prefix: usize, _hash: Option) -> Result, Error> { Ok(vec![1, 2, 3, 4]) } @@ -61,13 +61,13 @@ async fn main() -> anyhow::Result<()> { env_logger::init(); let server_addr = run_server().await?; - /*let url = format!("ws://{}", server_addr); + let url = format!("ws://{}", server_addr); let client = WsClientBuilder::default().build(&url).await?; assert_eq!(client.storage_pairs(10, None).await.unwrap(), vec![1, 2, 3, 4]); let mut sub = client.subscribe_storage(None).await.unwrap(); - assert_eq!(Some(vec![]), sub.next().await.unwrap());*/ + assert_eq!(Some(vec![]), sub.next().await.unwrap()); Ok(()) } diff --git a/proc-macros/src/lib.rs b/proc-macros/src/lib.rs index 6bf57ef8c9..a710f285d6 100644 --- a/proc-macros/src/lib.rs +++ b/proc-macros/src/lib.rs @@ -198,16 +198,16 @@ mod new; /// /// // RPC is moved into a separate module to clearly show names of generated entities. /// mod rpc_impl { -/// use jsonrpsee::{proc_macros::rpc, types::async_trait, ws_server::SubscriptionSink}; +/// use jsonrpsee::{proc_macros::rpc, types::{async_trait, JsonRpcResult}, ws_server::SubscriptionSink}; /// /// // Generate both server and client implementations, prepend all the methods with `foo_` prefix. /// #[rpc(client, server, namespace = "foo")] /// pub trait Rpc { /// #[method(name = "foo")] -/// async fn async_method(&self, param_a: u8, param_b: String) -> u16; +/// async fn async_method(&self, param_a: u8, param_b: String) -> JsonRpcResult; /// /// #[method(name = "bar")] -/// fn sync_method(&self) -> u16; +/// fn sync_method(&self) -> JsonRpcResult; /// /// #[subscription(name = "sub", unsub = "unsub", item = String)] /// fn sub(&self); @@ -220,12 +220,12 @@ mod new; /// // Note that the trait name we use is `RpcServer`, not `Rpc`! /// #[async_trait] /// impl RpcServer for RpcServerImpl { -/// async fn async_method(&self, _param_a: u8, _param_b: String) -> u16 { -/// 42u16 +/// async fn async_method(&self, _param_a: u8, _param_b: String) -> JsonRpcResult { +/// Ok(42u16) /// } /// -/// fn sync_method(&self) -> u16 { -/// 10u16 +/// fn sync_method(&self) -> JsonRpcResult { +/// Ok(10u16) /// } /// /// // We could've spawned a `tokio` future that yields values while our program works, diff --git a/proc-macros/src/new/render_client.rs b/proc-macros/src/new/render_client.rs index 204f1af322..41ebd0454b 100644 --- a/proc-macros/src/new/render_client.rs +++ b/proc-macros/src/new/render_client.rs @@ -52,7 +52,7 @@ impl RpcDescription { // `returns` represent the return type of the *rust method* (`Result< <..>, jsonrpsee::Error`). let (called_method, returns) = if let Some(returns) = &method.returns { let called_method = quote::format_ident!("request"); - let returns = quote! { Result<#returns> }; + let returns = quote! { #returns }; (called_method, returns) } else { diff --git a/proc-macros/tests/rpc_example.rs b/proc-macros/tests/rpc_example.rs index f2dbdd1859..d9f2c1910f 100644 --- a/proc-macros/tests/rpc_example.rs +++ b/proc-macros/tests/rpc_example.rs @@ -1,15 +1,16 @@ //! Example of using proc macro to generate working client and server. +use jsonrpsee::types::Error; use jsonrpsee_proc_macros::rpc; use std::borrow::Cow; #[rpc(client, server, namespace = "foo")] pub trait Rpc { #[method(name = "foo")] - async fn async_method(&self, param_a: u8, param_b: Option>) -> u16; + async fn async_method(&self, param_a: u8, param_b: Option>) -> Result; #[method(name = "bar")] - fn sync_method(&self) -> u16; + fn sync_method(&self) -> Result; #[subscription(name = "sub", unsub = "unsub", item = String)] fn sub(&self); diff --git a/proc-macros/tests/ui/correct/basic.rs b/proc-macros/tests/ui/correct/basic.rs index f310ece891..2b505b009a 100644 --- a/proc-macros/tests/ui/correct/basic.rs +++ b/proc-macros/tests/ui/correct/basic.rs @@ -2,7 +2,7 @@ use jsonrpsee::{ proc_macros::rpc, - types::async_trait, + types::{async_trait, JsonRpcResult}, ws_client::*, ws_server::{SubscriptionSink, WsServerBuilder}, }; @@ -11,10 +11,10 @@ use std::{net::SocketAddr, sync::mpsc::channel}; #[rpc(client, server, namespace = "foo")] pub trait Rpc { #[method(name = "foo")] - async fn async_method(&self, param_a: u8, param_b: String) -> u16; + async fn async_method(&self, param_a: u8, param_b: String) -> JsonRpcResult; #[method(name = "bar")] - fn sync_method(&self) -> u16; + fn sync_method(&self) -> JsonRpcResult; #[subscription(name = "sub", unsub = "unsub", item = String)] fn sub(&self); @@ -27,12 +27,12 @@ pub struct RpcServerImpl; #[async_trait] impl RpcServer for RpcServerImpl { - async fn async_method(&self, _param_a: u8, _param_b: String) -> u16 { - 42u16 + async fn async_method(&self, _param_a: u8, _param_b: String) -> JsonRpcResult { + Ok(42u16) } - fn sync_method(&self) -> u16 { - 10u16 + fn sync_method(&self) -> JsonRpcResult { + Ok(10u16) } fn sub(&self, mut sink: SubscriptionSink) { diff --git a/proc-macros/tests/ui/correct/only_client.rs b/proc-macros/tests/ui/correct/only_client.rs index c04d87e96c..ee38367ebc 100644 --- a/proc-macros/tests/ui/correct/only_client.rs +++ b/proc-macros/tests/ui/correct/only_client.rs @@ -1,14 +1,14 @@ //! Example of using proc macro to generate working client and server. -use jsonrpsee::proc_macros::rpc; +use jsonrpsee::{proc_macros::rpc, types::JsonRpcResult}; #[rpc(client)] pub trait Rpc { #[method(name = "foo")] - async fn async_method(&self, param_a: u8, param_b: String) -> u16; + async fn async_method(&self, param_a: u8, param_b: String) -> JsonRpcResult; #[method(name = "bar")] - fn sync_method(&self) -> u16; + fn sync_method(&self) -> JsonRpcResult; #[subscription(name = "sub", unsub = "unsub", item = String)] fn sub(&self); diff --git a/proc-macros/tests/ui/correct/only_server.rs b/proc-macros/tests/ui/correct/only_server.rs index 19922bfbe9..db3e96afe6 100644 --- a/proc-macros/tests/ui/correct/only_server.rs +++ b/proc-macros/tests/ui/correct/only_server.rs @@ -1,6 +1,6 @@ use jsonrpsee::{ proc_macros::rpc, - types::async_trait, + types::{async_trait, JsonRpcResult}, ws_server::{SubscriptionSink, WsServerBuilder}, }; use std::{net::SocketAddr, sync::mpsc::channel}; @@ -8,10 +8,10 @@ use std::{net::SocketAddr, sync::mpsc::channel}; #[rpc(server)] pub trait Rpc { #[method(name = "foo")] - async fn async_method(&self, param_a: u8, param_b: String) -> u16; + async fn async_method(&self, param_a: u8, param_b: String) -> JsonRpcResult; #[method(name = "bar")] - fn sync_method(&self) -> u16; + fn sync_method(&self) -> JsonRpcResult; #[subscription(name = "sub", unsub = "unsub", item = String)] fn sub(&self); @@ -21,12 +21,12 @@ pub struct RpcServerImpl; #[async_trait] impl RpcServer for RpcServerImpl { - async fn async_method(&self, _param_a: u8, _param_b: String) -> u16 { - 42u16 + async fn async_method(&self, _param_a: u8, _param_b: String) -> JsonRpcResult { + Ok(42u16) } - fn sync_method(&self) -> u16 { - 10u16 + fn sync_method(&self) -> JsonRpcResult { + Ok(10u16) } fn sub(&self, mut sink: SubscriptionSink) { diff --git a/proc-macros/tests/ui/incorrect/method/method_no_name.rs b/proc-macros/tests/ui/incorrect/method/method_no_name.rs index a3375d2f0d..226f28106d 100644 --- a/proc-macros/tests/ui/incorrect/method/method_no_name.rs +++ b/proc-macros/tests/ui/incorrect/method/method_no_name.rs @@ -4,7 +4,7 @@ use jsonrpsee::proc_macros::rpc; #[rpc(client, server)] pub trait NoMethodName { #[method()] - async fn async_method(&self) -> u8; + async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/method/method_unexpected_field.rs b/proc-macros/tests/ui/incorrect/method/method_unexpected_field.rs index c9b7c2e4d5..39111bff00 100644 --- a/proc-macros/tests/ui/incorrect/method/method_unexpected_field.rs +++ b/proc-macros/tests/ui/incorrect/method/method_unexpected_field.rs @@ -4,7 +4,7 @@ use jsonrpsee::proc_macros::rpc; #[rpc(client, server)] pub trait UnexpectedField { #[method(name = "foo", magic = false)] - async fn async_method(&self) -> u8; + async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/rpc/rpc_assoc_items.rs b/proc-macros/tests/ui/incorrect/rpc/rpc_assoc_items.rs index e84e7819e5..f15f6a2a30 100644 --- a/proc-macros/tests/ui/incorrect/rpc/rpc_assoc_items.rs +++ b/proc-macros/tests/ui/incorrect/rpc/rpc_assoc_items.rs @@ -6,7 +6,7 @@ pub trait AssociatedConst { const WOO: usize; #[method(name = "foo")] - async fn async_method(&self) -> u8; + async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; } #[rpc(client, server)] @@ -14,7 +14,7 @@ pub trait AssociatedType { type Woo; #[method(name = "foo")] - async fn async_method(&self) -> u8; + async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.rs b/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.rs index ac8f457453..1664abb0af 100644 --- a/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.rs +++ b/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.rs @@ -1,13 +1,13 @@ -use jsonrpsee::proc_macros::rpc; +use jsonrpsee::{proc_macros::rpc, types::JsonRpcResult}; // Associated items are forbidden. #[rpc(client, server)] pub trait MethodNameConflict { #[method(name = "foo")] - async fn foo(&self) -> u8; + async fn foo(&self) -> JsonRpcResult; #[method(name = "foo")] - async fn bar(&self) -> u8; + async fn bar(&self) -> JsonRpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.stderr b/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.stderr index 213f6fbacc..0ec9c07dd2 100644 --- a/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.stderr +++ b/proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.stderr @@ -1,5 +1,5 @@ error: "foo" is already defined --> $DIR/rpc_name_conflict.rs:10:11 | -10 | async fn bar(&self) -> u8; +10 | async fn bar(&self) -> JsonRpcResult; | ^^^ diff --git a/proc-macros/tests/ui/incorrect/rpc/rpc_no_impls.rs b/proc-macros/tests/ui/incorrect/rpc/rpc_no_impls.rs index 4e8e98dbb0..5649322fe2 100644 --- a/proc-macros/tests/ui/incorrect/rpc/rpc_no_impls.rs +++ b/proc-macros/tests/ui/incorrect/rpc/rpc_no_impls.rs @@ -4,7 +4,7 @@ use jsonrpsee::proc_macros::rpc; #[rpc()] pub trait NoImpls { #[method(name = "foo")] - async fn async_method(&self) -> u8; + async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.rs b/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.rs index 46d48d5161..92ac92e6b0 100644 --- a/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.rs +++ b/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.rs @@ -3,7 +3,7 @@ use jsonrpsee::proc_macros::rpc; // Method without type marker. #[rpc(client, server)] pub trait NotQualified { - async fn async_method(&self) -> u8; + async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.stderr b/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.stderr index 5f41617512..8fd2826f85 100644 --- a/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.stderr +++ b/proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.stderr @@ -1,5 +1,5 @@ error: Methods must have either 'method' or 'subscription' attribute --> $DIR/rpc_not_qualified.rs:6:2 | -6 | async fn async_method(&self) -> u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 | async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/tests/proc_macros.rs b/tests/tests/proc_macros.rs index d6d500bb17..59dcb3c2a1 100644 --- a/tests/tests/proc_macros.rs +++ b/tests/tests/proc_macros.rs @@ -33,15 +33,19 @@ use jsonrpsee::{ws_client::*, ws_server::WsServerBuilder}; use serde_json::value::RawValue; mod rpc_impl { - use jsonrpsee::{proc_macros::rpc, types::async_trait, ws_server::SubscriptionSink}; + use jsonrpsee::{ + proc_macros::rpc, + types::{async_trait, JsonRpcResult}, + ws_server::SubscriptionSink, + }; #[rpc(client, server, namespace = "foo")] pub trait Rpc { #[method(name = "foo")] - async fn async_method(&self, param_a: u8, param_b: String) -> u16; + async fn async_method(&self, param_a: u8, param_b: String) -> JsonRpcResult; #[method(name = "bar")] - fn sync_method(&self) -> u16; + fn sync_method(&self) -> JsonRpcResult; #[subscription(name = "sub", unsub = "unsub", item = String)] fn sub(&self); @@ -50,13 +54,13 @@ mod rpc_impl { fn sub_with_params(&self, val: u32); #[method(name = "params")] - fn params(&self, a: u8, b: &str) -> String { - format!("Called with: {}, {}", a, b) + fn params(&self, a: u8, b: &str) -> JsonRpcResult { + Ok(format!("Called with: {}, {}", a, b)) } #[method(name = "optional_params")] - fn optional_params(&self, a: u32, b: Option, c: Option) -> String { - format!("Called with: {}, {:?}, {:?}", a, b, c) + fn optional_params(&self, a: u32, b: Option, c: Option) -> JsonRpcResult { + Ok(format!("Called with: {}, {:?}, {:?}", a, b, c)) } #[method(name = "lifetimes")] @@ -66,13 +70,13 @@ mod rpc_impl { b: &'_ str, c: std::borrow::Cow<'_, str>, d: Option>, - ) -> String { - format!("Called with: {}, {}, {}, {:?}", a, b, c, d) + ) -> JsonRpcResult { + Ok(format!("Called with: {}, {}, {}, {:?}", a, b, c, d)) } #[method(name = "zero_copy_cow")] - fn zero_copy_cow(&self, a: std::borrow::Cow<'_, str>, b: beef::Cow<'_, str>) -> String { - format!("Zero copy params: {}, {}", matches!(a, std::borrow::Cow::Borrowed(_)), b.is_borrowed()) + fn zero_copy_cow(&self, a: std::borrow::Cow<'_, str>, b: beef::Cow<'_, str>) -> JsonRpcResult { + Ok(format!("Zero copy params: {}, {}", matches!(a, std::borrow::Cow::Borrowed(_)), b.is_borrowed())) } } @@ -80,12 +84,12 @@ mod rpc_impl { #[async_trait] impl RpcServer for RpcServerImpl { - async fn async_method(&self, _param_a: u8, _param_b: String) -> u16 { - 42u16 + async fn async_method(&self, _param_a: u8, _param_b: String) -> JsonRpcResult { + Ok(42u16) } - fn sync_method(&self) -> u16 { - 10u16 + fn sync_method(&self) -> JsonRpcResult { + Ok(10u16) } fn sub(&self, mut sink: SubscriptionSink) { diff --git a/types/src/lib.rs b/types/src/lib.rs index e54f3e7e47..c9d8a52105 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -38,3 +38,6 @@ pub mod __reexports { pub use serde; pub use serde_json; } + +/// JSON-RPC result. +pub type JsonRpcResult = Result; diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index 06f4b0a2bf..7f7a50c9d4 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -208,7 +208,7 @@ impl RpcModule { where Context: Send + Sync + 'static, R: Serialize, - F: Fn(RpcParams, &Context) -> Result + Send + Sync + 'static, + F: Fn(RpcParams, &Context) -> Result + Send + Sync + 'static, { self.methods.verify_method_name(method_name)?; @@ -218,22 +218,24 @@ impl RpcModule { method_name, MethodCallback::Sync(Arc::new(move |id, params, tx, _| { match callback(params, &*ctx) { - Ok(res) => send_response(id, tx, res), - Err(CallError::InvalidParams) => send_error(id, tx, JsonRpcErrorCode::InvalidParams.into()), - Err(CallError::Failed(e)) => { + Ok(res) => send_response(id, &tx, res), + Err(Error::Call(CallError::InvalidParams)) => { + send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()) + } + Err(Error::Call(CallError::Failed(e))) => { let err = JsonRpcErrorObject { code: JsonRpcErrorCode::ServerError(CALL_EXECUTION_FAILED_CODE), message: &e.to_string(), data: None, }; - send_error(id, tx, err) + send_error(id, &tx, err) } - Err(CallError::Custom { code, message, data }) => { + Err(Error::Call(CallError::Custom { code, message, data })) => { let err = JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; - send_error(id, tx, err) + send_error(id, &tx, err) } + _ => unreachable!(), }; - Ok(()) })), ); @@ -245,11 +247,7 @@ impl RpcModule { pub fn register_async_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> where R: Serialize + Send + Sync + 'static, - F: Fn(RpcParams<'static>, Arc) -> BoxFuture<'static, Result> - + Copy - + Send - + Sync - + 'static, + F: Fn(RpcParams<'static>, Arc) -> BoxFuture<'static, Result> + Copy + Send + Sync + 'static, { self.methods.verify_method_name(method_name)?; @@ -262,8 +260,10 @@ impl RpcModule { let future = async move { match callback(params, ctx).await { Ok(res) => send_response(id, &tx, res), - Err(CallError::InvalidParams) => send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()), - Err(CallError::Failed(e)) => { + Err(Error::Call(CallError::InvalidParams)) => { + send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()) + } + Err(Error::Call(CallError::Failed(e))) => { let err = JsonRpcErrorObject { code: JsonRpcErrorCode::ServerError(CALL_EXECUTION_FAILED_CODE), message: &e.to_string(), @@ -271,11 +271,12 @@ impl RpcModule { }; send_error(id, &tx, err) } - Err(CallError::Custom { code, message, data }) => { + Err(Error::Call(CallError::Custom { code, message, data })) => { let err = JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; send_error(id, &tx, err) } + _ => unreachable!(), }; Ok(()) }; diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index eb23c97cd0..176c849cd9 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -95,8 +95,10 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { .boxed() }) .unwrap(); - module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams)).unwrap(); - module.register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(Box::new(MyAppError)))).unwrap(); + module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams.into())).unwrap(); + module + .register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(Box::new(MyAppError)).into())) + .unwrap(); module .register_method("sleep_for", |params, _| { let sleep: Vec = params.parse()?; @@ -149,7 +151,7 @@ async fn server_with_context() -> SocketAddr { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; // Async work that returns an error - futures_util::future::err::<(), CallError>(CallError::Failed(String::from("nah").into())).await + futures_util::future::err::<(), Error>(CallError::Failed(String::from("nah").into()).into()).await } .boxed() }) From 08c45d516c2bf1a4ac17f82855adf027b89000e7 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 13 Aug 2021 16:00:37 +0200 Subject: [PATCH 03/15] send unknown message when error is not CallError --- types/src/v2/error.rs | 2 ++ utils/src/server/rpc_module.rs | 24 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/types/src/v2/error.rs b/types/src/v2/error.rs index ed48f9b2c5..cdee6fbdc4 100644 --- a/types/src/v2/error.rs +++ b/types/src/v2/error.rs @@ -66,6 +66,8 @@ pub const INVALID_REQUEST_CODE: i32 = -32600; pub const METHOD_NOT_FOUND_CODE: i32 = -32601; /// Custom server error when a call failed. pub const CALL_EXECUTION_FAILED_CODE: i32 = -32000; +/// Unknown error. +pub const UNKNOWN_ERROR_CODE: i32 = -32001; /// Parse error message pub const PARSE_ERROR_MSG: &str = "Parse error"; diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index 7f7a50c9d4..8190f64abf 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -3,7 +3,9 @@ use beef::Cow; use futures_channel::{mpsc, oneshot}; use futures_util::{future::BoxFuture, FutureExt, StreamExt}; use jsonrpsee_types::error::{CallError, Error, SubscriptionClosedError}; -use jsonrpsee_types::v2::error::{JsonRpcErrorCode, JsonRpcErrorObject, CALL_EXECUTION_FAILED_CODE}; +use jsonrpsee_types::v2::error::{ + JsonRpcErrorCode, JsonRpcErrorObject, CALL_EXECUTION_FAILED_CODE, UNKNOWN_ERROR_CODE, +}; use jsonrpsee_types::v2::params::{ Id, JsonRpcSubscriptionParams, RpcParams, SubscriptionId as JsonRpcSubscriptionId, TwoPointZero, }; @@ -234,7 +236,15 @@ impl RpcModule { let err = JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; send_error(id, &tx, err) } - _ => unreachable!(), + // This should normally not happen. + Err(e) => { + let err = JsonRpcErrorObject { + code: JsonRpcErrorCode::ServerError(UNKNOWN_ERROR_CODE), + message: &e.to_string(), + data: None, + }; + send_error(id, &tx, err) + } }; Ok(()) })), @@ -276,7 +286,15 @@ impl RpcModule { JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; send_error(id, &tx, err) } - _ => unreachable!(), + // This should normally not happen. + Err(e) => { + let err = JsonRpcErrorObject { + code: JsonRpcErrorCode::ServerError(UNKNOWN_ERROR_CODE), + message: &e.to_string(), + data: None, + }; + send_error(id, &tx, err) + } }; Ok(()) }; From 394a06b61f19c64beeb657db81ccc84b074e9e38 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 13 Aug 2021 16:15:40 +0200 Subject: [PATCH 04/15] show example that auto cast StdError doesn't work --- types/src/error.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/types/src/error.rs b/types/src/error.rs index 0dc9a6c259..5e17983440 100644 --- a/types/src/error.rs +++ b/types/src/error.rs @@ -38,6 +38,18 @@ pub enum CallError { }, } +// TODO(niklasad1): doesn't work probably conflicting with `thiserror::Error` +/* +impl From for Error +where + E: std::error::Error + Send + Sync + 'static, +{ + fn from(err: E) -> Self { + Error::Call(CallError::Failed(Box::new(err))) + } +} +*/ + /// Error type. #[derive(Debug, thiserror::Error)] pub enum Error { From 33b4fa28730b72647ba150659d3c0ab1937e524a Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Sat, 14 Aug 2021 21:52:51 +0200 Subject: [PATCH 05/15] register_*_method Into --- benches/helpers.rs | 9 ++++---- examples/http.rs | 3 ++- examples/proc_macro.rs | 2 +- examples/ws.rs | 4 ++-- http-server/src/tests.rs | 24 +++++++++---------- tests/tests/helpers.rs | 9 ++++---- utils/src/server/rpc_module.rs | 20 ++++++++-------- ws-server/src/tests.rs | 42 ++++++++++++++++------------------ 8 files changed, 58 insertions(+), 55 deletions(-) diff --git a/benches/helpers.rs b/benches/helpers.rs index e8dc250b3a..adc38200de 100644 --- a/benches/helpers.rs +++ b/benches/helpers.rs @@ -2,6 +2,7 @@ use futures_channel::oneshot; use futures_util::future::FutureExt; use jsonrpsee::{ http_server::HttpServerBuilder, + types::Error, ws_server::{RpcModule, WsServerBuilder}, }; @@ -17,8 +18,8 @@ pub async fn http_server() -> String { let server = HttpServerBuilder::default().max_request_body_size(u32::MAX).build("127.0.0.1:0".parse().unwrap()).unwrap(); let mut module = RpcModule::new(()); - module.register_method(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); - module.register_async_method(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); + module.register_method::<_, _, Error>(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); + module.register_async_method::<_, _, Error>(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); server_started_tx.send(server.local_addr().unwrap()).unwrap(); server.start(module).await }); @@ -31,8 +32,8 @@ pub async fn ws_server() -> String { tokio::spawn(async move { let server = WsServerBuilder::default().build("127.0.0.1:0").await.unwrap(); let mut module = RpcModule::new(()); - module.register_method(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); - module.register_async_method(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); + module.register_method::<_, _, Error>(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); + module.register_async_method::<_, _, Error>(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); module .register_subscription(SUB_METHOD_NAME, UNSUB_METHOD_NAME, |_params, mut sink, _ctx| { let x = "Hello"; diff --git a/examples/http.rs b/examples/http.rs index 7027fde5ee..cf13bb1db4 100644 --- a/examples/http.rs +++ b/examples/http.rs @@ -27,6 +27,7 @@ use jsonrpsee::{ http_client::HttpClientBuilder, http_server::{HttpServerBuilder, RpcModule}, + types::Error, types::{traits::Client, JsonValue}, }; use std::net::SocketAddr; @@ -50,7 +51,7 @@ async fn main() -> anyhow::Result<()> { async fn run_server() -> anyhow::Result { let server = HttpServerBuilder::default().build("127.0.0.1:0".parse()?)?; let mut module = RpcModule::new(()); - module.register_method("say_hello", |_, _| Ok("lo"))?; + module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo"))?; let addr = server.local_addr()?; tokio::spawn(server.start(module)); diff --git a/examples/proc_macro.rs b/examples/proc_macro.rs index b9f1706d01..3b47e58ad5 100644 --- a/examples/proc_macro.rs +++ b/examples/proc_macro.rs @@ -75,7 +75,7 @@ async fn main() -> anyhow::Result<()> { async fn run_server() -> anyhow::Result { let server = WsServerBuilder::default().build("127.0.0.1:0").await?; let mut module = RpcModule::new(()); - module.register_method("state_getPairs", |_, _| Ok(vec![1, 2, 3]))?; + module.register_method::<_, _, Error>("state_getPairs", |_, _| Ok(vec![1, 2, 3]))?; let addr = server.local_addr()?; tokio::spawn(async move { server.start(RpcServerImpl.into_rpc()).await }); diff --git a/examples/ws.rs b/examples/ws.rs index 66ce250db1..7a170cd9cc 100644 --- a/examples/ws.rs +++ b/examples/ws.rs @@ -25,7 +25,7 @@ // DEALINGS IN THE SOFTWARE. use jsonrpsee::{ - types::{traits::Client, v2::params::JsonRpcParams}, + types::{traits::Client, v2::params::JsonRpcParams, Error}, ws_client::WsClientBuilder, ws_server::{RpcModule, WsServerBuilder}, }; @@ -47,7 +47,7 @@ async fn main() -> anyhow::Result<()> { async fn run_server() -> anyhow::Result { let server = WsServerBuilder::default().build("127.0.0.1:0").await?; let mut module = RpcModule::new(()); - module.register_method("say_hello", |_, _| Ok("lo"))?; + module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo"))?; let addr = server.local_addr()?; tokio::spawn(server.start(module)); Ok(addr) diff --git a/http-server/src/tests.rs b/http-server/src/tests.rs index 3d88873e22..84ce58587d 100644 --- a/http-server/src/tests.rs +++ b/http-server/src/tests.rs @@ -47,38 +47,38 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle>, St let ctx = TestContext; let mut module = RpcModule::new(ctx); let addr = server.local_addr().unwrap(); - module.register_method("say_hello", |_, _| Ok("lo")).unwrap(); - module.register_async_method("say_hello_async", |_, _| async move { Ok("lo") }.boxed()).unwrap(); + module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo")).unwrap(); + module.register_async_method::<_, _, Error>("say_hello_async", |_, _| async move { Ok("lo") }.boxed()).unwrap(); module - .register_method("add", |params, _| { + .register_method::<_, _, Error>("add", |params, _| { let params: Vec = params.parse()?; let sum: u64 = params.into_iter().sum(); Ok(sum) }) .unwrap(); module - .register_method("multiparam", |params, _| { + .register_method::<_, _, Error>("multiparam", |params, _| { let params: (String, String, Vec) = params.parse()?; let r = format!("string1={}, string2={}, vec={}", params.0.len(), params.1.len(), params.2.len()); Ok(r) }) .unwrap(); - module.register_method("notif", |_, _| Ok("")).unwrap(); + module.register_method::<_, _, Error>("notif", |_, _| Ok("")).unwrap(); module - .register_method("should_err", |_, ctx| { + .register_method::<_, _, Error>("should_err", |_, ctx| { let _ = ctx.err().map_err(|e| CallError::Failed(e.into()))?; Ok("err") }) .unwrap(); module - .register_method("should_ok", |_, ctx| { + .register_method::<_, _, Error>("should_ok", |_, ctx| { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; Ok("ok") }) .unwrap(); module - .register_async_method("should_ok_async", |_p, ctx| { + .register_async_method::<_, _, Error>("should_ok_async", |_p, ctx| { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; Ok("ok") @@ -369,12 +369,12 @@ async fn can_register_modules() { let mut mod2 = RpcModule::new(cx2); assert_eq!(mod1.method_names().count(), 0); - mod1.register_method("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod1.register_method("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod2.register_method("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod1.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod1.register_method::<_, _, Error>("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod2.register_method::<_, _, Error>("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); // Won't register, name clashes - mod2.register_method("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod2.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); assert_eq!(mod1.method_names().count(), 2); diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index c92243d4d3..3ed344bdde 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -27,6 +27,7 @@ use futures_channel::oneshot; use jsonrpsee::{ http_server::HttpServerBuilder, + types::Error, ws_server::{WsServerBuilder, WsStopHandle}, RpcModule, }; @@ -42,7 +43,7 @@ pub async fn websocket_server_with_subscription() -> (SocketAddr, WsStopHandle) let server = rt.block_on(WsServerBuilder::default().build("127.0.0.1:0")).unwrap(); let mut module = RpcModule::new(()); - module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); + module.register_method::<_, _, Error>("say_hello", |_, _| Ok("hello")).unwrap(); module .register_subscription("subscribe_hello", "unsubscribe_hello", |_, mut sink, _| { @@ -102,7 +103,7 @@ pub async fn websocket_server() -> SocketAddr { let rt = tokio::runtime::Runtime::new().unwrap(); let server = rt.block_on(WsServerBuilder::default().build("127.0.0.1:0")).unwrap(); let mut module = RpcModule::new(()); - module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); + module.register_method::<_, _, Error>("say_hello", |_, _| Ok("hello")).unwrap(); rt.block_on(async move { server_started_tx.send(server.local_addr().unwrap()).unwrap(); @@ -118,8 +119,8 @@ pub async fn http_server() -> SocketAddr { let server = HttpServerBuilder::default().build("127.0.0.1:0".parse().unwrap()).unwrap(); let mut module = RpcModule::new(()); let addr = server.local_addr().unwrap(); - module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); - module.register_method("notif", |_, _| Ok("")).unwrap(); + module.register_method::<_, _, Error>("say_hello", |_, _| Ok("hello")).unwrap(); + module.register_method::<_, _, Error>("notif", |_, _| Ok("")).unwrap(); tokio::spawn(server.start(module)); addr diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index 8190f64abf..e0cd18fa94 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -206,11 +206,12 @@ impl From> for Methods { impl RpcModule { /// Register a new synchronous RPC method, which computes the response with the given callback. - pub fn register_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> + pub fn register_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> where Context: Send + Sync + 'static, R: Serialize, - F: Fn(RpcParams, &Context) -> Result + Send + Sync + 'static, + F: Fn(RpcParams, &Context) -> Result + Send + Sync + 'static, + E: Into, { self.methods.verify_method_name(method_name)?; @@ -219,7 +220,7 @@ impl RpcModule { self.methods.mut_callbacks().insert( method_name, MethodCallback::Sync(Arc::new(move |id, params, tx, _| { - match callback(params, &*ctx) { + match callback(params, &*ctx).map_err(Into::into) { Ok(res) => send_response(id, &tx, res), Err(Error::Call(CallError::InvalidParams)) => { send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()) @@ -254,10 +255,11 @@ impl RpcModule { } /// Register a new asynchronous RPC method, which computes the response with the given callback. - pub fn register_async_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> + pub fn register_async_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> where R: Serialize + Send + Sync + 'static, - F: Fn(RpcParams<'static>, Arc) -> BoxFuture<'static, Result> + Copy + Send + Sync + 'static, + F: Fn(RpcParams<'static>, Arc) -> BoxFuture<'static, Result> + Copy + Send + Sync + 'static, + E: Into, { self.methods.verify_method_name(method_name)?; @@ -268,7 +270,7 @@ impl RpcModule { MethodCallback::Async(Arc::new(move |id, params, tx, _| { let ctx = ctx.clone(); let future = async move { - match callback(params, ctx).await { + match callback(params, ctx).await.map_err(Into::into) { Ok(res) => send_response(id, &tx, res), Err(Error::Call(CallError::InvalidParams)) => { send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()) @@ -490,9 +492,9 @@ mod tests { fn rpc_modules_with_different_contexts_can_be_merged() { let cx = Vec::::new(); let mut mod1 = RpcModule::new(cx); - mod1.register_method("bla with Vec context", |_: RpcParams, _| Ok(())).unwrap(); + mod1.register_method::<_, _, Error>("bla with Vec context", |_: RpcParams, _| Ok(())).unwrap(); let mut mod2 = RpcModule::new(String::new()); - mod2.register_method("bla with String context", |_: RpcParams, _| Ok(())).unwrap(); + mod2.register_method::<_, _, Error>("bla with String context", |_: RpcParams, _| Ok(())).unwrap(); mod1.merge(mod2).unwrap(); @@ -514,7 +516,7 @@ mod tests { fn rpc_register_alias() { let mut module = RpcModule::new(()); - module.register_method("hello_world", |_: RpcParams, _| Ok(())).unwrap(); + module.register_method::<_, _, Error>("hello_world", |_: RpcParams, _| Ok(())).unwrap(); module.register_alias("hello_foobar", "hello_world").unwrap(); assert!(module.method("hello_world").is_some()); diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index 176c849cd9..662705ff00 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -62,20 +62,20 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { let server = WsServerBuilder::default().build("127.0.0.1:0").with_default_timeout().await.unwrap().unwrap(); let mut module = RpcModule::new(()); module - .register_method("say_hello", |_, _| { + .register_method::<_, _, Error>("say_hello", |_, _| { log::debug!("server respond to hello"); Ok("hello") }) .unwrap(); module - .register_method("add", |params, _| { + .register_method::<_, _, Error>("add", |params, _| { let params: Vec = params.parse()?; let sum: u64 = params.into_iter().sum(); Ok(sum) }) .unwrap(); module - .register_async_method("say_hello_async", |_, _| { + .register_async_method::<_, _, Error>("say_hello_async", |_, _| { async move { log::debug!("server respond to hello"); // Call some async function inside. @@ -86,7 +86,7 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { }) .unwrap(); module - .register_async_method("add_async", |params, _| { + .register_async_method::<_, _, Error>("add_async", |params, _| { async move { let params: Vec = params.parse()?; let sum: u64 = params.into_iter().sum(); @@ -95,12 +95,10 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { .boxed() }) .unwrap(); - module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams.into())).unwrap(); + module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams)).unwrap(); + module.register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(Box::new(MyAppError)))).unwrap(); module - .register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(Box::new(MyAppError)).into())) - .unwrap(); - module - .register_method("sleep_for", |params, _| { + .register_method::<_, _, Error>("sleep_for", |params, _| { let sleep: Vec = params.parse()?; std::thread::sleep(std::time::Duration::from_millis(sleep[0])); Ok("Yawn!") @@ -122,21 +120,21 @@ async fn server_with_context() -> SocketAddr { let mut rpc_module = RpcModule::new(ctx); rpc_module - .register_method("should_err", |_p, ctx| { + .register_method::<_, _, Error>("should_err", |_p, ctx| { let _ = ctx.err().map_err(|e| CallError::Failed(e.into()))?; Ok("err") }) .unwrap(); rpc_module - .register_method("should_ok", |_p, ctx| { + .register_method::<_, _, Error>("should_ok", |_p, ctx| { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; Ok("ok") }) .unwrap(); rpc_module - .register_async_method("should_ok_async", |_p, ctx| { + .register_async_method::<_, _, Error>("should_ok_async", |_p, ctx| { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; // Call some async function inside. @@ -151,7 +149,7 @@ async fn server_with_context() -> SocketAddr { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; // Async work that returns an error - futures_util::future::err::<(), Error>(CallError::Failed(String::from("nah").into()).into()).await + futures_util::future::err::<(), _>(CallError::Failed(String::from("nah").into())).await } .boxed() }) @@ -169,7 +167,7 @@ async fn can_set_the_max_request_body_size() { // Rejects all requests larger than 10 bytes let server = WsServerBuilder::default().max_request_body_size(10).build(addr).await.unwrap(); let mut module = RpcModule::new(()); - module.register_method("anything", |_p, _cx| Ok(())).unwrap(); + module.register_method::<_, _, Error>("anything", |_p, _cx| Ok(())).unwrap(); let addr = server.local_addr().unwrap(); tokio::spawn(server.start(module)); @@ -192,7 +190,7 @@ async fn can_set_max_connections() { // Server that accepts max 2 connections let server = WsServerBuilder::default().max_connections(2).build(addr).await.unwrap(); let mut module = RpcModule::new(()); - module.register_method("anything", |_p, _cx| Ok(())).unwrap(); + module.register_method::<_, _, Error>("anything", |_p, _cx| Ok(())).unwrap(); let addr = server.local_addr().unwrap(); tokio::spawn(server.start(module)); @@ -453,12 +451,12 @@ async fn invalid_request_object() { #[tokio::test] async fn register_methods_works() { let mut module = RpcModule::new(()); - assert!(module.register_method("say_hello", |_, _| Ok("lo")).is_ok()); - assert!(module.register_method("say_hello", |_, _| Ok("lo")).is_err()); + assert!(module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo")).is_ok()); + assert!(module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo")).is_err()); assert!(module.register_subscription("subscribe_hello", "unsubscribe_hello", |_, _, _| Ok(())).is_ok()); assert!(module.register_subscription("subscribe_hello_again", "unsubscribe_hello", |_, _, _| Ok(())).is_err()); assert!( - module.register_method("subscribe_hello_again", |_, _| Ok("lo")).is_ok(), + module.register_method::<_, _, Error>("subscribe_hello_again", |_, _| Ok("lo")).is_ok(), "Failed register_subscription should not have side-effects" ); } @@ -529,12 +527,12 @@ async fn can_register_modules() { assert_eq!(mod1.method_names().count(), 0); assert_eq!(mod2.method_names().count(), 0); - mod1.register_method("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod1.register_method("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod2.register_method("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod1.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod1.register_method::<_, _, Error>("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod2.register_method::<_, _, Error>("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); // Won't register, name clashes - mod2.register_method("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod2.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); assert_eq!(mod1.method_names().count(), 2); let err = mod1.merge(mod2).unwrap_err(); From 07029a909a3bc960d884b95d40561ed5be97a7c8 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 16 Aug 2021 12:14:47 +0200 Subject: [PATCH 06/15] clippy --- utils/src/server/helpers.rs | 2 +- utils/src/server/rpc_module.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/src/server/helpers.rs b/utils/src/server/helpers.rs index 022e5061d4..75309c352f 100644 --- a/utils/src/server/helpers.rs +++ b/utils/src/server/helpers.rs @@ -42,7 +42,7 @@ pub fn send_error(id: Id, tx: &MethodSink, error: JsonRpcErrorObject) { /// Figure out if this is a sufficiently complete request that we can extract an [`Id`] out of, or just plain /// unparseable garbage. pub fn prepare_error(data: &[u8]) -> (Id<'_>, JsonRpcErrorCode) { - match serde_json::from_slice::(&data) { + match serde_json::from_slice::(data) { Ok(JsonRpcInvalidRequest { id }) => (id, JsonRpcErrorCode::InvalidRequest), Err(_) => (Id::Null, JsonRpcErrorCode::ParseError), } diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index e0cd18fa94..a0f9becbaa 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -221,9 +221,9 @@ impl RpcModule { method_name, MethodCallback::Sync(Arc::new(move |id, params, tx, _| { match callback(params, &*ctx).map_err(Into::into) { - Ok(res) => send_response(id, &tx, res), + Ok(res) => send_response(id, tx, res), Err(Error::Call(CallError::InvalidParams)) => { - send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()) + send_error(id, tx, JsonRpcErrorCode::InvalidParams.into()) } Err(Error::Call(CallError::Failed(e))) => { let err = JsonRpcErrorObject { @@ -231,11 +231,11 @@ impl RpcModule { message: &e.to_string(), data: None, }; - send_error(id, &tx, err) + send_error(id, tx, err) } Err(Error::Call(CallError::Custom { code, message, data })) => { let err = JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; - send_error(id, &tx, err) + send_error(id, tx, err) } // This should normally not happen. Err(e) => { @@ -244,7 +244,7 @@ impl RpcModule { message: &e.to_string(), data: None, }; - send_error(id, &tx, err) + send_error(id, tx, err) } }; Ok(()) From 5cc7fea52dcf7a91a9a35308693956118c98968e Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 16 Aug 2021 13:10:49 +0200 Subject: [PATCH 07/15] replace generic errors with anyhow::Error --- http-client/src/client.rs | 8 ++++---- types/Cargo.toml | 1 + types/src/client.rs | 2 +- types/src/error.rs | 26 +++++++++++--------------- ws-client/src/client.rs | 10 +++++----- ws-server/Cargo.toml | 1 + ws-server/src/tests.rs | 4 ++-- 7 files changed, 25 insertions(+), 27 deletions(-) diff --git a/http-client/src/client.rs b/http-client/src/client.rs index 42bcf671b2..9e113ed28f 100644 --- a/http-client/src/client.rs +++ b/http-client/src/client.rs @@ -64,7 +64,7 @@ impl HttpClientBuilder { /// Build the HTTP client with target to connect to. pub fn build(self, target: impl AsRef) -> Result { let transport = - HttpTransportClient::new(target, self.max_request_body_size).map_err(|e| Error::Transport(Box::new(e)))?; + HttpTransportClient::new(target, self.max_request_body_size).map_err(|e| Error::Transport(e.into()))?; Ok(HttpClient { transport, request_id: AtomicU64::new(0), request_timeout: self.request_timeout }) } } @@ -94,7 +94,7 @@ impl Client for HttpClient { match tokio::time::timeout(self.request_timeout, fut).await { Ok(Ok(ok)) => Ok(ok), Err(_) => Err(Error::RequestTimeout), - Ok(Err(e)) => Err(Error::Transport(Box::new(e))), + Ok(Err(e)) => Err(Error::Transport(e.into())), } } @@ -111,7 +111,7 @@ impl Client for HttpClient { let body = match tokio::time::timeout(self.request_timeout, fut).await { Ok(Ok(body)) => body, Err(_e) => return Err(Error::RequestTimeout), - Ok(Err(e)) => return Err(Error::Transport(Box::new(e))), + Ok(Err(e)) => return Err(Error::Transport(e.into())), }; let response: JsonRpcResponse<_> = match serde_json::from_slice(&body) { @@ -152,7 +152,7 @@ impl Client for HttpClient { let body = match tokio::time::timeout(self.request_timeout, fut).await { Ok(Ok(body)) => body, Err(_e) => return Err(Error::RequestTimeout), - Ok(Err(e)) => return Err(Error::Transport(Box::new(e))), + Ok(Err(e)) => return Err(Error::Transport(e.into())), }; let rps: Vec> = match serde_json::from_slice(&body) { diff --git a/types/Cargo.toml b/types/Cargo.toml index 86b4aa666b..cd18e52861 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -11,6 +11,7 @@ documentation = "https://docs.rs/jsonrpsee-types" [dependencies] async-trait = "0.1" +anyhow = "1" beef = { version = "0.5.1", features = ["impl_serde"] } futures-channel = { version = "0.3.14", features = ["sink"] } futures-util = { version = "0.3.14", default-features = false, features = ["std", "sink", "channel"] } diff --git a/types/src/client.rs b/types/src/client.rs index 5793d83357..d28e74a855 100644 --- a/types/src/client.rs +++ b/types/src/client.rs @@ -136,7 +136,7 @@ where Some(n) => match serde_json::from_value::>(n) { Ok(NotifResponse::Ok(parsed)) => Ok(Some(parsed)), Ok(NotifResponse::Err(e)) => Err(Error::SubscriptionClosed(e)), - Err(e) => Err(e.into()), + Err(e) => Err(Error::ParseError(e)), }, None => Ok(None), } diff --git a/types/src/error.rs b/types/src/error.rs index 24cadf0bb1..84d696f3e8 100644 --- a/types/src/error.rs +++ b/types/src/error.rs @@ -25,7 +25,7 @@ pub enum CallError { InvalidParams, /// The call failed (let jsonrpsee assign default error code and error message). #[error("RPC Call failed: {0}")] - Failed(Box), + Failed(anyhow::Error), /// Custom error with specific JSON-RPC error code, message and data. #[error("RPC Call failed: code: {code}, message: {message}, data: {data:?}")] Custom { @@ -38,17 +38,13 @@ pub enum CallError { }, } -// TODO(niklasad1): doesn't work probably conflicting with `thiserror::Error` -/* -impl From for Error -where - E: std::error::Error + Send + Sync + 'static, -{ - fn from(err: E) -> Self { - Error::Call(CallError::Failed(Box::new(err))) +// NOTE(niklasad1): this `From` impl is a bit opinionated to regard all generic errors as `CallError`. +// The most common use case is when register method calls on the servers. +impl From for Error { + fn from(err: anyhow::Error) -> Self { + Error::Call(CallError::Failed(err.into())) } } -*/ /// Error type. #[derive(Debug, thiserror::Error)] @@ -58,7 +54,7 @@ pub enum Error { Call(#[from] CallError), /// Networking error or error on the low-level protocol layer. #[error("Networking or low-level protocol error: {0}")] - Transport(#[source] Box), + Transport(#[source] anyhow::Error), /// JSON-RPC request error. #[error("JSON-RPC request error: {0:?}")] Request(String), @@ -145,24 +141,24 @@ pub enum GenericTransportError { impl From for Error { fn from(io_err: std::io::Error) -> Error { - Error::Transport(Box::new(io_err)) + Error::Transport(io_err.into()) } } impl From for Error { fn from(handshake_err: soketto::handshake::Error) -> Error { - Error::Transport(Box::new(handshake_err)) + Error::Transport(handshake_err.into()) } } impl From for Error { fn from(conn_err: soketto::connection::Error) -> Error { - Error::Transport(Box::new(conn_err)) + Error::Transport(conn_err.into()) } } impl From for Error { fn from(hyper_err: hyper::Error) -> Error { - Error::Transport(Box::new(hyper_err)) + Error::Transport(hyper_err.into()) } } diff --git a/ws-client/src/client.rs b/ws-client/src/client.rs index 6b3072868c..eef86bb413 100644 --- a/ws-client/src/client.rs +++ b/ws-client/src/client.rs @@ -268,13 +268,13 @@ impl<'a> WsClientBuilder<'a> { let builder = WsTransportClientBuilder { certificate_store, - target: Target::parse(url).map_err(|e| Error::Transport(Box::new(e)))?, + target: Target::parse(url).map_err(|e| Error::Transport(e.into()))?, timeout: self.connection_timeout, origin_header: self.origin_header, max_request_body_size: self.max_request_body_size, }; - let (sender, receiver) = builder.build().await.map_err(|e| Error::Transport(Box::new(e)))?; + let (sender, receiver) = builder.build().await.map_err(|e| Error::Transport(e.into()))?; tokio::spawn(async move { background_task(sender, receiver, from_front, err_tx, max_capacity_per_subscription).await; @@ -562,7 +562,7 @@ async fn background_task( .expect("ID unused checked above; qed"), Err(e) => { log::warn!("[backend]: client request failed: {:?}", e); - let _ = request.send_back.map(|s| s.send(Err(Error::Transport(Box::new(e))))); + let _ = request.send_back.map(|s| s.send(Err(Error::Transport(e.into())))); } } } @@ -579,7 +579,7 @@ async fn background_task( .expect("Request ID unused checked above; qed"), Err(e) => { log::warn!("[backend]: client subscription failed: {:?}", e); - let _ = sub.send_back.send(Err(Error::Transport(Box::new(e)))); + let _ = sub.send_back.send(Err(Error::Transport(e.into()))); } }, // User dropped a subscription. @@ -669,7 +669,7 @@ async fn background_task( } Either::Right((Some(Err(e)), _)) => { log::error!("Error: {:?} terminating client", e); - let _ = front_error.send(Error::Transport(Box::new(e))); + let _ = front_error.send(Error::Transport(e.into())); return; } Either::Right((None, _)) => { diff --git a/ws-server/Cargo.toml b/ws-server/Cargo.toml index 4b0f73aa0a..394860299a 100644 --- a/ws-server/Cargo.toml +++ b/ws-server/Cargo.toml @@ -25,6 +25,7 @@ tokio-stream = { version = "0.1.1", features = ["net"] } tokio-util = { version = "0.6", features = ["compat"] } [dev-dependencies] +anyhow = "1" env_logger = "0.9" jsonrpsee-test-utils = { path = "../test-utils" } jsonrpsee-ws-client = { path = "../ws-client" } diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index 662705ff00..7249e45d5c 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -96,7 +96,7 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { }) .unwrap(); module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams)).unwrap(); - module.register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(Box::new(MyAppError)))).unwrap(); + module.register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(MyAppError.into()))).unwrap(); module .register_method::<_, _, Error>("sleep_for", |params, _| { let sleep: Vec = params.parse()?; @@ -149,7 +149,7 @@ async fn server_with_context() -> SocketAddr { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; // Async work that returns an error - futures_util::future::err::<(), _>(CallError::Failed(String::from("nah").into())).await + futures_util::future::err::<(), _>(CallError::Failed(anyhow::anyhow!("nah"))).await } .boxed() }) From 58db4afebffb3210f3d36de51f38d3c58a2ffb71 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 16 Aug 2021 13:33:31 +0200 Subject: [PATCH 08/15] fix nits --- types/src/error.rs | 2 +- ws-server/src/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/src/error.rs b/types/src/error.rs index 84d696f3e8..617794065b 100644 --- a/types/src/error.rs +++ b/types/src/error.rs @@ -42,7 +42,7 @@ pub enum CallError { // The most common use case is when register method calls on the servers. impl From for Error { fn from(err: anyhow::Error) -> Self { - Error::Call(CallError::Failed(err.into())) + Error::Call(CallError::Failed(err)) } } diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index 7249e45d5c..60c345fc50 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -96,7 +96,7 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { }) .unwrap(); module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams)).unwrap(); - module.register_method("call_fail", |_params, _| Err::<(), _>(CallError::Failed(MyAppError.into()))).unwrap(); + module.register_method("call_fail", |_params, _| Err::<(), Error>(anyhow::Error::new(MyAppError).into())).unwrap(); module .register_method::<_, _, Error>("sleep_for", |params, _| { let sleep: Vec = params.parse()?; From f73cef4061fd2b3af0b0e2b8dd3ca2338d712e80 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 16 Aug 2021 13:37:24 +0200 Subject: [PATCH 09/15] example that anyhow::Error in register_method works --- ws-server/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index 60c345fc50..0fbef644dd 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -96,7 +96,7 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { }) .unwrap(); module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams)).unwrap(); - module.register_method("call_fail", |_params, _| Err::<(), Error>(anyhow::Error::new(MyAppError).into())).unwrap(); + module.register_method("call_fail", |_params, _| Err::<(), _>(anyhow::Error::new(MyAppError))).unwrap(); module .register_method::<_, _, Error>("sleep_for", |params, _| { let sleep: Vec = params.parse()?; From a97ccd936dfd23372d24b6c84b000d3f76bf2434 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 16 Aug 2021 15:42:40 +0200 Subject: [PATCH 10/15] CallError: add missing From impl --- types/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/src/error.rs b/types/src/error.rs index 617794065b..03e6a3a3d2 100644 --- a/types/src/error.rs +++ b/types/src/error.rs @@ -25,7 +25,7 @@ pub enum CallError { InvalidParams, /// The call failed (let jsonrpsee assign default error code and error message). #[error("RPC Call failed: {0}")] - Failed(anyhow::Error), + Failed(#[from] anyhow::Error), /// Custom error with specific JSON-RPC error code, message and data. #[error("RPC Call failed: code: {code}, message: {message}, data: {data:?}")] Custom { From 6f9ef0c92db83fea219655943430bfa13e72b0b0 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 17 Aug 2021 11:37:47 +0200 Subject: [PATCH 11/15] [types]: add helper methods for Error types The rationale is to make it possible for users to either use anyhow::Error or use the helper methods. --- types/src/error.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/types/src/error.rs b/types/src/error.rs index 03e6a3a3d2..d9166d05b4 100644 --- a/types/src/error.rs +++ b/types/src/error.rs @@ -38,8 +38,18 @@ pub enum CallError { }, } +impl CallError { + /// Create `CallError` from a generic error. + pub fn from_std_error(err: E) -> Self + where E: std::error::Error + Send + Sync + 'static + { + CallError::Failed(err.into()) + } +} + + // NOTE(niklasad1): this `From` impl is a bit opinionated to regard all generic errors as `CallError`. -// The most common use case is when register method calls on the servers. +// In practice this should be the most common use case for users of this library. impl From for Error { fn from(err: anyhow::Error) -> Self { Error::Call(CallError::Failed(err)) @@ -111,6 +121,18 @@ pub enum Error { Custom(String), } +impl Error { + /// Create `Error::CallError` from a generic error. + /// Useful if you don't care about specific JSON-RPC error code and + /// just wants to return your custom error type. + pub fn to_call_error(err: E) -> Self + where E: std::error::Error + Send + Sync + 'static + { + Error::Call(CallError::from_std_error(err)) + } +} + + /// Error type with a special `subscription_closed` field to detect that /// a subscription has been closed to distinguish valid items produced /// by the server on the subscription stream from an error. From df9890ebbe58e3c2292167a6c0d0287fb3a4031a Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 17 Aug 2021 11:47:48 +0200 Subject: [PATCH 12/15] fmt --- types/src/error.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/types/src/error.rs b/types/src/error.rs index d9166d05b4..b79dfe329d 100644 --- a/types/src/error.rs +++ b/types/src/error.rs @@ -41,13 +41,13 @@ pub enum CallError { impl CallError { /// Create `CallError` from a generic error. pub fn from_std_error(err: E) -> Self - where E: std::error::Error + Send + Sync + 'static + where + E: std::error::Error + Send + Sync + 'static, { CallError::Failed(err.into()) } } - // NOTE(niklasad1): this `From` impl is a bit opinionated to regard all generic errors as `CallError`. // In practice this should be the most common use case for users of this library. impl From for Error { @@ -126,13 +126,13 @@ impl Error { /// Useful if you don't care about specific JSON-RPC error code and /// just wants to return your custom error type. pub fn to_call_error(err: E) -> Self - where E: std::error::Error + Send + Sync + 'static + where + E: std::error::Error + Send + Sync + 'static, { Error::Call(CallError::from_std_error(err)) } } - /// Error type with a special `subscription_closed` field to detect that /// a subscription has been closed to distinguish valid items produced /// by the server on the subscription stream from an error. From ac7de26bd56ecc7956457b0e5379b494880ea85d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 18 Aug 2021 10:37:22 +0200 Subject: [PATCH 13/15] Revert "register_*_method Into" This reverts commit 33b4fa28730b72647ba150659d3c0ab1937e524a. --- benches/helpers.rs | 9 ++++---- examples/http.rs | 3 +-- examples/proc_macro.rs | 2 +- examples/ws.rs | 4 ++-- http-server/src/tests.rs | 24 ++++++++++---------- tests/tests/helpers.rs | 9 ++++---- utils/src/server/rpc_module.rs | 22 +++++++++--------- ws-server/src/tests.rs | 41 +++++++++++++++++----------------- 8 files changed, 55 insertions(+), 59 deletions(-) diff --git a/benches/helpers.rs b/benches/helpers.rs index adc38200de..e8dc250b3a 100644 --- a/benches/helpers.rs +++ b/benches/helpers.rs @@ -2,7 +2,6 @@ use futures_channel::oneshot; use futures_util::future::FutureExt; use jsonrpsee::{ http_server::HttpServerBuilder, - types::Error, ws_server::{RpcModule, WsServerBuilder}, }; @@ -18,8 +17,8 @@ pub async fn http_server() -> String { let server = HttpServerBuilder::default().max_request_body_size(u32::MAX).build("127.0.0.1:0".parse().unwrap()).unwrap(); let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); - module.register_async_method::<_, _, Error>(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); + module.register_method(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); + module.register_async_method(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); server_started_tx.send(server.local_addr().unwrap()).unwrap(); server.start(module).await }); @@ -32,8 +31,8 @@ pub async fn ws_server() -> String { tokio::spawn(async move { let server = WsServerBuilder::default().build("127.0.0.1:0").await.unwrap(); let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); - module.register_async_method::<_, _, Error>(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); + module.register_method(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); + module.register_async_method(ASYNC_METHOD_NAME, |_, _| (async { Ok("lo") }).boxed()).unwrap(); module .register_subscription(SUB_METHOD_NAME, UNSUB_METHOD_NAME, |_params, mut sink, _ctx| { let x = "Hello"; diff --git a/examples/http.rs b/examples/http.rs index cf13bb1db4..7027fde5ee 100644 --- a/examples/http.rs +++ b/examples/http.rs @@ -27,7 +27,6 @@ use jsonrpsee::{ http_client::HttpClientBuilder, http_server::{HttpServerBuilder, RpcModule}, - types::Error, types::{traits::Client, JsonValue}, }; use std::net::SocketAddr; @@ -51,7 +50,7 @@ async fn main() -> anyhow::Result<()> { async fn run_server() -> anyhow::Result { let server = HttpServerBuilder::default().build("127.0.0.1:0".parse()?)?; let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo"))?; + module.register_method("say_hello", |_, _| Ok("lo"))?; let addr = server.local_addr()?; tokio::spawn(server.start(module)); diff --git a/examples/proc_macro.rs b/examples/proc_macro.rs index 3b47e58ad5..b9f1706d01 100644 --- a/examples/proc_macro.rs +++ b/examples/proc_macro.rs @@ -75,7 +75,7 @@ async fn main() -> anyhow::Result<()> { async fn run_server() -> anyhow::Result { let server = WsServerBuilder::default().build("127.0.0.1:0").await?; let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("state_getPairs", |_, _| Ok(vec![1, 2, 3]))?; + module.register_method("state_getPairs", |_, _| Ok(vec![1, 2, 3]))?; let addr = server.local_addr()?; tokio::spawn(async move { server.start(RpcServerImpl.into_rpc()).await }); diff --git a/examples/ws.rs b/examples/ws.rs index 7a170cd9cc..66ce250db1 100644 --- a/examples/ws.rs +++ b/examples/ws.rs @@ -25,7 +25,7 @@ // DEALINGS IN THE SOFTWARE. use jsonrpsee::{ - types::{traits::Client, v2::params::JsonRpcParams, Error}, + types::{traits::Client, v2::params::JsonRpcParams}, ws_client::WsClientBuilder, ws_server::{RpcModule, WsServerBuilder}, }; @@ -47,7 +47,7 @@ async fn main() -> anyhow::Result<()> { async fn run_server() -> anyhow::Result { let server = WsServerBuilder::default().build("127.0.0.1:0").await?; let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo"))?; + module.register_method("say_hello", |_, _| Ok("lo"))?; let addr = server.local_addr()?; tokio::spawn(server.start(module)); Ok(addr) diff --git a/http-server/src/tests.rs b/http-server/src/tests.rs index 84ce58587d..3d88873e22 100644 --- a/http-server/src/tests.rs +++ b/http-server/src/tests.rs @@ -47,38 +47,38 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle>, St let ctx = TestContext; let mut module = RpcModule::new(ctx); let addr = server.local_addr().unwrap(); - module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo")).unwrap(); - module.register_async_method::<_, _, Error>("say_hello_async", |_, _| async move { Ok("lo") }.boxed()).unwrap(); + module.register_method("say_hello", |_, _| Ok("lo")).unwrap(); + module.register_async_method("say_hello_async", |_, _| async move { Ok("lo") }.boxed()).unwrap(); module - .register_method::<_, _, Error>("add", |params, _| { + .register_method("add", |params, _| { let params: Vec = params.parse()?; let sum: u64 = params.into_iter().sum(); Ok(sum) }) .unwrap(); module - .register_method::<_, _, Error>("multiparam", |params, _| { + .register_method("multiparam", |params, _| { let params: (String, String, Vec) = params.parse()?; let r = format!("string1={}, string2={}, vec={}", params.0.len(), params.1.len(), params.2.len()); Ok(r) }) .unwrap(); - module.register_method::<_, _, Error>("notif", |_, _| Ok("")).unwrap(); + module.register_method("notif", |_, _| Ok("")).unwrap(); module - .register_method::<_, _, Error>("should_err", |_, ctx| { + .register_method("should_err", |_, ctx| { let _ = ctx.err().map_err(|e| CallError::Failed(e.into()))?; Ok("err") }) .unwrap(); module - .register_method::<_, _, Error>("should_ok", |_, ctx| { + .register_method("should_ok", |_, ctx| { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; Ok("ok") }) .unwrap(); module - .register_async_method::<_, _, Error>("should_ok_async", |_p, ctx| { + .register_async_method("should_ok_async", |_p, ctx| { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; Ok("ok") @@ -369,12 +369,12 @@ async fn can_register_modules() { let mut mod2 = RpcModule::new(cx2); assert_eq!(mod1.method_names().count(), 0); - mod1.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod1.register_method::<_, _, Error>("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod2.register_method::<_, _, Error>("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod1.register_method("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod1.register_method("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod2.register_method("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); // Won't register, name clashes - mod2.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod2.register_method("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); assert_eq!(mod1.method_names().count(), 2); diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 3ed344bdde..c92243d4d3 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -27,7 +27,6 @@ use futures_channel::oneshot; use jsonrpsee::{ http_server::HttpServerBuilder, - types::Error, ws_server::{WsServerBuilder, WsStopHandle}, RpcModule, }; @@ -43,7 +42,7 @@ pub async fn websocket_server_with_subscription() -> (SocketAddr, WsStopHandle) let server = rt.block_on(WsServerBuilder::default().build("127.0.0.1:0")).unwrap(); let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("say_hello", |_, _| Ok("hello")).unwrap(); + module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); module .register_subscription("subscribe_hello", "unsubscribe_hello", |_, mut sink, _| { @@ -103,7 +102,7 @@ pub async fn websocket_server() -> SocketAddr { let rt = tokio::runtime::Runtime::new().unwrap(); let server = rt.block_on(WsServerBuilder::default().build("127.0.0.1:0")).unwrap(); let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("say_hello", |_, _| Ok("hello")).unwrap(); + module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); rt.block_on(async move { server_started_tx.send(server.local_addr().unwrap()).unwrap(); @@ -119,8 +118,8 @@ pub async fn http_server() -> SocketAddr { let server = HttpServerBuilder::default().build("127.0.0.1:0".parse().unwrap()).unwrap(); let mut module = RpcModule::new(()); let addr = server.local_addr().unwrap(); - module.register_method::<_, _, Error>("say_hello", |_, _| Ok("hello")).unwrap(); - module.register_method::<_, _, Error>("notif", |_, _| Ok("")).unwrap(); + module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); + module.register_method("notif", |_, _| Ok("")).unwrap(); tokio::spawn(server.start(module)); addr diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index a0f9becbaa..5bb776134d 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -206,12 +206,11 @@ impl From> for Methods { impl RpcModule { /// Register a new synchronous RPC method, which computes the response with the given callback. - pub fn register_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> + pub fn register_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> where Context: Send + Sync + 'static, R: Serialize, - F: Fn(RpcParams, &Context) -> Result + Send + Sync + 'static, - E: Into, + F: Fn(RpcParams, &Context) -> Result + Send + Sync + 'static, { self.methods.verify_method_name(method_name)?; @@ -220,8 +219,8 @@ impl RpcModule { self.methods.mut_callbacks().insert( method_name, MethodCallback::Sync(Arc::new(move |id, params, tx, _| { - match callback(params, &*ctx).map_err(Into::into) { - Ok(res) => send_response(id, tx, res), + match callback(params, &*ctx) { + Ok(res) => send_response(id, &tx, res), Err(Error::Call(CallError::InvalidParams)) => { send_error(id, tx, JsonRpcErrorCode::InvalidParams.into()) } @@ -255,11 +254,10 @@ impl RpcModule { } /// Register a new asynchronous RPC method, which computes the response with the given callback. - pub fn register_async_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> + pub fn register_async_method(&mut self, method_name: &'static str, callback: F) -> Result<(), Error> where R: Serialize + Send + Sync + 'static, - F: Fn(RpcParams<'static>, Arc) -> BoxFuture<'static, Result> + Copy + Send + Sync + 'static, - E: Into, + F: Fn(RpcParams<'static>, Arc) -> BoxFuture<'static, Result> + Copy + Send + Sync + 'static, { self.methods.verify_method_name(method_name)?; @@ -270,7 +268,7 @@ impl RpcModule { MethodCallback::Async(Arc::new(move |id, params, tx, _| { let ctx = ctx.clone(); let future = async move { - match callback(params, ctx).await.map_err(Into::into) { + match callback(params, ctx).await { Ok(res) => send_response(id, &tx, res), Err(Error::Call(CallError::InvalidParams)) => { send_error(id, &tx, JsonRpcErrorCode::InvalidParams.into()) @@ -492,9 +490,9 @@ mod tests { fn rpc_modules_with_different_contexts_can_be_merged() { let cx = Vec::::new(); let mut mod1 = RpcModule::new(cx); - mod1.register_method::<_, _, Error>("bla with Vec context", |_: RpcParams, _| Ok(())).unwrap(); + mod1.register_method("bla with Vec context", |_: RpcParams, _| Ok(())).unwrap(); let mut mod2 = RpcModule::new(String::new()); - mod2.register_method::<_, _, Error>("bla with String context", |_: RpcParams, _| Ok(())).unwrap(); + mod2.register_method("bla with String context", |_: RpcParams, _| Ok(())).unwrap(); mod1.merge(mod2).unwrap(); @@ -516,7 +514,7 @@ mod tests { fn rpc_register_alias() { let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("hello_world", |_: RpcParams, _| Ok(())).unwrap(); + module.register_method("hello_world", |_: RpcParams, _| Ok(())).unwrap(); module.register_alias("hello_foobar", "hello_world").unwrap(); assert!(module.method("hello_world").is_some()); diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index 0fbef644dd..d4bf3ff55f 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -28,6 +28,7 @@ use crate::types::error::{CallError, Error}; use crate::{server::StopHandle, RpcModule, WsServerBuilder}; +use anyhow::anyhow; use futures_util::FutureExt; use jsonrpsee_test_utils::helpers::*; use jsonrpsee_test_utils::types::{Id, TestContext, WebSocketTestClient}; @@ -62,20 +63,20 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { let server = WsServerBuilder::default().build("127.0.0.1:0").with_default_timeout().await.unwrap().unwrap(); let mut module = RpcModule::new(()); module - .register_method::<_, _, Error>("say_hello", |_, _| { + .register_method("say_hello", |_, _| { log::debug!("server respond to hello"); Ok("hello") }) .unwrap(); module - .register_method::<_, _, Error>("add", |params, _| { + .register_method("add", |params, _| { let params: Vec = params.parse()?; let sum: u64 = params.into_iter().sum(); Ok(sum) }) .unwrap(); module - .register_async_method::<_, _, Error>("say_hello_async", |_, _| { + .register_async_method("say_hello_async", |_, _| { async move { log::debug!("server respond to hello"); // Call some async function inside. @@ -86,7 +87,7 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { }) .unwrap(); module - .register_async_method::<_, _, Error>("add_async", |params, _| { + .register_async_method("add_async", |params, _| { async move { let params: Vec = params.parse()?; let sum: u64 = params.into_iter().sum(); @@ -95,10 +96,10 @@ async fn server_with_handles() -> (SocketAddr, JoinHandle<()>, StopHandle) { .boxed() }) .unwrap(); - module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams)).unwrap(); - module.register_method("call_fail", |_params, _| Err::<(), _>(anyhow::Error::new(MyAppError))).unwrap(); + module.register_method("invalid_params", |_params, _| Err::<(), _>(CallError::InvalidParams.into())).unwrap(); + module.register_method("call_fail", |_params, _| Err::<(), _>(Error::to_call_error(MyAppError))).unwrap(); module - .register_method::<_, _, Error>("sleep_for", |params, _| { + .register_method("sleep_for", |params, _| { let sleep: Vec = params.parse()?; std::thread::sleep(std::time::Duration::from_millis(sleep[0])); Ok("Yawn!") @@ -120,21 +121,21 @@ async fn server_with_context() -> SocketAddr { let mut rpc_module = RpcModule::new(ctx); rpc_module - .register_method::<_, _, Error>("should_err", |_p, ctx| { + .register_method("should_err", |_p, ctx| { let _ = ctx.err().map_err(|e| CallError::Failed(e.into()))?; Ok("err") }) .unwrap(); rpc_module - .register_method::<_, _, Error>("should_ok", |_p, ctx| { + .register_method("should_ok", |_p, ctx| { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; Ok("ok") }) .unwrap(); rpc_module - .register_async_method::<_, _, Error>("should_ok_async", |_p, ctx| { + .register_async_method("should_ok_async", |_p, ctx| { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; // Call some async function inside. @@ -149,7 +150,7 @@ async fn server_with_context() -> SocketAddr { async move { let _ = ctx.ok().map_err(|e| CallError::Failed(e.into()))?; // Async work that returns an error - futures_util::future::err::<(), _>(CallError::Failed(anyhow::anyhow!("nah"))).await + futures_util::future::err::<(), _>(anyhow!("nah").into()).await } .boxed() }) @@ -167,7 +168,7 @@ async fn can_set_the_max_request_body_size() { // Rejects all requests larger than 10 bytes let server = WsServerBuilder::default().max_request_body_size(10).build(addr).await.unwrap(); let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("anything", |_p, _cx| Ok(())).unwrap(); + module.register_method("anything", |_p, _cx| Ok(())).unwrap(); let addr = server.local_addr().unwrap(); tokio::spawn(server.start(module)); @@ -190,7 +191,7 @@ async fn can_set_max_connections() { // Server that accepts max 2 connections let server = WsServerBuilder::default().max_connections(2).build(addr).await.unwrap(); let mut module = RpcModule::new(()); - module.register_method::<_, _, Error>("anything", |_p, _cx| Ok(())).unwrap(); + module.register_method("anything", |_p, _cx| Ok(())).unwrap(); let addr = server.local_addr().unwrap(); tokio::spawn(server.start(module)); @@ -451,12 +452,12 @@ async fn invalid_request_object() { #[tokio::test] async fn register_methods_works() { let mut module = RpcModule::new(()); - assert!(module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo")).is_ok()); - assert!(module.register_method::<_, _, Error>("say_hello", |_, _| Ok("lo")).is_err()); + assert!(module.register_method("say_hello", |_, _| Ok("lo")).is_ok()); + assert!(module.register_method("say_hello", |_, _| Ok("lo")).is_err()); assert!(module.register_subscription("subscribe_hello", "unsubscribe_hello", |_, _, _| Ok(())).is_ok()); assert!(module.register_subscription("subscribe_hello_again", "unsubscribe_hello", |_, _, _| Ok(())).is_err()); assert!( - module.register_method::<_, _, Error>("subscribe_hello_again", |_, _| Ok("lo")).is_ok(), + module.register_method("subscribe_hello_again", |_, _| Ok("lo")).is_ok(), "Failed register_subscription should not have side-effects" ); } @@ -527,12 +528,12 @@ async fn can_register_modules() { assert_eq!(mod1.method_names().count(), 0); assert_eq!(mod2.method_names().count(), 0); - mod1.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod1.register_method::<_, _, Error>("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); - mod2.register_method::<_, _, Error>("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod1.register_method("bla", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod1.register_method("bla2", |_, cx| Ok(format!("Gave me {}", cx))).unwrap(); + mod2.register_method("yada", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); // Won't register, name clashes - mod2.register_method::<_, _, Error>("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); + mod2.register_method("bla", |_, cx| Ok(format!("Gave me {:?}", cx))).unwrap(); assert_eq!(mod1.method_names().count(), 2); let err = mod1.merge(mod2).unwrap_err(); From 61b365aa9d2ada41d42de5ad52634c70bdf2e871 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 18 Aug 2021 10:52:29 +0200 Subject: [PATCH 14/15] add better comment --- utils/src/server/rpc_module.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index 96b3e59057..e3f3973102 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -247,7 +247,8 @@ impl RpcModule { let err = JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; send_error(id, tx, err) } - // This should normally not happen. + // This should normally not happen because the most common use case is to + // return `Error::Call` in `register_method`. Err(e) => { let err = JsonRpcErrorObject { code: JsonRpcErrorCode::ServerError(UNKNOWN_ERROR_CODE), @@ -296,7 +297,8 @@ impl RpcModule { JsonRpcErrorObject { code: code.into(), message: &message, data: data.as_deref() }; send_error(id, &tx, err) } - // This should normally not happen. + // This should normally not happen because the most common use case is to + // return `Error::Call` in `register_async_method`. Err(e) => { let err = JsonRpcErrorObject { code: JsonRpcErrorCode::ServerError(UNKNOWN_ERROR_CODE), From 710138815894c2925feaf92a7a19f3659995addf Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 18 Aug 2021 10:57:07 +0200 Subject: [PATCH 15/15] fix nit --- utils/src/server/rpc_module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index e3f3973102..d44d0a447f 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -231,7 +231,7 @@ impl RpcModule { method_name, MethodCallback::Sync(Arc::new(move |id, params, tx, _| { match callback(params, &*ctx) { - Ok(res) => send_response(id, &tx, res), + Ok(res) => send_response(id, tx, res), Err(Error::Call(CallError::InvalidParams)) => { send_error(id, tx, JsonRpcErrorCode::InvalidParams.into()) }