From 9c6fd4bfee44aec6ebb10dae0fb2779562ecf125 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 19 Nov 2021 19:30:47 +0100 Subject: [PATCH] feat: make it possible to override `method name` in subscriptions (#568) * feat: override `method` subscription notif * Arrow syntax for overwrites (#569) * check that unique notifs are used * check that custom sub name is unique * cargo fmt * address grumbles * Update proc-macros/src/rpc_macro.rs * commit added tests * Update proc-macros/src/render_server.rs Co-authored-by: David * Update proc-macros/src/render_server.rs Co-authored-by: David * Update proc-macros/src/rpc_macro.rs Co-authored-by: David * Update proc-macros/src/rpc_macro.rs Co-authored-by: David * Update utils/src/server/rpc_module.rs Co-authored-by: David * grumbles * fix long lines * Update utils/src/server/rpc_module.rs Co-authored-by: David * Update utils/src/server/rpc_module.rs Co-authored-by: David * Update proc-macros/src/rpc_macro.rs Co-authored-by: David * Update proc-macros/src/render_server.rs Co-authored-by: David * Update proc-macros/src/render_server.rs Co-authored-by: David * more grumbles Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> Co-authored-by: David --- benches/helpers.rs | 2 +- examples/proc_macro.rs | 2 +- examples/ws_sub_with_params.rs | 4 +- examples/ws_subscription.rs | 2 +- proc-macros/src/attributes.rs | 39 +++++++++++++++---- proc-macros/src/render_server.rs | 12 +++++- proc-macros/src/rpc_macro.rs | 28 +++++++++++-- proc-macros/tests/ui/correct/basic.rs | 13 +++++++ .../ui/incorrect/sub/sub_dup_name_override.rs | 12 ++++++ .../sub/sub_dup_name_override.stderr | 5 +++ .../ui/incorrect/sub/sub_name_override.rs | 10 +++++ .../ui/incorrect/sub/sub_name_override.stderr | 5 +++ tests/tests/helpers.rs | 33 +++++++++------- tests/tests/integration_tests.rs | 2 +- tests/tests/proc_macros.rs | 2 +- utils/src/server/rpc_module.rs | 29 ++++++++++---- ws-server/src/tests.rs | 12 ++++-- 17 files changed, 167 insertions(+), 45 deletions(-) create mode 100644 proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.rs create mode 100644 proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.stderr create mode 100644 proc-macros/tests/ui/incorrect/sub/sub_name_override.rs create mode 100644 proc-macros/tests/ui/incorrect/sub/sub_name_override.stderr diff --git a/benches/helpers.rs b/benches/helpers.rs index f60fc122b6..dcd3de7394 100644 --- a/benches/helpers.rs +++ b/benches/helpers.rs @@ -101,7 +101,7 @@ pub async fn ws_server(handle: tokio::runtime::Handle) -> (String, jsonrpsee::ws module.register_method(SYNC_METHOD_NAME, |_, _| Ok("lo")).unwrap(); module.register_async_method(ASYNC_METHOD_NAME, |_, _| async { Ok("lo") }).unwrap(); module - .register_subscription(SUB_METHOD_NAME, UNSUB_METHOD_NAME, |_params, mut sink, _ctx| { + .register_subscription(SUB_METHOD_NAME, SUB_METHOD_NAME, UNSUB_METHOD_NAME, |_params, mut sink, _ctx| { let x = "Hello"; tokio::spawn(async move { sink.send(&x) }); Ok(()) diff --git a/examples/proc_macro.rs b/examples/proc_macro.rs index 11825834b3..f13a8b29b4 100644 --- a/examples/proc_macro.rs +++ b/examples/proc_macro.rs @@ -45,7 +45,7 @@ where async fn storage_keys(&self, storage_key: StorageKey, hash: Option) -> Result, Error>; /// Subscription that takes a `StorageKey` as input and produces a `Vec`. - #[subscription(name = "subscribeStorage", item = Vec)] + #[subscription(name = "subscribeStorage" => "override", item = Vec)] fn subscribe_storage(&self, keys: Option>) -> Result<(), Error>; } diff --git a/examples/ws_sub_with_params.rs b/examples/ws_sub_with_params.rs index 3c3c61c3d1..1275168d64 100644 --- a/examples/ws_sub_with_params.rs +++ b/examples/ws_sub_with_params.rs @@ -62,7 +62,7 @@ async fn run_server() -> anyhow::Result { let server = WsServerBuilder::default().build("127.0.0.1:0").await?; let mut module = RpcModule::new(()); module - .register_subscription("sub_one_param", "unsub_one_param", |params, mut sink, _| { + .register_subscription("sub_one_param", "sub_one_param", "unsub_one_param", |params, mut sink, _| { let idx: usize = params.one()?; std::thread::spawn(move || loop { let _ = sink.send(&LETTERS.chars().nth(idx)); @@ -72,7 +72,7 @@ async fn run_server() -> anyhow::Result { }) .unwrap(); module - .register_subscription("sub_params_two", "unsub_params_two", |params, mut sink, _| { + .register_subscription("sub_params_two", "params_two", "unsub_params_two", |params, mut sink, _| { let (one, two): (usize, usize) = params.parse()?; std::thread::spawn(move || loop { let _ = sink.send(&LETTERS[one..two].to_string()); diff --git a/examples/ws_subscription.rs b/examples/ws_subscription.rs index f9521992dc..4af06c9fa0 100644 --- a/examples/ws_subscription.rs +++ b/examples/ws_subscription.rs @@ -61,7 +61,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_subscription("subscribe_hello", "unsubscribe_hello", |_, mut sink, _| { + module.register_subscription("subscribe_hello", "s_hello", "unsubscribe_hello", |_, mut sink, _| { std::thread::spawn(move || loop { if let Err(Error::SubscriptionClosed(_)) = sink.send(&"hello my friend") { return; diff --git a/proc-macros/src/attributes.rs b/proc-macros/src/attributes.rs index 02da827efa..a143a7a873 100644 --- a/proc-macros/src/attributes.rs +++ b/proc-macros/src/attributes.rs @@ -28,7 +28,7 @@ use proc_macro2::{Span, TokenStream as TokenStream2, TokenTree}; use std::{fmt, iter}; use syn::parse::{Parse, ParseStream, Parser}; use syn::punctuated::Punctuated; -use syn::{spanned::Spanned, Attribute, Error, Token}; +use syn::{spanned::Spanned, Attribute, Error, LitInt, LitStr, Token}; pub(crate) struct AttributeMeta { pub path: syn::Path, @@ -48,15 +48,22 @@ pub enum ParamKind { #[derive(Debug, Clone)] pub struct Resource { - pub name: syn::LitStr, + pub name: LitStr, pub assign: Token![=], - pub value: syn::LitInt, + pub value: LitInt, } -pub struct Aliases { - pub list: Punctuated, +pub struct NameMapping { + pub name: String, + pub mapped: Option, } +pub struct Bracketed { + pub list: Punctuated, +} + +pub type Aliases = Bracketed; + impl Parse for Argument { fn parse(input: ParseStream) -> syn::Result { let label = input.parse()?; @@ -91,7 +98,23 @@ impl Parse for Resource { } } -impl Parse for Aliases { +impl Parse for NameMapping { + fn parse(input: ParseStream) -> syn::Result { + let name = input.parse::()?.value(); + + let mapped = if input.peek(Token![=>]) { + input.parse::]>()?; + + Some(input.parse::()?.value()) + } else { + None + }; + + Ok(NameMapping { name, mapped }) + } +} + +impl Parse for Bracketed { fn parse(input: ParseStream) -> syn::Result { let content; @@ -99,7 +122,7 @@ impl Parse for Aliases { let list = content.parse_terminated(Parse::parse)?; - Ok(Aliases { list }) + Ok(Bracketed { list }) } } @@ -201,7 +224,7 @@ impl Argument { /// Asserts that the argument is `key = "string"` and gets the value of the string pub fn string(self) -> syn::Result { - self.value::().map(|lit| lit.value()) + self.value::().map(|lit| lit.value()) } } diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index 86b96cb757..68d4b7e816 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -174,6 +174,8 @@ impl RpcDescription { let rust_method_name = &sub.signature.sig.ident; // Name of the RPC method to subscribe to (e.g. `foo_sub`). let rpc_sub_name = self.rpc_identifier(&sub.name); + // Name of `method` in the subscription response. + let rpc_notif_name_override = sub.notif_name_override.as_ref().map(|m| self.rpc_identifier(m)); // Name of the RPC method to unsubscribe (e.g. `foo_sub`). let rpc_unsub_name = self.rpc_identifier(&sub.unsubscribe); // `parsing` is the code associated with parsing structure from the @@ -184,8 +186,16 @@ impl RpcDescription { check_name(&rpc_sub_name, rust_method_name.span()); check_name(&rpc_unsub_name, rust_method_name.span()); + let rpc_notif_name = match rpc_notif_name_override { + Some(notif) => { + check_name(¬if, rust_method_name.span()); + notif + } + None => rpc_sub_name.clone(), + }; + handle_register_result(quote! { - rpc.register_subscription(#rpc_sub_name, #rpc_unsub_name, |params, sink, context| { + rpc.register_subscription(#rpc_sub_name, #rpc_notif_name, #rpc_unsub_name, |params, sink, context| { #parsing context.as_ref().#rust_method_name(sink, #params_seq) }) diff --git a/proc-macros/src/rpc_macro.rs b/proc-macros/src/rpc_macro.rs index be251cae00..156f2f051b 100644 --- a/proc-macros/src/rpc_macro.rs +++ b/proc-macros/src/rpc_macro.rs @@ -27,7 +27,9 @@ //! Declaration of the JSON RPC generator procedural macros. use crate::{ - attributes::{optional, parse_param_kind, Aliases, Argument, AttributeMeta, MissingArgument, ParamKind, Resource}, + attributes::{ + optional, parse_param_kind, Aliases, Argument, AttributeMeta, MissingArgument, NameMapping, ParamKind, Resource, + }, helpers::extract_doc_comments, }; @@ -95,6 +97,13 @@ impl RpcMethod { #[derive(Debug, Clone)] pub struct RpcSubscription { pub name: String, + /// When subscribing to an RPC, users can override the content of the `method` field + /// in the JSON data sent to subscribers. + /// Each subscription thus has one method name to set up the subscription, + /// one to unsubscribe and, optionally, a third method name used to describe the + /// payload (aka "notification") sent back from the server to subscribers. + /// If no override is provided, the subscription method name is used. + pub notif_name_override: Option, pub docs: TokenStream2, pub unsubscribe: String, pub params: Vec<(syn::PatIdent, syn::Type)>, @@ -111,7 +120,9 @@ impl RpcSubscription { AttributeMeta::parse(attr)?.retain(["aliases", "item", "name", "param_kind", "unsubscribe_aliases"])?; let aliases = parse_aliases(aliases)?; - let name = name?.string()?; + let map = name?.value::()?; + let name = map.name; + let notif_name_override = map.mapped; let item = item?.value()?; let param_kind = parse_param_kind(param_kind)?; let unsubscribe_aliases = parse_aliases(unsubscribe_aliases)?; @@ -135,7 +146,18 @@ impl RpcSubscription { // We've analyzed attributes and don't need them anymore. sub.attrs.clear(); - Ok(Self { name, unsubscribe, unsubscribe_aliases, params, param_kind, item, signature: sub, aliases, docs }) + Ok(Self { + name, + notif_name_override, + unsubscribe, + unsubscribe_aliases, + params, + param_kind, + item, + signature: sub, + aliases, + docs, + }) } } diff --git a/proc-macros/tests/ui/correct/basic.rs b/proc-macros/tests/ui/correct/basic.rs index c8052ce288..05b062b88a 100644 --- a/proc-macros/tests/ui/correct/basic.rs +++ b/proc-macros/tests/ui/correct/basic.rs @@ -31,6 +31,11 @@ pub trait Rpc { #[subscription(name = "echo", 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` + // because it's in the `foo` namespace. + #[subscription(name = "subscribe_method" => "subscribe_override", item = u32)] + fn sub_with_override_notif_method(&self) -> RpcResult<()>; } pub struct RpcServerImpl; @@ -68,6 +73,10 @@ impl RpcServer for RpcServerImpl { sink.send(&val)?; sink.send(&val) } + + fn sub_with_override_notif_method(&self, mut sink: SubscriptionSink) -> RpcResult<()> { + sink.send(&1) + } } pub async fn websocket_server() -> SocketAddr { @@ -102,4 +111,8 @@ async fn main() { assert_eq!(first_recv, Some("Response_A".to_string())); let second_recv = sub.next().await.unwrap(); assert_eq!(second_recv, Some("Response_B".to_string())); + + let mut sub = client.sub_with_override_notif_method().await.unwrap(); + let recv = sub.next().await.unwrap(); + assert_eq!(recv, Some(1)); } diff --git a/proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.rs b/proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.rs new file mode 100644 index 0000000000..53adf3fe2e --- /dev/null +++ b/proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.rs @@ -0,0 +1,12 @@ +use jsonrpsee::{proc_macros::rpc, types::RpcResult}; + +// Subscription method must not use the same override name. +#[rpc(client, server)] +pub trait DupOverride { + #[subscription(name = "one" => "override", item = u8)] + fn one(&self) -> RpcResult<()>; + #[subscription(name = "two" => "override", item = u8)] + fn two(&self) -> RpcResult<()>; +} + +fn main() {} diff --git a/proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.stderr b/proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.stderr new file mode 100644 index 0000000000..a34210fe70 --- /dev/null +++ b/proc-macros/tests/ui/incorrect/sub/sub_dup_name_override.stderr @@ -0,0 +1,5 @@ +error: "override" is already defined + --> tests/ui/incorrect/sub/sub_dup_name_override.rs:9:5 + | +9 | fn two(&self) -> RpcResult<()>; + | ^^^ diff --git a/proc-macros/tests/ui/incorrect/sub/sub_name_override.rs b/proc-macros/tests/ui/incorrect/sub/sub_name_override.rs new file mode 100644 index 0000000000..740b30699f --- /dev/null +++ b/proc-macros/tests/ui/incorrect/sub/sub_name_override.rs @@ -0,0 +1,10 @@ +use jsonrpsee::{proc_macros::rpc, types::RpcResult}; + +// Subscription method name conflict with notif override. +#[rpc(client, server)] +pub trait DupName { + #[subscription(name = "one" => "one", item = u8)] + fn one(&self) -> RpcResult<()>; +} + +fn main() {} diff --git a/proc-macros/tests/ui/incorrect/sub/sub_name_override.stderr b/proc-macros/tests/ui/incorrect/sub/sub_name_override.stderr new file mode 100644 index 0000000000..719b2e88cf --- /dev/null +++ b/proc-macros/tests/ui/incorrect/sub/sub_name_override.stderr @@ -0,0 +1,5 @@ +error: "one" is already defined + --> tests/ui/incorrect/sub/sub_name_override.rs:7:5 + | +7 | fn one(&self) -> RpcResult<()>; + | ^^^ diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index a9773522f4..7df1d923e6 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -40,7 +40,7 @@ pub async fn websocket_server_with_subscription() -> (SocketAddr, WsServerHandle module.register_method("say_hello", |_, _| Ok("hello")).unwrap(); module - .register_subscription("subscribe_hello", "unsubscribe_hello", |_, mut sink, _| { + .register_subscription("subscribe_hello", "subscribe_hello", "unsubscribe_hello", |_, mut sink, _| { std::thread::spawn(move || loop { if let Err(Error::SubscriptionClosed(_)) = sink.send(&"hello from subscription") { break; @@ -52,7 +52,7 @@ pub async fn websocket_server_with_subscription() -> (SocketAddr, WsServerHandle .unwrap(); module - .register_subscription("subscribe_foo", "unsubscribe_foo", |_, mut sink, _| { + .register_subscription("subscribe_foo", "subscribe_foo", "unsubscribe_foo", |_, mut sink, _| { std::thread::spawn(move || loop { if let Err(Error::SubscriptionClosed(_)) = sink.send(&1337) { break; @@ -64,21 +64,26 @@ pub async fn websocket_server_with_subscription() -> (SocketAddr, WsServerHandle .unwrap(); module - .register_subscription("subscribe_add_one", "unsubscribe_add_one", |params, mut sink, _| { - let mut count: usize = params.one()?; - std::thread::spawn(move || loop { - count = count.wrapping_add(1); - if let Err(Error::SubscriptionClosed(_)) = sink.send(&count) { - break; - } - std::thread::sleep(Duration::from_millis(100)); - }); - Ok(()) - }) + .register_subscription( + "subscribe_add_one", + "subscribe_add_one", + "unsubscribe_add_one", + |params, mut sink, _| { + let mut count: usize = params.one()?; + std::thread::spawn(move || loop { + count = count.wrapping_add(1); + if let Err(Error::SubscriptionClosed(_)) = sink.send(&count) { + break; + } + std::thread::sleep(Duration::from_millis(100)); + }); + Ok(()) + }, + ) .unwrap(); module - .register_subscription("subscribe_noop", "unsubscribe_noop", |_, mut sink, _| { + .register_subscription("subscribe_noop", "subscribe_noop", "unsubscribe_noop", |_, mut sink, _| { std::thread::spawn(move || { std::thread::sleep(Duration::from_secs(1)); sink.close("Server closed the stream because it was lazy") diff --git a/tests/tests/integration_tests.rs b/tests/tests/integration_tests.rs index 118c270a81..267a8205ca 100644 --- a/tests/tests/integration_tests.rs +++ b/tests/tests/integration_tests.rs @@ -332,7 +332,7 @@ async fn ws_server_should_stop_subscription_after_client_drop() { let mut module = RpcModule::new(tx); module - .register_subscription("subscribe_hello", "unsubscribe_hello", |_, mut sink, mut tx| { + .register_subscription("subscribe_hello", "subscribe_hello", "unsubscribe_hello", |_, mut sink, mut tx| { tokio::spawn(async move { let close_err = loop { if let Err(Error::SubscriptionClosed(err)) = sink.send(&1) { diff --git a/tests/tests/proc_macros.rs b/tests/tests/proc_macros.rs index 2597e8caf1..08d2ce9a64 100644 --- a/tests/tests/proc_macros.rs +++ b/tests/tests/proc_macros.rs @@ -312,7 +312,7 @@ async fn multiple_blocking_calls_overlap() { #[tokio::test] async fn subscriptions_do_not_work_for_http_servers() { - let htserver = HttpServerBuilder::default().build("127.0.0.1:0".parse().unwrap()).unwrap(); + let htserver = HttpServerBuilder::default().build("127.0.0.1:0").unwrap(); let addr = htserver.local_addr().unwrap(); let htserver_url = format!("http://{}", addr); let _handle = htserver.start(RpcServerImpl.into_rpc()).unwrap(); diff --git a/utils/src/server/rpc_module.rs b/utils/src/server/rpc_module.rs index 4652962c60..294b7f9a72 100644 --- a/utils/src/server/rpc_module.rs +++ b/utils/src/server/rpc_module.rs @@ -516,9 +516,20 @@ impl RpcModule { Ok(MethodResourcesBuilder { build: ResourceVec::new(), callback }) } - /// Register a new RPC subscription that invokes callback on every subscription request. - /// The callback itself takes three parameters: - /// - [`Params`]: JSONRPC parameters in the subscription request. + /// Register a new RPC subscription that invokes s callback on every subscription call. + /// + /// This method ensures that the `subscription_method_name` and `unsubscription_method_name` are unique. + /// The `notif_method_name` argument sets the content of the `method` field in the JSON document that + /// the server sends back to the client. The uniqueness of this value is not machine checked and it's up to + /// the user to ensure it is not used in any other [`RpcModule`] used in the server. + /// + /// # Arguments + /// + /// * `subscription_method_name` - name of the method to call to initiate a subscription + /// * `notif_method_name` - name of method to be used in the subscription payload (technically a JSON-RPC notification) + /// * `unsubscription_method` - name of the method to call to terminate a subscription + /// * `callback` - A callback to invoke on each subscription; it takes three parameters: + /// - [`Params`]: JSON-RPC parameters in the subscription call. /// - [`SubscriptionSink`]: A sink to send messages to the subscriber. /// - Context: Any type that can be embedded into the [`RpcModule`]. /// @@ -529,7 +540,7 @@ impl RpcModule { /// use jsonrpsee_utils::server::rpc_module::RpcModule; /// /// let mut ctx = RpcModule::new(99_usize); - /// ctx.register_subscription("sub", "unsub", |params, mut sink, ctx| { + /// ctx.register_subscription("sub", "notif_name", "unsub", |params, mut sink, ctx| { /// let x: usize = params.one()?; /// std::thread::spawn(move || { /// let sum = x + (*ctx); @@ -541,6 +552,7 @@ impl RpcModule { pub fn register_subscription( &mut self, subscribe_method_name: &'static str, + notif_method_name: &'static str, unsubscribe_method_name: &'static str, callback: F, ) -> Result<(), Error> @@ -554,6 +566,7 @@ impl RpcModule { self.methods.verify_method_name(subscribe_method_name)?; self.methods.verify_method_name(unsubscribe_method_name)?; + let ctx = self.ctx.clone(); let subscribers = Subscribers::default(); @@ -577,7 +590,7 @@ impl RpcModule { let sink = SubscriptionSink { inner: method_sink.clone(), - method: subscribe_method_name, + method: notif_method_name, subscribers: subscribers.clone(), uniq_sub: SubscriptionKey { conn_id, sub_id }, is_connected: Some(conn_tx), @@ -784,7 +797,7 @@ mod tests { fn rpc_context_modules_can_register_subscriptions() { let cx = (); let mut cxmodule = RpcModule::new(cx); - let _subscription = cxmodule.register_subscription("hi", "goodbye", |_, _, _| Ok(())); + let _subscription = cxmodule.register_subscription("hi", "hi", "goodbye", |_, _, _| Ok(())); assert!(cxmodule.method("hi").is_some()); assert!(cxmodule.method("goodbye").is_some()); @@ -922,7 +935,7 @@ mod tests { async fn subscribing_without_server() { let mut module = RpcModule::new(()); module - .register_subscription("my_sub", "my_unsub", |_, mut sink, _| { + .register_subscription("my_sub", "my_sub", "my_unsub", |_, mut sink, _| { let mut stream_data = vec!['0', '1', '2']; std::thread::spawn(move || loop { tracing::debug!("This is your friendly subscription sending data."); @@ -956,7 +969,7 @@ mod tests { async fn close_test_subscribing_without_server() { let mut module = RpcModule::new(()); module - .register_subscription("my_sub", "my_unsub", |_, mut sink, _| { + .register_subscription("my_sub", "my_sub", "my_unsub", |_, mut sink, _| { std::thread::spawn(move || loop { if let Err(Error::SubscriptionClosed(_)) = sink.send(&"lo") { return; diff --git a/ws-server/src/tests.rs b/ws-server/src/tests.rs index 121cbdf7fb..67e5f36f66 100644 --- a/ws-server/src/tests.rs +++ b/ws-server/src/tests.rs @@ -117,7 +117,7 @@ async fn server_with_handles() -> (SocketAddr, ServerHandle) { }) .unwrap(); module - .register_subscription("subscribe_hello", "unsubscribe_hello", |_, sink, _| { + .register_subscription("subscribe_hello", "subscribe_hello", "unsubscribe_hello", |_, sink, _| { std::thread::spawn(move || loop { let _ = sink; std::thread::sleep(std::time::Duration::from_secs(30)); @@ -472,8 +472,12 @@ 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_subscription("subscribe_hello", "unsubscribe_hello", |_, _, _| Ok(())).is_ok()); - assert!(module.register_subscription("subscribe_hello_again", "unsubscribe_hello", |_, _, _| Ok(())).is_err()); + assert!(module + .register_subscription("subscribe_hello", "subscribe_hello", "unsubscribe_hello", |_, _, _| Ok(())) + .is_ok()); + assert!(module + .register_subscription("subscribe_hello_again", "subscribe_hello_again", "unsubscribe_hello", |_, _, _| Ok(())) + .is_err()); assert!( module.register_method("subscribe_hello_again", |_, _| Ok("lo")).is_ok(), "Failed register_subscription should not have side-effects" @@ -484,7 +488,7 @@ async fn register_methods_works() { async fn register_same_subscribe_unsubscribe_is_err() { let mut module = RpcModule::new(()); assert!(matches!( - module.register_subscription("subscribe_hello", "subscribe_hello", |_, _, _| Ok(())), + module.register_subscription("subscribe_hello", "subscribe_hello", "subscribe_hello", |_, _, _| Ok(())), Err(Error::SubscriptionNameConflict(_)) )); }