Skip to content

Commit

Permalink
[proc macros]: only generate unsub method if not provided (#702)
Browse files Browse the repository at this point in the history
* [proc macros]: only generate unsub if not provided

* Update proc-macros/src/rpc_macro.rs

Co-authored-by: David <[email protected]>

* Update proc-macros/src/lib.rs

Co-authored-by: David <[email protected]>

* fix grumbles

* Update proc-macros/src/lib.rs

Co-authored-by: David <[email protected]>

* Update proc-macros/src/lib.rs

Co-authored-by: David <[email protected]>

* Update proc-macros/src/lib.rs

Co-authored-by: David <[email protected]>

* Update proc-macros/tests/ui/correct/alias_doesnt_use_namespace.rs

Co-authored-by: David <[email protected]>

Co-authored-by: David <[email protected]>
  • Loading branch information
niklasad1 and dvdplm authored Feb 18, 2022
1 parent 4bc9f57 commit 721117d
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 40 deletions.
2 changes: 1 addition & 1 deletion proc-macros/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fn find_jsonrpsee_crate(http_name: &str, ws_name: &str) -> Result<proc_macro2::T
/// #[method(name = "call")]
/// fn call(&self, a: A) -> RpcResult<B>;
///
/// #[subscription(name = "sub", item = Vec<C>)]
/// #[subscription(name = "subscribe", item = Vec<C>)]
/// fn sub(&self) -> RpcResult<()>;
/// }
/// ```
Expand Down
14 changes: 10 additions & 4 deletions proc-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub(crate) mod visitor;
/// #[method(name = "bar")]
/// fn sync_method(&self) -> String;
///
/// #[subscription(name = "sub", unsub = "unsub", item = "String")]
/// #[subscription(name = "subscribe", item = "String")]
/// fn sub(&self);
/// }
/// ```
Expand Down Expand Up @@ -163,6 +163,8 @@ pub(crate) mod visitor;
///
/// - `name` (mandatory): name of the RPC method. Does not have to be the same as the Rust method name.
/// - `aliases`: list of name aliases for the RPC method as a comma separated string.
/// Aliases are processed ignoring the namespace, so add the complete name, including the
/// namespace.
/// - `blocking`: when set method execution will always spawn on a dedicated thread. Only usable with non-`async` methods.
/// - `param_kind`: kind of structure to use for parameter passing. Can be "array" or "map", defaults to "array".
///
Expand All @@ -179,7 +181,11 @@ pub(crate) mod visitor;
/// **Arguments:**
///
/// - `name` (mandatory): name of the RPC method. Does not have to be the same as the Rust method name.
/// - `unsub` (mandatory): name of the RPC method to unsubscribe from the subscription. Must not be the same as `name`.
/// - `unsubscribe` (optional): name of the RPC method to unsubscribe from the subscription. Must not be the same as `name`.
/// This is generated for you if the subscription name starts with `subscribe`.
/// - `aliases` (optional): aliases for `name`. Aliases are processed ignoring the namespace,
/// so add the complete name, including the namespace.
/// - `unsubscribe_aliases` (optional): Similar to `aliases` but for `unsubscribe`.
/// - `item` (mandatory): type of items yielded by the subscription. Note that it must be the type, not string.
/// - `param_kind`: kind of structure to use for parameter passing. Can be "array" or "map", defaults to "array".
///
Expand All @@ -188,7 +194,7 @@ pub(crate) mod visitor;
/// Rust method marked with the `subscription` attribute **must**:
///
/// - be synchronous;
/// - not have return value.
/// - return `RpcResult<()>`
///
/// Rust method marked with `subscription` attribute **may**:
///
Expand Down Expand Up @@ -220,7 +226,7 @@ pub(crate) mod visitor;
/// #[method(name = "baz", blocking)]
/// fn blocking_method(&self) -> RpcResult<u16>;
///
/// #[subscription(name = "sub", item = String)]
/// #[subscription(name = "sub", unsubscribe = "unsub", item = String)]
/// fn sub(&self) -> RpcResult<()>;
/// }
///
Expand Down
21 changes: 16 additions & 5 deletions proc-macros/src/rpc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ pub struct RpcSubscription {

impl RpcSubscription {
pub fn from_item(attr: syn::Attribute, mut sub: syn::TraitItemMethod) -> syn::Result<Self> {
let [aliases, item, name, param_kind, unsubscribe_aliases] =
AttributeMeta::parse(attr)?.retain(["aliases", "item", "name", "param_kind", "unsubscribe_aliases"])?;
let [aliases, item, name, param_kind, unsubscribe, unsubscribe_aliases] = AttributeMeta::parse(attr)?
.retain(["aliases", "item", "name", "param_kind", "unsubscribe", "unsubscribe_aliases"])?;

let aliases = parse_aliases(aliases)?;
let map = name?.value::<NameMapping>()?;
Expand All @@ -150,7 +150,12 @@ impl RpcSubscription {

let sig = sub.sig.clone();
let docs = extract_doc_comments(&sub.attrs);
let unsubscribe = build_unsubscribe_method(&name);
let unsubscribe = match parse_subscribe(unsubscribe)? {
Some(unsub) => unsub,
None => build_unsubscribe_method(&name).expect(
&format!("Could not generate the unsubscribe method with name '{}'. You need to provide the name manually using the `unsubscribe` attribute in your RPC API definition", name),
),
};

let params: Vec<_> = sig
.inputs
Expand Down Expand Up @@ -335,10 +340,16 @@ fn parse_aliases(arg: Result<Argument, MissingArgument>) -> syn::Result<Vec<Stri
Ok(aliases.map(|a| a.list.into_iter().map(|lit| lit.value()).collect()).unwrap_or_default())
}

fn parse_subscribe(arg: Result<Argument, MissingArgument>) -> syn::Result<Option<String>> {
let unsub = optional(arg, Argument::string)?;

Ok(unsub)
}

fn find_attr<'a>(attrs: &'a [Attribute], ident: &str) -> Option<&'a Attribute> {
attrs.iter().find(|a| a.path.is_ident(ident))
}

fn build_unsubscribe_method(method: &str) -> String {
format!("unsubscribe{}", method.strip_prefix("subscribe").unwrap_or(method))
fn build_unsubscribe_method(method: &str) -> Option<String> {
method.strip_prefix("subscribe").map(|s| format!("unsubscribe{}", s))
}
7 changes: 4 additions & 3 deletions proc-macros/tests/ui/correct/alias_doesnt_use_namespace.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use jsonrpsee::{proc_macros::rpc, core::RpcResult};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

#[rpc(client, server, namespace = "myapi")]
pub trait Rpc {
/// Alias doesn't use the namespace so not duplicated.
/// Aliases don't use the namespace.
/// Thus, this will generate `myapi_getTemp` and `getTemp`.
#[method(name = "getTemp", aliases = ["getTemp"])]
async fn async_method(&self, param_a: u8, param_b: String) -> RpcResult<u16>;

#[subscription(name = "getFood", item = String, aliases = ["getFood"], unsubscribe_aliases = ["unsubscribegetFood"])]
#[subscription(name = "subscribeGetFood", item = String, aliases = ["getFood"], unsubscribe_aliases = ["unsubscribegetFood"])]
fn sub(&self) -> RpcResult<()>;
}

Expand Down
6 changes: 3 additions & 3 deletions proc-macros/tests/ui/correct/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
use std::net::SocketAddr;

use jsonrpsee::core::{async_trait, client::ClientT, RpcResult};
use jsonrpsee::proc_macros::rpc;
use jsonrpsee::rpc_params;
use jsonrpsee::core::{async_trait, client::ClientT, RpcResult};
use jsonrpsee::ws_client::*;
use jsonrpsee::ws_server::{SubscriptionSink, WsServerBuilder};

Expand All @@ -25,10 +25,10 @@ pub trait Rpc {
#[method(name = "bar")]
fn sync_method(&self) -> RpcResult<u16>;

#[subscription(name = "sub", item = String)]
#[subscription(name = "subscribe", item = String)]
fn sub(&self) -> RpcResult<()>;

#[subscription(name = "echo", aliases = ["ECHO"], item = u32, unsubscribe_aliases = ["NotInterested", "listenNoMore"])]
#[subscription(name = "echo", unsubscribe = "unsubscribeEcho", aliases = ["ECHO"], item = u32, unsubscribe_aliases = ["NotInterested", "listenNoMore"])]
fn sub_with_params(&self, val: u32) -> RpcResult<()>;

// This will send data to subscribers with the `method` field in the JSON payload set to `foo_subscribe_override`
Expand Down
4 changes: 2 additions & 2 deletions proc-macros/tests/ui/correct/only_client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Example of using proc macro to generate working client and server.
use jsonrpsee::{proc_macros::rpc, core::RpcResult};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

#[rpc(client)]
pub trait Rpc {
Expand All @@ -10,7 +10,7 @@ pub trait Rpc {
#[method(name = "bar")]
fn sync_method(&self) -> RpcResult<u16>;

#[subscription(name = "sub", item = String)]
#[subscription(name = "subscribe", item = String)]
fn sub(&self);
}

Expand Down
6 changes: 3 additions & 3 deletions proc-macros/tests/ui/correct/only_server.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::net::SocketAddr;

use jsonrpsee::proc_macros::rpc;
use jsonrpsee::core::{async_trait, RpcResult};
use jsonrpsee::proc_macros::rpc;
use jsonrpsee::ws_server::{SubscriptionSink, WsServerBuilder};

#[rpc(server)]
Expand All @@ -12,7 +12,7 @@ pub trait Rpc {
#[method(name = "bar")]
fn sync_method(&self) -> RpcResult<u16>;

#[subscription(name = "sub", item = String)]
#[subscription(name = "subscribe", item = String)]
fn sub(&self) -> RpcResult<()>;
}

Expand All @@ -39,7 +39,7 @@ pub async fn websocket_server() -> SocketAddr {
let addr = server.local_addr().unwrap();

server.start(RpcServerImpl.into_rpc()).unwrap();

addr
}

Expand Down
5 changes: 3 additions & 2 deletions proc-macros/tests/ui/correct/parse_angle_brackets.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use jsonrpsee::{proc_macros::rpc, core::RpcResult};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

fn main() {
#[rpc(server)]
pub trait Rpc {
#[subscription(
name = "submitAndWatchExtrinsic",
unsubscribe = "author_unwatchExtrinsic",
aliases = ["author_extrinsicUpdate"],
unsubscribe_aliases = ["author_unwatchExtrinsic"],
unsubscribe_aliases = ["author_unwatchExtrinsic2"],
// Arguments are being parsed the nearest comma,
// angle braces need to be accounted for manually.
item = TransactionStatus<Hash, BlockHash>,
Expand Down
4 changes: 2 additions & 2 deletions proc-macros/tests/ui/correct/rpc_deny_missing_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#![deny(missing_docs)]

use jsonrpsee::proc_macros::rpc;
use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;

#[rpc(client, server)]
pub trait ApiWithDocumentation {
Expand All @@ -12,7 +12,7 @@ pub trait ApiWithDocumentation {
async fn async_method(&self) -> RpcResult<u8>;

/// Subscription docs.
#[subscription(name = "sub", item = String)]
#[subscription(name = "sub", unsubscribe = "unsub", item = String)]
fn sub(&self) -> RpcResult<()>;
}

Expand Down
4 changes: 2 additions & 2 deletions proc-macros/tests/ui/incorrect/sub/sub_conflicting_alias.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use jsonrpsee::{proc_macros::rpc, core::RpcResult};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

#[rpc(client, server)]
pub trait DuplicatedSubAlias {
#[subscription(name = "alias", item = String, aliases = ["hello_is_goodbye"], unsubscribe_aliases = ["hello_is_goodbye"])]
#[subscription(name = "subscribeAlias", item = String, aliases = ["hello_is_goodbye"], unsubscribe_aliases = ["hello_is_goodbye"])]
fn async_method(&self) -> RpcResult<()>;
}

Expand Down
6 changes: 3 additions & 3 deletions proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use jsonrpsee::{proc_macros::rpc, core::RpcResult};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

// Subscription method must not use the same override name.
#[rpc(client, server)]
pub trait DupOverride {
#[subscription(name = "one" => "override", item = u8)]
#[subscription(name = "subscribeOne" => "override", item = u8)]
fn one(&self) -> RpcResult<()>;
#[subscription(name = "two" => "override", item = u8)]
#[subscription(name = "subscribeTwo" => "override", item = u8)]
fn two(&self) -> RpcResult<()>;
}

Expand Down
4 changes: 2 additions & 2 deletions proc-macros/tests/ui/incorrect/sub/sub_name_override.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use jsonrpsee::{proc_macros::rpc, core::RpcResult};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

// Subscription method name conflict with notif override.
#[rpc(client, server)]
pub trait DupName {
#[subscription(name = "one" => "one", item = u8)]
#[subscription(name = "one" => "one", unsubscribe = "unsubscribeOne", item = u8)]
fn one(&self) -> RpcResult<()>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use jsonrpsee::proc_macros::rpc;
// Unsupported attribute field.
#[rpc(client, server)]
pub trait UnsupportedField {
#[subscription(name = "sub", item = u8, magic = true)]
#[subscription(name = "sub", unsubscribe = "unsub", item = u8, magic = true)]
fn sub(&self);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: Unknown argument `magic`, expected one of: `aliases`, `item`, `name`, `param_kind`, `unsubscribe_aliases`
--> $DIR/sub_unsupported_field.rs:6:42
error: Unknown argument `magic`, expected one of: `aliases`, `item`, `name`, `param_kind`, `unsubscribe`, `unsubscribe_aliases`
--> tests/ui/incorrect/sub/sub_unsupported_field.rs:6:65
|
6 | #[subscription(name = "sub", item = u8, magic = true)]
| ^^^^^
6 | #[subscription(name = "sub", unsubscribe = "unsub", item = u8, magic = true)]
| ^^^^^
6 changes: 3 additions & 3 deletions tests/tests/proc_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ mod rpc_impl {
#[method(name = "bar")]
fn sync_method(&self) -> RpcResult<u16>;

#[subscription(name = "sub", item = String)]
#[subscription(name = "sub", unsubscribe = "unsub", item = String)]
fn sub(&self) -> RpcResult<()>;

#[subscription(name = "echo", aliases = ["alias_echo"], item = u32)]
#[subscription(name = "echo", unsubscribe = "unsubscribe_echo", aliases = ["alias_echo"], item = u32)]
fn sub_with_params(&self, val: u32) -> RpcResult<()>;

#[method(name = "params")]
Expand Down Expand Up @@ -123,7 +123,7 @@ mod rpc_impl {
#[rpc(client, server, namespace = "generic_sub")]
pub trait OnlyGenericSubscription<Input, R> {
/// Get header of a relay chain block.
#[subscription(name = "sub", item = Vec<R>)]
#[subscription(name = "sub", unsubscribe = "unsub", item = Vec<R>)]
fn sub(&self, hash: Input) -> RpcResult<()>;
}

Expand Down

0 comments on commit 721117d

Please sign in to comment.