Skip to content

Commit

Permalink
[proc macros] force proc macro api to return Result (#435)
Browse files Browse the repository at this point in the history
* rewrite me

* require proc macro API to return result

* send unknown message when error is not CallError

* show example that auto cast StdError doesn't work

* register_*_method Into<Error>

* clippy

* replace generic errors with anyhow::Error

* fix nits

* example that anyhow::Error in register_method works

* CallError: add missing From impl

* [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.

* fmt

* Revert "register_*_method Into<Error>"

This reverts commit 33b4fa2.

* add better comment

* fix nit
  • Loading branch information
niklasad1 authored Aug 18, 2021
1 parent 872a8d7 commit 09abbaa
Show file tree
Hide file tree
Showing 27 changed files with 160 additions and 97 deletions.
10 changes: 5 additions & 5 deletions examples/proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@

use jsonrpsee::{
proc_macros::rpc,
types::async_trait,
types::{async_trait, error::Error},
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<u128>) -> Vec<usize>;
async fn storage_pairs(&self, prefix: usize, hash: Option<u128>) -> Result<Vec<usize>, Error>;

/// Subscription that take `Option<Vec<u8>>` as input and produces output `Vec<usize>`.
#[subscription(name = "subscribeStorage", unsub = "unsubscribeStorage", item = Vec<usize>)]
Expand All @@ -47,8 +47,8 @@ pub struct RpcServerImpl;

#[async_trait]
impl RpcServer for RpcServerImpl {
async fn storage_pairs(&self, _prefix: usize, _hash: Option<u128>) -> Vec<usize> {
vec![1, 2, 3, 4]
async fn storage_pairs(&self, _prefix: usize, _hash: Option<u128>) -> Result<Vec<usize>, Error> {
Ok(vec![1, 2, 3, 4])
}

fn subscribe_storage(&self, mut sink: SubscriptionSink, keys: Option<Vec<u8>>) {
Expand Down
8 changes: 4 additions & 4 deletions http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl HttpClientBuilder {
/// Build the HTTP client with target to connect to.
pub fn build(self, target: impl AsRef<str>) -> Result<HttpClient, Error> {
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 })
}
}
Expand Down Expand Up @@ -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())),
}
}

Expand All @@ -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) {
Expand Down Expand Up @@ -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<JsonRpcResponse<_>> = match serde_json::from_slice(&body) {
Expand Down
14 changes: 7 additions & 7 deletions proc-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u16>;
///
/// #[method(name = "bar")]
/// fn sync_method(&self) -> u16;
/// fn sync_method(&self) -> JsonRpcResult<u16>;
///
/// #[subscription(name = "sub", unsub = "unsub", item = String)]
/// fn sub(&self);
Expand All @@ -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<u16> {
/// Ok(42u16)
/// }
///
/// fn sync_method(&self) -> u16 {
/// 10u16
/// fn sync_method(&self) -> JsonRpcResult<u16> {
/// Ok(10u16)
/// }
///
/// // We could've spawned a `tokio` future that yields values while our program works,
Expand Down
2 changes: 1 addition & 1 deletion proc-macros/src/new/render_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! { #returns };

(called_method, returns)
} else {
Expand Down
10 changes: 4 additions & 6 deletions proc-macros/src/new/render_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ impl RpcDescription {
}
};

// panic!("{}", trait_impl);

Ok(trait_impl)
}

Expand Down Expand Up @@ -83,7 +81,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());
Expand All @@ -93,7 +91,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)
})
Expand All @@ -102,7 +100,7 @@ impl RpcDescription {
handle_register_result(quote! {
rpc.register_method(#rpc_method_name, |params, context| {
#parsing
Ok(context.#rust_method_name(#params_seq))
context.#rust_method_name(#params_seq)
})
})
}
Expand All @@ -121,7 +119,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());
Expand Down
5 changes: 3 additions & 2 deletions proc-macros/tests/rpc_example.rs
Original file line number Diff line number Diff line change
@@ -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<Cow<'_, str>>) -> u16;
async fn async_method(&self, param_a: u8, param_b: Option<Cow<'_, str>>) -> Result<u16, Error>;

#[method(name = "bar")]
fn sync_method(&self) -> u16;
fn sync_method(&self) -> Result<u16, Error>;

#[subscription(name = "sub", unsub = "unsub", item = String)]
fn sub(&self);
Expand Down
14 changes: 7 additions & 7 deletions proc-macros/tests/ui/correct/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use jsonrpsee::{
proc_macros::rpc,
types::async_trait,
types::{async_trait, JsonRpcResult},
ws_client::*,
ws_server::{SubscriptionSink, WsServerBuilder},
};
Expand All @@ -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<u16>;

#[method(name = "bar")]
fn sync_method(&self) -> u16;
fn sync_method(&self) -> JsonRpcResult<u16>;

#[subscription(name = "sub", unsub = "unsub", item = String)]
fn sub(&self);
Expand All @@ -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<u16> {
Ok(42u16)
}

fn sync_method(&self) -> u16 {
10u16
fn sync_method(&self) -> JsonRpcResult<u16> {
Ok(10u16)
}

fn sub(&self, mut sink: SubscriptionSink) {
Expand Down
6 changes: 3 additions & 3 deletions proc-macros/tests/ui/correct/only_client.rs
Original file line number Diff line number Diff line change
@@ -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<u16>;

#[method(name = "bar")]
fn sync_method(&self) -> u16;
fn sync_method(&self) -> JsonRpcResult<u16>;

#[subscription(name = "sub", unsub = "unsub", item = String)]
fn sub(&self);
Expand Down
14 changes: 7 additions & 7 deletions proc-macros/tests/ui/correct/only_server.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use jsonrpsee::{
proc_macros::rpc,
types::async_trait,
types::{async_trait, JsonRpcResult},
ws_server::{SubscriptionSink, WsServerBuilder},
};
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<u16>;

#[method(name = "bar")]
fn sync_method(&self) -> u16;
fn sync_method(&self) -> JsonRpcResult<u16>;

#[subscription(name = "sub", unsub = "unsub", item = String)]
fn sub(&self);
Expand All @@ -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<u16> {
Ok(42u16)
}

fn sync_method(&self) -> u16 {
10u16
fn sync_method(&self) -> JsonRpcResult<u16> {
Ok(10u16)
}

fn sub(&self, mut sink: SubscriptionSink) {
Expand Down
2 changes: 1 addition & 1 deletion proc-macros/tests/ui/incorrect/method/method_no_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>;
}

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>;
}

fn main() {}
4 changes: 2 additions & 2 deletions proc-macros/tests/ui/incorrect/rpc/rpc_assoc_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ pub trait AssociatedConst {
const WOO: usize;

#[method(name = "foo")]
async fn async_method(&self) -> u8;
async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult<u8>;
}

#[rpc(client, server)]
pub trait AssociatedType {
type Woo;

#[method(name = "foo")]
async fn async_method(&self) -> u8;
async fn async_method(&self) -> jsonrpsee::types::JsonRpcResult<u8>;
}

fn main() {}
6 changes: 3 additions & 3 deletions proc-macros/tests/ui/incorrect/rpc/rpc_name_conflict.rs
Original file line number Diff line number Diff line change
@@ -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<u8>;

#[method(name = "foo")]
async fn bar(&self) -> u8;
async fn bar(&self) -> JsonRpcResult<u8>;
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<u8>;
| ^^^
2 changes: 1 addition & 1 deletion proc-macros/tests/ui/incorrect/rpc/rpc_no_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>;
}

fn main() {}
2 changes: 1 addition & 1 deletion proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>;
}

fn main() {}
4 changes: 2 additions & 2 deletions proc-macros/tests/ui/incorrect/rpc/rpc_not_qualified.stderr
Original file line number Diff line number Diff line change
@@ -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<u8>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Loading

0 comments on commit 09abbaa

Please sign in to comment.