From 26ec635add815507065ca535e2fe466d9c180836 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 14:54:27 +0200 Subject: [PATCH 01/32] server: Add a raw method Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 6 ++++++ server/src/middleware/rpc/layer/rpc_service.rs | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 0a68638f54..4ffca5ff5d 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -60,6 +60,8 @@ pub type SyncMethod = Arc M /// Similar to [`SyncMethod`], but represents an asynchronous handler. pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; +/// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. +pub type RawMethod = Arc MethodResponse>; /// Method callback for subscriptions. pub type SubscriptionMethod<'a> = Arc BoxFuture<'a, MethodResponse>>; @@ -131,6 +133,8 @@ pub enum MethodCallback { Sync(SyncMethod), /// Asynchronous method handler. Async(AsyncMethod<'static>), + /// Raw method handler. + Raw(RawMethod), /// Subscription method handler. Subscription(SubscriptionMethod<'static>), /// Unsubscription method handler. @@ -185,6 +189,7 @@ impl Debug for MethodCallback { match self { Self::Async(_) => write!(f, "Async"), Self::Sync(_) => write!(f, "Sync"), + Self::Raw(_) => write!(f, "Raw"), Self::Subscription(_) => write!(f, "Subscription"), Self::Unsubscription(_) => write!(f, "Unsubscription"), } @@ -355,6 +360,7 @@ impl Methods { None => MethodResponse::error(req.id, ErrorObject::from(ErrorCode::MethodNotFound)), Some(MethodCallback::Sync(cb)) => (cb)(id, params, usize::MAX), Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, + Some(MethodCallback::Raw(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX), Some(MethodCallback::Subscription(cb)) => { let conn_state = SubscriptionState { conn_id: 0, id_provider: &RandomIntegerIdProvider, subscription_permit }; diff --git a/server/src/middleware/rpc/layer/rpc_service.rs b/server/src/middleware/rpc/layer/rpc_service.rs index 061908801a..cb93153921 100644 --- a/server/src/middleware/rpc/layer/rpc_service.rs +++ b/server/src/middleware/rpc/layer/rpc_service.rs @@ -98,6 +98,10 @@ impl<'a> RpcServiceT<'a> for RpcService { let rp = (callback)(id, params, max_response_body_size); ResponseFuture::ready(rp) } + MethodCallback::Raw(callback) => { + let rp = (callback)(id, params, conn_id, max_response_body_size); + ResponseFuture::ready(rp) + } MethodCallback::Subscription(callback) => { let RpcServiceCfg::CallsAndSubscriptions { bounded_subscriptions, From ef24148962a00111aa93a6f8a0b045cc0c1bf3dc Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 15:05:08 +0200 Subject: [PATCH 02/32] server: Register raw methods, blocking or unblocking Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 64 ++++++++++++++++++- .../src/middleware/rpc/layer/rpc_service.rs | 7 +- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 4ffca5ff5d..9e25f551ac 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -61,7 +61,8 @@ pub type SyncMethod = Arc M pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. -pub type RawMethod = Arc MethodResponse>; +pub type RawMethod<'a> = + Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Method callback for subscriptions. pub type SubscriptionMethod<'a> = Arc BoxFuture<'a, MethodResponse>>; @@ -134,7 +135,7 @@ pub enum MethodCallback { /// Asynchronous method handler. Async(AsyncMethod<'static>), /// Raw method handler. - Raw(RawMethod), + Raw(RawMethod<'static>), /// Subscription method handler. Subscription(SubscriptionMethod<'static>), /// Unsubscription method handler. @@ -360,7 +361,7 @@ impl Methods { None => MethodResponse::error(req.id, ErrorObject::from(ErrorCode::MethodNotFound)), Some(MethodCallback::Sync(cb)) => (cb)(id, params, usize::MAX), Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, - Some(MethodCallback::Raw(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX), + Some(MethodCallback::Raw(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, Some(MethodCallback::Subscription(cb)) => { let conn_state = SubscriptionState { conn_id: 0, id_provider: &RandomIntegerIdProvider, subscription_permit }; @@ -604,6 +605,63 @@ impl RpcModule { Ok(callback) } + /// Register a new raw RPC method, which computes the response with the given callback. + /// + /// ## Examples + /// + /// ``` + /// use jsonrpsee_core::server::RpcModule; + /// + /// let mut module = RpcModule::new(()); + /// module.register_raw_method("say_hello", false, |_params, _connection_id, _ctx| "lo").unwrap(); + /// ``` + pub fn register_raw_method( + &mut self, + method_name: &'static str, + blocking: bool, + callback: F, + ) -> Result<&mut MethodCallback, RegisterMethodError> + where + Context: Send + Sync + 'static, + R: IntoResponse + 'static, + F: Fn(Params, usize, Arc) -> R + Clone + Send + Sync + 'static, + { + let ctx = self.ctx.clone(); + if blocking { + let callback = self.methods.verify_and_insert( + method_name, + MethodCallback::Raw(Arc::new(move |id, params, connection_id, max_response_size| { + let ctx = ctx.clone(); + let callback = callback.clone(); + + tokio::task::spawn_blocking(move || { + let rp = callback(params, connection_id, ctx).into_response(); + MethodResponse::response(id, rp, max_response_size) + }) + .map(|result| match result { + Ok(r) => r, + Err(err) => { + tracing::error!(target: LOG_TARGET, "Join error for blocking RPC method: {:?}", err); + MethodResponse::error(Id::Null, ErrorObject::from(ErrorCode::InternalError)) + } + }) + .boxed() + })), + )?; + + return Ok(callback); + } + + self.methods.verify_and_insert( + method_name, + MethodCallback::Raw(Arc::new(move |id, params, connection_id, max_response_size| { + let ctx = ctx.clone(); + let rp = callback(params, connection_id, ctx).into_response(); + futures_util::future::ready(MethodResponse::response(id, rp, max_response_size)).boxed() + })), + ) + } + /// Register a new publish/subscribe interface using JSON-RPC notifications. /// /// It implements the [ethereum pubsub specification](https://geth.ethereum.org/docs/rpc/pubsub) diff --git a/server/src/middleware/rpc/layer/rpc_service.rs b/server/src/middleware/rpc/layer/rpc_service.rs index cb93153921..eb532ddf5c 100644 --- a/server/src/middleware/rpc/layer/rpc_service.rs +++ b/server/src/middleware/rpc/layer/rpc_service.rs @@ -99,8 +99,11 @@ impl<'a> RpcServiceT<'a> for RpcService { ResponseFuture::ready(rp) } MethodCallback::Raw(callback) => { - let rp = (callback)(id, params, conn_id, max_response_body_size); - ResponseFuture::ready(rp) + let params = params.into_owned(); + let id = id.into_owned(); + + let fut = (callback)(id, params, conn_id, max_response_body_size); + ResponseFuture::future(fut) } MethodCallback::Subscription(callback) => { let RpcServiceCfg::CallsAndSubscriptions { From 4f8eb03fad5d655424e03e353d1451456f3bce63 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 16:48:16 +0200 Subject: [PATCH 03/32] proc-macros: Add with-context attribute Signed-off-by: Alexandru Vasile --- proc-macros/src/render_server.rs | 42 +++++++++++++++++++++++--------- proc-macros/src/rpc_macro.rs | 15 ++++++++++-- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index eddb9e3d99..d97e46396d 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -62,7 +62,15 @@ impl RpcDescription { fn render_methods(&self) -> Result { let methods = self.methods.iter().map(|method| { let docs = &method.docs; - let method_sig = &method.signature; + let mut method_sig = method.signature.clone(); + + if self.with_context { + let context_ty = self.jrps_server_item(quote! { ConnectionId }); + // Add `connection ID` as the second input parameter to the signature. + let context: syn::FnArg = syn::parse_quote!(connection_context: #context_ty); + method_sig.sig.inputs.insert(1, context); + } + quote! { #docs #method_sig @@ -133,23 +141,35 @@ impl RpcDescription { check_name(&rpc_method_name, rust_method_name.span()); - if method.signature.sig.asyncness.is_some() { + if self.with_context { + let blocking = if method.blocking { quote!(true) } else { quote!(false) }; + let maybe_await = if method.signature.sig.asyncness.is_some() { quote!(.await) } else { quote!() }; + handle_register_result(quote! { - rpc.register_async_method(#rpc_method_name, |params, context| async move { + rpc.register_raw_method(#rpc_method_name, #blocking, |params, connection_id, context| async move { #parsing - #into_response::into_response(context.as_ref().#rust_method_name(#params_seq).await) + #into_response::into_response(context.as_ref().#rust_method_name(connection_id, #params_seq) #maybe_await) }) }) } else { - let register_kind = - if method.blocking { quote!(register_blocking_method) } else { quote!(register_method) }; + if method.signature.sig.asyncness.is_some() { + handle_register_result(quote! { + rpc.register_async_method(#rpc_method_name, |params, context| async move { + #parsing + #into_response::into_response(context.as_ref().#rust_method_name(#params_seq).await) + }) + }) + } else { + let register_kind = + if method.blocking { quote!(register_blocking_method) } else { quote!(register_method) }; - handle_register_result(quote! { - rpc.#register_kind(#rpc_method_name, |params, context| { - #parsing - #into_response::into_response(context.#rust_method_name(#params_seq)) + handle_register_result(quote! { + rpc.#register_kind(#rpc_method_name, |params, context| { + #parsing + #into_response::into_response(context.#rust_method_name(#params_seq)) + }) }) - }) + } } }) .collect::>(); diff --git a/proc-macros/src/rpc_macro.rs b/proc-macros/src/rpc_macro.rs index 693ec2ad23..338ca9c29d 100644 --- a/proc-macros/src/rpc_macro.rs +++ b/proc-macros/src/rpc_macro.rs @@ -188,6 +188,8 @@ pub struct RpcDescription { /// Assuming that trait to which attribute is applied is named `Foo`, the generated /// client trait will have `FooClient` name. pub(crate) needs_client: bool, + /// Expose the server methods with additional connection context. + pub(crate) with_context: bool, /// Optional prefix for RPC namespace. pub(crate) namespace: Option, /// Trait definition in which all the attributes were stripped. @@ -204,19 +206,27 @@ pub struct RpcDescription { impl RpcDescription { pub fn from_item(attr: Attribute, mut item: syn::ItemTrait) -> syn::Result { - let [client, server, namespace, client_bounds, server_bounds] = - AttributeMeta::parse(attr)?.retain(["client", "server", "namespace", "client_bounds", "server_bounds"])?; + let [client, server, namespace, client_bounds, server_bounds, with_context] = AttributeMeta::parse(attr)? + .retain(["client", "server", "namespace", "client_bounds", "server_bounds", "with_context"])?; let needs_server = optional(server, Argument::flag)?.is_some(); let needs_client = optional(client, Argument::flag)?.is_some(); let namespace = optional(namespace, Argument::string)?; let client_bounds = optional(client_bounds, Argument::group)?; let server_bounds = optional(server_bounds, Argument::group)?; + let with_context = optional(with_context, Argument::flag)?.is_some(); if !needs_server && !needs_client { return Err(syn::Error::new_spanned(&item.ident, "Either 'server' or 'client' attribute must be applied")); } + if !needs_server && with_context { + return Err(syn::Error::new_spanned( + &item.ident, + "Attribute 'with_context' must be specified with 'server'", + )); + } + if client_bounds.is_some() && !needs_client { return Err(syn::Error::new_spanned( &item.ident, @@ -295,6 +305,7 @@ impl RpcDescription { jsonrpsee_server_path, needs_server, needs_client, + with_context, namespace, trait_def: item, methods, From 9eba8999f3f4e0ea560f097430bf677abd234fe8 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 17:20:19 +0200 Subject: [PATCH 04/32] server: Register sync and nonblocking methods for raw API Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 40 +++---------------- proc-macros/src/render_server.rs | 7 ++-- proc-macros/src/rpc_macro.rs | 15 +++++++ .../src/middleware/rpc/layer/rpc_service.rs | 7 +--- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 9e25f551ac..36db4b8b79 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -61,8 +61,7 @@ pub type SyncMethod = Arc M pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. -pub type RawMethod<'a> = - Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; +pub type RawMethod = Arc MethodResponse>; /// Method callback for subscriptions. pub type SubscriptionMethod<'a> = Arc BoxFuture<'a, MethodResponse>>; @@ -135,7 +134,7 @@ pub enum MethodCallback { /// Asynchronous method handler. Async(AsyncMethod<'static>), /// Raw method handler. - Raw(RawMethod<'static>), + Raw(RawMethod), /// Subscription method handler. Subscription(SubscriptionMethod<'static>), /// Unsubscription method handler. @@ -361,7 +360,7 @@ impl Methods { None => MethodResponse::error(req.id, ErrorObject::from(ErrorCode::MethodNotFound)), Some(MethodCallback::Sync(cb)) => (cb)(id, params, usize::MAX), Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, - Some(MethodCallback::Raw(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, + Some(MethodCallback::Raw(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX), Some(MethodCallback::Subscription(cb)) => { let conn_state = SubscriptionState { conn_id: 0, id_provider: &RandomIntegerIdProvider, subscription_permit }; @@ -618,46 +617,19 @@ impl RpcModule { pub fn register_raw_method( &mut self, method_name: &'static str, - blocking: bool, callback: F, ) -> Result<&mut MethodCallback, RegisterMethodError> where Context: Send + Sync + 'static, R: IntoResponse + 'static, - F: Fn(Params, usize, Arc) -> R + Clone + Send + Sync + 'static, + F: Fn(Params, ConnectionId, &Context) -> R + Send + Sync + 'static, { let ctx = self.ctx.clone(); - if blocking { - let callback = self.methods.verify_and_insert( - method_name, - MethodCallback::Raw(Arc::new(move |id, params, connection_id, max_response_size| { - let ctx = ctx.clone(); - let callback = callback.clone(); - - tokio::task::spawn_blocking(move || { - let rp = callback(params, connection_id, ctx).into_response(); - MethodResponse::response(id, rp, max_response_size) - }) - .map(|result| match result { - Ok(r) => r, - Err(err) => { - tracing::error!(target: LOG_TARGET, "Join error for blocking RPC method: {:?}", err); - MethodResponse::error(Id::Null, ErrorObject::from(ErrorCode::InternalError)) - } - }) - .boxed() - })), - )?; - - return Ok(callback); - } - self.methods.verify_and_insert( method_name, MethodCallback::Raw(Arc::new(move |id, params, connection_id, max_response_size| { - let ctx = ctx.clone(); - let rp = callback(params, connection_id, ctx).into_response(); - futures_util::future::ready(MethodResponse::response(id, rp, max_response_size)).boxed() + let rp = callback(params, connection_id, &*ctx).into_response(); + MethodResponse::response(id, rp, max_response_size) })), ) } diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index d97e46396d..f50d5eb48b 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -142,13 +142,12 @@ impl RpcDescription { check_name(&rpc_method_name, rust_method_name.span()); if self.with_context { - let blocking = if method.blocking { quote!(true) } else { quote!(false) }; - let maybe_await = if method.signature.sig.asyncness.is_some() { quote!(.await) } else { quote!() }; + handle_register_result(quote! { - rpc.register_raw_method(#rpc_method_name, #blocking, |params, connection_id, context| async move { + rpc.register_raw_method(#rpc_method_name, |params, connection_id, context| { #parsing - #into_response::into_response(context.as_ref().#rust_method_name(connection_id, #params_seq) #maybe_await) + #into_response::into_response(context.#rust_method_name(connection_id, #params_seq)) }) }) } else { diff --git a/proc-macros/src/rpc_macro.rs b/proc-macros/src/rpc_macro.rs index 338ca9c29d..3a4fc19f8c 100644 --- a/proc-macros/src/rpc_macro.rs +++ b/proc-macros/src/rpc_macro.rs @@ -270,6 +270,14 @@ impl RpcDescription { is_method = true; let method_data = RpcMethod::from_item(attr.clone(), method.clone())?; + + if method_data.blocking && with_context { + return Err(syn::Error::new_spanned( + method, + "Methods cannot be blocking when used with `with_context`; remove `blocking` attribute or `with_context` attribute", + )); + } + methods.push(method_data); } if let Some(attr) = find_attr(&method.attrs, "subscription") { @@ -291,6 +299,13 @@ impl RpcDescription { "Methods must have either 'method' or 'subscription' attribute", )); } + + if is_method && method.sig.asyncness.is_some() && with_context { + return Err(syn::Error::new_spanned( + method, + "Methods must be synchronous when used with `with_context`; use `fn` instead of `async fn`", + )); + } } else { return Err(syn::Error::new_spanned(entry, "Only methods allowed in RPC traits")); } diff --git a/server/src/middleware/rpc/layer/rpc_service.rs b/server/src/middleware/rpc/layer/rpc_service.rs index eb532ddf5c..cb93153921 100644 --- a/server/src/middleware/rpc/layer/rpc_service.rs +++ b/server/src/middleware/rpc/layer/rpc_service.rs @@ -99,11 +99,8 @@ impl<'a> RpcServiceT<'a> for RpcService { ResponseFuture::ready(rp) } MethodCallback::Raw(callback) => { - let params = params.into_owned(); - let id = id.into_owned(); - - let fut = (callback)(id, params, conn_id, max_response_body_size); - ResponseFuture::future(fut) + let rp = (callback)(id, params, conn_id, max_response_body_size); + ResponseFuture::ready(rp) } MethodCallback::Subscription(callback) => { let RpcServiceCfg::CallsAndSubscriptions { From 239cafecd7a6f476d8135aa2c2eff9ce9910852a Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 17:24:16 +0200 Subject: [PATCH 05/32] examples: Add with context example Signed-off-by: Alexandru Vasile --- examples/examples/server_with_context.rs | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 examples/examples/server_with_context.rs diff --git a/examples/examples/server_with_context.rs b/examples/examples/server_with_context.rs new file mode 100644 index 0000000000..94dd7d339d --- /dev/null +++ b/examples/examples/server_with_context.rs @@ -0,0 +1,129 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the +// Software without restriction, including without +// limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice +// shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use std::net::SocketAddr; + +use jsonrpsee::core::{async_trait, client::Subscription, SubscriptionResult}; +use jsonrpsee::proc_macros::rpc; +use jsonrpsee::server::{PendingSubscriptionSink, Server, SubscriptionMessage}; +use jsonrpsee::types::ErrorObjectOwned; +use jsonrpsee::ws_client::WsClientBuilder; +use jsonrpsee::ConnectionId; + +type ExampleHash = [u8; 32]; +type ExampleStorageKey = Vec; + +#[rpc(server, client, with_context)] +pub trait Rpc +where + Hash: std::fmt::Debug, +{ + /// Async method call example. + #[method(name = "getKeys")] + fn storage_keys(&self, storage_key: StorageKey, hash: Option) -> Result; + + /// Subscription that takes a `StorageKey` as input and produces a `Vec`. + #[subscription(name = "subscribeStorage" => "override", item = Vec)] + async fn subscribe_storage(&self, keys: Option>) -> SubscriptionResult; + + #[subscription(name = "subscribeSync" => "sync", item = Vec)] + fn s(&self, keys: Option>); +} + +pub struct RpcServerImpl; + +#[async_trait] +impl RpcServer for RpcServerImpl { + fn storage_keys( + &self, + connection_id: ConnectionId, + _storage_key: ExampleStorageKey, + _hash: Option, + ) -> Result { + Ok(connection_id) + } + + async fn subscribe_storage( + &self, + pending: PendingSubscriptionSink, + _keys: Option>, + ) -> SubscriptionResult { + let sink = pending.accept().await?; + let msg = SubscriptionMessage::from_json(&vec![[0; 32]])?; + sink.send(msg).await?; + + Ok(()) + } + + fn s(&self, pending: PendingSubscriptionSink, _keys: Option>) { + tokio::spawn(async move { + let sink = pending.accept().await.unwrap(); + let msg = SubscriptionMessage::from_json(&vec![[0; 32]]).unwrap(); + sink.send(msg).await.unwrap(); + }); + } +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::FmtSubscriber::builder() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init() + .expect("setting default subscriber failed"); + + let server_addr = run_server().await?; + let url = format!("ws://{}", server_addr); + + let client = WsClientBuilder::default().build(&url).await?; + let connection_id_first = client.storage_keys(vec![1, 2, 3, 4], None::).await.unwrap(); + + // Second call from the same connection ID. + assert_eq!(client.storage_keys(vec![1, 2, 3, 4], None::).await.unwrap(), connection_id_first); + + // Second client will increment the connection ID. + let client_second = WsClientBuilder::default().build(&url).await?; + let connection_id_second = client_second.storage_keys(vec![1, 2, 3, 4], None::).await.unwrap(); + assert_ne!(connection_id_first, connection_id_second); + + let mut sub: Subscription> = + RpcClient::::subscribe_storage(&client, None).await.unwrap(); + assert_eq!(Some(vec![[0; 32]]), sub.next().await.transpose().unwrap()); + + Ok(()) +} + +async fn run_server() -> anyhow::Result { + let server = Server::builder().build("127.0.0.1:0").await?; + + let addr = server.local_addr()?; + let handle = server.start(RpcServerImpl.into_rpc()); + + // In this example we don't care about doing shutdown so let's it run forever. + // You may use the `ServerHandle` to shut it down or manage it yourself. + tokio::spawn(handle.stopped()); + + Ok(addr) +} From 0de6d95cdfe533f8d0eedf74af6ae75929536810 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 17:55:20 +0200 Subject: [PATCH 06/32] core: Adjust docs for the raw method registering Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 36db4b8b79..7c100cd7dd 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -612,7 +612,7 @@ impl RpcModule { /// use jsonrpsee_core::server::RpcModule; /// /// let mut module = RpcModule::new(()); - /// module.register_raw_method("say_hello", false, |_params, _connection_id, _ctx| "lo").unwrap(); + /// module.register_raw_method("say_hello", |_params, _connection_id, _ctx| "lo").unwrap(); /// ``` pub fn register_raw_method( &mut self, From 4ce51c6658052e2244d82e913eadf2ab8019e6a4 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 21 Feb 2024 18:03:38 +0200 Subject: [PATCH 07/32] proc-macros: Cargo fmt Signed-off-by: Alexandru Vasile --- proc-macros/src/render_server.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index f50d5eb48b..0e51689a5a 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -142,8 +142,6 @@ impl RpcDescription { check_name(&rpc_method_name, rust_method_name.span()); if self.with_context { - - handle_register_result(quote! { rpc.register_raw_method(#rpc_method_name, |params, connection_id, context| { #parsing From 5f2b40a1f4b02565f6d296404f2e42e1cda015bd Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 17:20:46 +0200 Subject: [PATCH 08/32] server: Request Arc for the raw method callback Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 7c100cd7dd..3cff9ad089 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -622,13 +622,14 @@ impl RpcModule { where Context: Send + Sync + 'static, R: IntoResponse + 'static, - F: Fn(Params, ConnectionId, &Context) -> R + Send + Sync + 'static, + F: Fn(Params, ConnectionId, Arc) -> R + Clone + Send + Sync + 'static, { let ctx = self.ctx.clone(); self.methods.verify_and_insert( method_name, MethodCallback::Raw(Arc::new(move |id, params, connection_id, max_response_size| { - let rp = callback(params, connection_id, &*ctx).into_response(); + let ctx = ctx.clone(); + let rp = callback(params, connection_id, ctx).into_response(); MethodResponse::response(id, rp, max_response_size) })), ) From 753224aebb733d7d648e85175018e4f0ba58d5b3 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 17:42:18 +0200 Subject: [PATCH 09/32] proc-macros: Per method raw-method attribute Signed-off-by: Alexandru Vasile --- proc-macros/src/render_server.rs | 4 +-- proc-macros/src/rpc_macro.rs | 49 +++++++++++++++----------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index 0e51689a5a..a20ad23eff 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -64,7 +64,7 @@ impl RpcDescription { let docs = &method.docs; let mut method_sig = method.signature.clone(); - if self.with_context { + if method.raw_method { let context_ty = self.jrps_server_item(quote! { ConnectionId }); // Add `connection ID` as the second input parameter to the signature. let context: syn::FnArg = syn::parse_quote!(connection_context: #context_ty); @@ -141,7 +141,7 @@ impl RpcDescription { check_name(&rpc_method_name, rust_method_name.span()); - if self.with_context { + if method.raw_method { handle_register_result(quote! { rpc.register_raw_method(#rpc_method_name, |params, connection_id, context| { #parsing diff --git a/proc-macros/src/rpc_macro.rs b/proc-macros/src/rpc_macro.rs index 3a4fc19f8c..929b45c780 100644 --- a/proc-macros/src/rpc_macro.rs +++ b/proc-macros/src/rpc_macro.rs @@ -48,17 +48,19 @@ pub struct RpcMethod { pub returns: Option, pub signature: syn::TraitItemMethod, pub aliases: Vec, + pub raw_method: bool, } impl RpcMethod { pub fn from_item(attr: Attribute, mut method: syn::TraitItemMethod) -> syn::Result { - let [aliases, blocking, name, param_kind] = - AttributeMeta::parse(attr)?.retain(["aliases", "blocking", "name", "param_kind"])?; + let [aliases, blocking, name, param_kind, raw_method] = + AttributeMeta::parse(attr)?.retain(["aliases", "blocking", "name", "param_kind", "raw_method"])?; let aliases = parse_aliases(aliases)?; let blocking = optional(blocking, Argument::flag)?.is_some(); let name = name?.string()?; let param_kind = parse_param_kind(param_kind)?; + let raw_method = optional(raw_method, Argument::flag)?.is_some(); let sig = method.sig.clone(); let docs = extract_doc_comments(&method.attrs); @@ -98,7 +100,7 @@ impl RpcMethod { // We've analyzed attributes and don't need them anymore. method.attrs.clear(); - Ok(Self { aliases, blocking, name, params, param_kind, returns, signature: method, docs, deprecated }) + Ok(Self { aliases, blocking, name, params, param_kind, returns, signature: method, docs, deprecated, raw_method }) } } @@ -188,8 +190,6 @@ pub struct RpcDescription { /// Assuming that trait to which attribute is applied is named `Foo`, the generated /// client trait will have `FooClient` name. pub(crate) needs_client: bool, - /// Expose the server methods with additional connection context. - pub(crate) with_context: bool, /// Optional prefix for RPC namespace. pub(crate) namespace: Option, /// Trait definition in which all the attributes were stripped. @@ -206,27 +206,18 @@ pub struct RpcDescription { impl RpcDescription { pub fn from_item(attr: Attribute, mut item: syn::ItemTrait) -> syn::Result { - let [client, server, namespace, client_bounds, server_bounds, with_context] = AttributeMeta::parse(attr)? - .retain(["client", "server", "namespace", "client_bounds", "server_bounds", "with_context"])?; + let [client, server, namespace, client_bounds, server_bounds] = AttributeMeta::parse(attr)? + .retain(["client", "server", "namespace", "client_bounds", "server_bounds"])?; let needs_server = optional(server, Argument::flag)?.is_some(); let needs_client = optional(client, Argument::flag)?.is_some(); let namespace = optional(namespace, Argument::string)?; let client_bounds = optional(client_bounds, Argument::group)?; let server_bounds = optional(server_bounds, Argument::group)?; - let with_context = optional(with_context, Argument::flag)?.is_some(); - if !needs_server && !needs_client { return Err(syn::Error::new_spanned(&item.ident, "Either 'server' or 'client' attribute must be applied")); } - if !needs_server && with_context { - return Err(syn::Error::new_spanned( - &item.ident, - "Attribute 'with_context' must be specified with 'server'", - )); - } - if client_bounds.is_some() && !needs_client { return Err(syn::Error::new_spanned( &item.ident, @@ -271,10 +262,24 @@ impl RpcDescription { let method_data = RpcMethod::from_item(attr.clone(), method.clone())?; - if method_data.blocking && with_context { + if method_data.blocking && method_data.raw_method { + return Err(syn::Error::new_spanned( + method, + "Methods cannot be blocking when used with `raw_method`; remove `blocking` attribute or `raw_method` attribute", + )); + } + + if !needs_server && method_data.raw_method { + return Err(syn::Error::new_spanned( + &item.ident, + "Attribute 'raw_method' must be specified with 'server'", + )); + } + + if method.sig.asyncness.is_some() && method_data.raw_method { return Err(syn::Error::new_spanned( method, - "Methods cannot be blocking when used with `with_context`; remove `blocking` attribute or `with_context` attribute", + "Methods must be synchronous when used with `raw_method`; use `fn` instead of `async fn`", )); } @@ -299,13 +304,6 @@ impl RpcDescription { "Methods must have either 'method' or 'subscription' attribute", )); } - - if is_method && method.sig.asyncness.is_some() && with_context { - return Err(syn::Error::new_spanned( - method, - "Methods must be synchronous when used with `with_context`; use `fn` instead of `async fn`", - )); - } } else { return Err(syn::Error::new_spanned(entry, "Only methods allowed in RPC traits")); } @@ -320,7 +318,6 @@ impl RpcDescription { jsonrpsee_server_path, needs_server, needs_client, - with_context, namespace, trait_def: item, methods, From d526b7097ff58993f1f35344b1938762e7427d66 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:05:58 +0200 Subject: [PATCH 10/32] examples: Add server raw method Signed-off-by: Alexandru Vasile --- ...h_context.rs => server_with_raw_method.rs} | 75 +++++++++---------- 1 file changed, 36 insertions(+), 39 deletions(-) rename examples/examples/{server_with_context.rs => server_with_raw_method.rs} (58%) diff --git a/examples/examples/server_with_context.rs b/examples/examples/server_with_raw_method.rs similarity index 58% rename from examples/examples/server_with_context.rs rename to examples/examples/server_with_raw_method.rs index 94dd7d339d..2b322d077c 100644 --- a/examples/examples/server_with_context.rs +++ b/examples/examples/server_with_raw_method.rs @@ -26,62 +26,57 @@ use std::net::SocketAddr; -use jsonrpsee::core::{async_trait, client::Subscription, SubscriptionResult}; +use jsonrpsee::core::{async_trait, client::Subscription}; use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::{PendingSubscriptionSink, Server, SubscriptionMessage}; use jsonrpsee::types::ErrorObjectOwned; use jsonrpsee::ws_client::WsClientBuilder; use jsonrpsee::ConnectionId; -type ExampleHash = [u8; 32]; -type ExampleStorageKey = Vec; +#[rpc(server, client)] +pub trait Rpc { + /// Raw method with connection ID. + #[method(name = "connectionIdMethod", raw_method)] + fn raw_method(&self, first_param: usize, second_param: u16) -> Result; -#[rpc(server, client, with_context)] -pub trait Rpc -where - Hash: std::fmt::Debug, -{ - /// Async method call example. - #[method(name = "getKeys")] - fn storage_keys(&self, storage_key: StorageKey, hash: Option) -> Result; + /// Normal method call example. + #[method(name = "normalMethod")] + fn normal_method(&self, first_param: usize, second_param: u16) -> Result; - /// Subscription that takes a `StorageKey` as input and produces a `Vec`. - #[subscription(name = "subscribeStorage" => "override", item = Vec)] - async fn subscribe_storage(&self, keys: Option>) -> SubscriptionResult; - - #[subscription(name = "subscribeSync" => "sync", item = Vec)] - fn s(&self, keys: Option>); + /// Subscriptions expose the connection ID on the subscription sink. + #[subscription(name = "subscribeSync" => "sync", item = usize)] + fn sub(&self, first_param: usize); } pub struct RpcServerImpl; #[async_trait] -impl RpcServer for RpcServerImpl { - fn storage_keys( +impl RpcServer for RpcServerImpl { + fn raw_method( &self, connection_id: ConnectionId, - _storage_key: ExampleStorageKey, - _hash: Option, + _first_param: usize, + _second_param: u16, ) -> Result { + // Return the connection ID from which this method was called. Ok(connection_id) } - async fn subscribe_storage( - &self, - pending: PendingSubscriptionSink, - _keys: Option>, - ) -> SubscriptionResult { - let sink = pending.accept().await?; - let msg = SubscriptionMessage::from_json(&vec![[0; 32]])?; - sink.send(msg).await?; - - Ok(()) + fn normal_method(&self, _first_param: usize, _second_param: u16) -> Result { + // The normal method does not have access to the connection ID. + Ok(usize::MAX) } - fn s(&self, pending: PendingSubscriptionSink, _keys: Option>) { + fn sub(&self, pending: PendingSubscriptionSink, _first_param: usize) { tokio::spawn(async move { + // The connection ID can be obtained before or after accepting the subscription + let pending_connection_id = pending.connection_id(); let sink = pending.accept().await.unwrap(); - let msg = SubscriptionMessage::from_json(&vec![[0; 32]]).unwrap(); + let sink_connection_id = sink.connection_id(); + + assert_eq!(pending_connection_id, sink_connection_id); + + let msg = SubscriptionMessage::from_json(&sink_connection_id).unwrap(); sink.send(msg).await.unwrap(); }); } @@ -98,19 +93,21 @@ async fn main() -> anyhow::Result<()> { let url = format!("ws://{}", server_addr); let client = WsClientBuilder::default().build(&url).await?; - let connection_id_first = client.storage_keys(vec![1, 2, 3, 4], None::).await.unwrap(); + let connection_id_first = client.raw_method(1, 2).await.unwrap(); // Second call from the same connection ID. - assert_eq!(client.storage_keys(vec![1, 2, 3, 4], None::).await.unwrap(), connection_id_first); + assert_eq!(client.raw_method(1, 2).await.unwrap(), connection_id_first); // Second client will increment the connection ID. let client_second = WsClientBuilder::default().build(&url).await?; - let connection_id_second = client_second.storage_keys(vec![1, 2, 3, 4], None::).await.unwrap(); + let connection_id_second = client_second.raw_method(1, 2).await.unwrap(); assert_ne!(connection_id_first, connection_id_second); - let mut sub: Subscription> = - RpcClient::::subscribe_storage(&client, None).await.unwrap(); - assert_eq!(Some(vec![[0; 32]]), sub.next().await.transpose().unwrap()); + let mut sub: Subscription = RpcClient::sub(&client, 0).await.unwrap(); + assert_eq!(connection_id_first, sub.next().await.transpose().unwrap().unwrap()); + + let mut sub: Subscription = RpcClient::sub(&client_second, 0).await.unwrap(); + assert_eq!(connection_id_second, sub.next().await.transpose().unwrap().unwrap()); Ok(()) } From c8ff9698ba281164d7fd1371ba27634b7ad7663e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:12:41 +0200 Subject: [PATCH 11/32] tests/ui: Check correct proc-macro behavior Signed-off-by: Alexandru Vasile --- .../tests/ui/correct/server_with_raw_methods.rs | 15 +++++++++++++++ .../method/method_unexpected_field.stderr | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 proc-macros/tests/ui/correct/server_with_raw_methods.rs diff --git a/proc-macros/tests/ui/correct/server_with_raw_methods.rs b/proc-macros/tests/ui/correct/server_with_raw_methods.rs new file mode 100644 index 0000000000..cf1ef6cf07 --- /dev/null +++ b/proc-macros/tests/ui/correct/server_with_raw_methods.rs @@ -0,0 +1,15 @@ +//! Example of using proc macro to generate working client. + +use jsonrpsee::proc_macros::rpc; +use jsonrpsee::types::ErrorObjectOwned; + +#[rpc(server)] +pub trait Rpc { + #[method(name = "foo")] + async fn async_method(&self, param_a: u8, param_b: String) -> Result; + + #[method(name = "bar", raw_method)] + fn sync_method(&self) -> Result; +} + +fn main() {} diff --git a/proc-macros/tests/ui/incorrect/method/method_unexpected_field.stderr b/proc-macros/tests/ui/incorrect/method/method_unexpected_field.stderr index 8fecc8437a..fc19a2111c 100644 --- a/proc-macros/tests/ui/incorrect/method/method_unexpected_field.stderr +++ b/proc-macros/tests/ui/incorrect/method/method_unexpected_field.stderr @@ -1,5 +1,5 @@ -error: Unknown argument `magic`, expected one of: `aliases`, `blocking`, `name`, `param_kind` - --> $DIR/method_unexpected_field.rs:6:25 +error: Unknown argument `magic`, expected one of: `aliases`, `blocking`, `name`, `param_kind`, `raw_method` + --> tests/ui/incorrect/method/method_unexpected_field.rs:6:25 | 6 | #[method(name = "foo", magic = false)] | ^^^^^ From b4880b999dea37bb3ab04a40ea483cda750ecb6e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:15:37 +0200 Subject: [PATCH 12/32] tests/ui: Negative test for async with raw methods Signed-off-by: Alexandru Vasile --- .../ui/incorrect/method/method_async_raw_incompatible.rs | 9 +++++++++ .../method/method_async_raw_incompatible.stderr | 6 ++++++ 2 files changed, 15 insertions(+) create mode 100644 proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs create mode 100644 proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr diff --git a/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs b/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs new file mode 100644 index 0000000000..6b3bcc4f1b --- /dev/null +++ b/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs @@ -0,0 +1,9 @@ +use jsonrpsee::proc_macros::rpc; + +#[rpc(server)] +pub trait AsyncMethodCannotBeRaw { + #[method(name = "a", raw_method)] + async fn a(&self, param: Vec); +} + +fn main() {} diff --git a/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr b/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr new file mode 100644 index 0000000000..75b3c0acc5 --- /dev/null +++ b/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr @@ -0,0 +1,6 @@ +error: Methods must be synchronous when used with `raw_method`; use `fn` instead of `async fn` + --> tests/ui/incorrect/method/method_async_raw_incompatible.rs:5:2 + | +5 | / #[method(name = "a", raw_method)] +6 | | async fn a(&self, param: Vec); + | |______________________________________^ From d2da4b02312d1dd794ddd1f9f9f5db056f9d1fa2 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:17:32 +0200 Subject: [PATCH 13/32] tests/ui: Negative test for blocking with raw methods Signed-off-by: Alexandru Vasile --- .../incorrect/method/method_blocking_raw_incompatible.rs | 9 +++++++++ .../method/method_blocking_raw_incompatible.stderr | 6 ++++++ 2 files changed, 15 insertions(+) create mode 100644 proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.rs create mode 100644 proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.stderr diff --git a/proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.rs b/proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.rs new file mode 100644 index 0000000000..b87213d9ff --- /dev/null +++ b/proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.rs @@ -0,0 +1,9 @@ +use jsonrpsee::proc_macros::rpc; + +#[rpc(server)] +pub trait BlockingMethodCannotBeRaw { + #[method(name = "a", blocking, raw_method)] + fn a(&self, param: Vec); +} + +fn main() {} diff --git a/proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.stderr b/proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.stderr new file mode 100644 index 0000000000..7658d0df09 --- /dev/null +++ b/proc-macros/tests/ui/incorrect/method/method_blocking_raw_incompatible.stderr @@ -0,0 +1,6 @@ +error: Methods cannot be blocking when used with `raw_method`; remove `blocking` attribute or `raw_method` attribute + --> tests/ui/incorrect/method/method_blocking_raw_incompatible.rs:5:2 + | +5 | / #[method(name = "a", blocking, raw_method)] +6 | | fn a(&self, param: Vec); + | |________________________________^ From 0dc48e967bccf9e1709085dbd845176adf04ce5e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:22:18 +0200 Subject: [PATCH 14/32] tests/proc-macros: Ensure unique connection IDs from different clients Signed-off-by: Alexandru Vasile --- tests/tests/proc_macros.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/tests/proc_macros.rs b/tests/tests/proc_macros.rs index 182481d01e..2dbd977c5f 100644 --- a/tests/tests/proc_macros.rs +++ b/tests/tests/proc_macros.rs @@ -74,6 +74,9 @@ mod rpc_impl { #[method(name = "bar")] fn sync_method(&self) -> Result; + #[method(name = "syncRaw", raw_method)] + fn sync_raw_method(&self) -> Result; + #[subscription(name = "sub", unsubscribe = "unsub", item = String)] async fn sub(&self) -> SubscriptionResult; #[subscription(name = "echo", unsubscribe = "unsubscribe_echo", aliases = ["alias_echo"], item = u32)] @@ -162,6 +165,10 @@ mod rpc_impl { Ok(10) } + fn sync_raw_method(&self, connection_id: usize) -> Result { + Ok(connection_id) + } + async fn sub(&self, pending: PendingSubscriptionSink) -> SubscriptionResult { let sink = pending.accept().await?; sink.send("Response_A".into()).await?; @@ -239,6 +246,24 @@ async fn proc_macros_generic_ws_client_api() { assert_eq!(second_recv, 42); } +#[tokio::test] +async fn raw_methods_with_different_ws_clients() { + init_logger(); + + let server_addr = server().await; + let server_url = format!("ws://{}", server_addr); + let client = WsClientBuilder::default().build(&server_url).await.unwrap(); + + // Connection ID does not change for the same client. + let connection_id = client.sync_raw_method().await.unwrap(); + assert_eq!(connection_id, client.sync_raw_method().await.unwrap()); + + // Connection ID is different for different clients. + let second_client = WsClientBuilder::default().build(&server_url).await.unwrap(); + let second_connection_id = second_client.sync_raw_method().await.unwrap(); + assert_ne!(connection_id, second_connection_id); +} + #[tokio::test] async fn macro_param_parsing() { let module = RpcServerImpl.into_rpc(); From 0029418ce034b6d4ac3e39bef77ded41a20e48f7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:28:09 +0200 Subject: [PATCH 15/32] tests/integration: Ensure unique connection IDs from different clients Signed-off-by: Alexandru Vasile --- tests/tests/helpers.rs | 2 ++ tests/tests/integration_tests.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 71765b9c76..98dd23d96a 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -137,6 +137,8 @@ pub async fn server() -> SocketAddr { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "hello").unwrap(); + module.register_raw_method("raw_method", |_, connection_id, _| connection_id).unwrap(); + module .register_async_method("slow_hello", |_, _| async { tokio::time::sleep(std::time::Duration::from_secs(1)).await; diff --git a/tests/tests/integration_tests.rs b/tests/tests/integration_tests.rs index b6991b6196..97a8739348 100644 --- a/tests/tests/integration_tests.rs +++ b/tests/tests/integration_tests.rs @@ -200,6 +200,25 @@ async fn ws_method_call_works_over_proxy_stream() { assert_eq!(&response, "hello"); } +#[tokio::test] +async fn raw_methods_with_different_ws_clients() { + init_logger(); + + let server_addr = server().await; + let server_url = format!("ws://{}", server_addr); + let client = WsClientBuilder::default().build(&server_url).await.unwrap(); + + // Connection ID does not change for the same client. + let connection_id: usize = client.request("raw_method", rpc_params![]).await.unwrap(); + let identical_connection_id: usize = client.request("raw_method", rpc_params![]).await.unwrap(); + assert_eq!(connection_id, identical_connection_id); + + // Connection ID is different for different clients. + let second_client = WsClientBuilder::default().build(&server_url).await.unwrap(); + let second_connection_id: usize = second_client.request("raw_method", rpc_params![]).await.unwrap(); + assert_ne!(connection_id, second_connection_id); +} + #[tokio::test] async fn ws_method_call_str_id_works() { init_logger(); From 3a09a7e646e92e5664b7f061de42d110293692f9 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 22 Feb 2024 18:41:52 +0200 Subject: [PATCH 16/32] proc-macros: Apply cargo fmt Signed-off-by: Alexandru Vasile --- proc-macros/src/rpc_macro.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/proc-macros/src/rpc_macro.rs b/proc-macros/src/rpc_macro.rs index 929b45c780..cde346883a 100644 --- a/proc-macros/src/rpc_macro.rs +++ b/proc-macros/src/rpc_macro.rs @@ -100,7 +100,18 @@ impl RpcMethod { // We've analyzed attributes and don't need them anymore. method.attrs.clear(); - Ok(Self { aliases, blocking, name, params, param_kind, returns, signature: method, docs, deprecated, raw_method }) + Ok(Self { + aliases, + blocking, + name, + params, + param_kind, + returns, + signature: method, + docs, + deprecated, + raw_method, + }) } } @@ -206,8 +217,8 @@ pub struct RpcDescription { impl RpcDescription { pub fn from_item(attr: Attribute, mut item: syn::ItemTrait) -> syn::Result { - let [client, server, namespace, client_bounds, server_bounds] = AttributeMeta::parse(attr)? - .retain(["client", "server", "namespace", "client_bounds", "server_bounds"])?; + let [client, server, namespace, client_bounds, server_bounds] = + AttributeMeta::parse(attr)?.retain(["client", "server", "namespace", "client_bounds", "server_bounds"])?; let needs_server = optional(server, Argument::flag)?.is_some(); let needs_client = optional(client, Argument::flag)?.is_some(); From 15659276f1381748694fdb9c0cbaeee67ffec138 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Feb 2024 13:45:03 +0200 Subject: [PATCH 17/32] Register raw method as async method Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 26 +++++++++---------- examples/examples/server_with_raw_method.rs | 4 +-- proc-macros/src/render_server.rs | 4 +-- proc-macros/src/rpc_macro.rs | 4 +-- .../ui/correct/server_with_raw_methods.rs | 9 +++---- .../method_async_raw_incompatible.stderr | 6 ----- ...ble.rs => method_sync_raw_incompatible.rs} | 4 +-- .../method_sync_raw_incompatible.stderr | 6 +++++ .../src/middleware/rpc/layer/rpc_service.rs | 4 --- tests/tests/helpers.rs | 2 +- tests/tests/proc_macros.rs | 10 +++---- 11 files changed, 37 insertions(+), 42 deletions(-) delete mode 100644 proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr rename proc-macros/tests/ui/incorrect/method/{method_async_raw_incompatible.rs => method_sync_raw_incompatible.rs} (54%) create mode 100644 proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 3cff9ad089..44cb8f195e 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -61,7 +61,6 @@ pub type SyncMethod = Arc M pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. -pub type RawMethod = Arc MethodResponse>; /// Method callback for subscriptions. pub type SubscriptionMethod<'a> = Arc BoxFuture<'a, MethodResponse>>; @@ -133,8 +132,6 @@ pub enum MethodCallback { Sync(SyncMethod), /// Asynchronous method handler. Async(AsyncMethod<'static>), - /// Raw method handler. - Raw(RawMethod), /// Subscription method handler. Subscription(SubscriptionMethod<'static>), /// Unsubscription method handler. @@ -189,7 +186,6 @@ impl Debug for MethodCallback { match self { Self::Async(_) => write!(f, "Async"), Self::Sync(_) => write!(f, "Sync"), - Self::Raw(_) => write!(f, "Raw"), Self::Subscription(_) => write!(f, "Subscription"), Self::Unsubscription(_) => write!(f, "Unsubscription"), } @@ -360,7 +356,6 @@ impl Methods { None => MethodResponse::error(req.id, ErrorObject::from(ErrorCode::MethodNotFound)), Some(MethodCallback::Sync(cb)) => (cb)(id, params, usize::MAX), Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, - Some(MethodCallback::Raw(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX), Some(MethodCallback::Subscription(cb)) => { let conn_state = SubscriptionState { conn_id: 0, id_provider: &RandomIntegerIdProvider, subscription_permit }; @@ -612,25 +607,30 @@ impl RpcModule { /// use jsonrpsee_core::server::RpcModule; /// /// let mut module = RpcModule::new(()); - /// module.register_raw_method("say_hello", |_params, _connection_id, _ctx| "lo").unwrap(); + /// module.register_raw_method("say_hello", |_params, _connection_id _ctx| async { "lo" }).unwrap(); /// ``` - pub fn register_raw_method( + pub fn register_raw_method( &mut self, method_name: &'static str, - callback: F, + callback: Fun, ) -> Result<&mut MethodCallback, RegisterMethodError> where - Context: Send + Sync + 'static, R: IntoResponse + 'static, - F: Fn(Params, ConnectionId, Arc) -> R + Clone + Send + Sync + 'static, + Fut: Future + Send, + Fun: (Fn(Params<'static>, ConnectionId, Arc) -> Fut) + Clone + Send + Sync + 'static, { let ctx = self.ctx.clone(); self.methods.verify_and_insert( method_name, - MethodCallback::Raw(Arc::new(move |id, params, connection_id, max_response_size| { + MethodCallback::Async(Arc::new(move |id, params, connection_id, max_response_size| { let ctx = ctx.clone(); - let rp = callback(params, connection_id, ctx).into_response(); - MethodResponse::response(id, rp, max_response_size) + let callback = callback.clone(); + + let future = async move { + let rp = callback(params, connection_id, ctx).await.into_response(); + MethodResponse::response(id, rp, max_response_size) + }; + future.boxed() })), ) } diff --git a/examples/examples/server_with_raw_method.rs b/examples/examples/server_with_raw_method.rs index 2b322d077c..e3d90273d0 100644 --- a/examples/examples/server_with_raw_method.rs +++ b/examples/examples/server_with_raw_method.rs @@ -37,7 +37,7 @@ use jsonrpsee::ConnectionId; pub trait Rpc { /// Raw method with connection ID. #[method(name = "connectionIdMethod", raw_method)] - fn raw_method(&self, first_param: usize, second_param: u16) -> Result; + async fn raw_method(&self, first_param: usize, second_param: u16) -> Result; /// Normal method call example. #[method(name = "normalMethod")] @@ -52,7 +52,7 @@ pub struct RpcServerImpl; #[async_trait] impl RpcServer for RpcServerImpl { - fn raw_method( + async fn raw_method( &self, connection_id: ConnectionId, _first_param: usize, diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index a20ad23eff..50c4360466 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -143,9 +143,9 @@ impl RpcDescription { if method.raw_method { handle_register_result(quote! { - rpc.register_raw_method(#rpc_method_name, |params, connection_id, context| { + rpc.register_raw_method(#rpc_method_name, |params, connection_id, context| async move { #parsing - #into_response::into_response(context.#rust_method_name(connection_id, #params_seq)) + #into_response::into_response(context.as_ref().#rust_method_name(connection_id, #params_seq).await) }) }) } else { diff --git a/proc-macros/src/rpc_macro.rs b/proc-macros/src/rpc_macro.rs index cde346883a..f0db4da548 100644 --- a/proc-macros/src/rpc_macro.rs +++ b/proc-macros/src/rpc_macro.rs @@ -287,10 +287,10 @@ impl RpcDescription { )); } - if method.sig.asyncness.is_some() && method_data.raw_method { + if method.sig.asyncness.is_none() && method_data.raw_method { return Err(syn::Error::new_spanned( method, - "Methods must be synchronous when used with `raw_method`; use `fn` instead of `async fn`", + "Methods must be asynchronous when used with `raw_method`; use `async fn` instead of `fn`", )); } diff --git a/proc-macros/tests/ui/correct/server_with_raw_methods.rs b/proc-macros/tests/ui/correct/server_with_raw_methods.rs index cf1ef6cf07..57800a12f0 100644 --- a/proc-macros/tests/ui/correct/server_with_raw_methods.rs +++ b/proc-macros/tests/ui/correct/server_with_raw_methods.rs @@ -1,14 +1,13 @@ //! Example of using proc macro to generate working client. -use jsonrpsee::proc_macros::rpc; -use jsonrpsee::types::ErrorObjectOwned; +use jsonrpsee::{core::RpcResult, proc_macros::rpc, types::ErrorObjectOwned}; #[rpc(server)] pub trait Rpc { - #[method(name = "foo")] - async fn async_method(&self, param_a: u8, param_b: String) -> Result; + #[method(name = "foo"1)] + async fn async_method(&self, param_a: u8, param_b: String) -> RpcResult; - #[method(name = "bar", raw_method)] + #[method(name = "bar")] fn sync_method(&self) -> Result; } diff --git a/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr b/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr deleted file mode 100644 index 75b3c0acc5..0000000000 --- a/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: Methods must be synchronous when used with `raw_method`; use `fn` instead of `async fn` - --> tests/ui/incorrect/method/method_async_raw_incompatible.rs:5:2 - | -5 | / #[method(name = "a", raw_method)] -6 | | async fn a(&self, param: Vec); - | |______________________________________^ diff --git a/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs b/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.rs similarity index 54% rename from proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs rename to proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.rs index 6b3bcc4f1b..37751827f2 100644 --- a/proc-macros/tests/ui/incorrect/method/method_async_raw_incompatible.rs +++ b/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.rs @@ -1,9 +1,9 @@ use jsonrpsee::proc_macros::rpc; #[rpc(server)] -pub trait AsyncMethodCannotBeRaw { +pub trait SyncMethodCannotBeRaw { #[method(name = "a", raw_method)] - async fn a(&self, param: Vec); + fn a(&self, param: Vec) -> RpcResult; } fn main() {} diff --git a/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr b/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr new file mode 100644 index 0000000000..a5590f1169 --- /dev/null +++ b/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr @@ -0,0 +1,6 @@ +error: Methods must be asynchronous when used with `raw_method`; use `async fn` instead of `fn` + --> tests/ui/incorrect/method/method_sync_raw_incompatible.rs:5:2 + | +5 | / #[method(name = "a", raw_method)] +6 | | fn a(&self, param: Vec) -> RpcResult; + | |__________________________________________________^ \ No newline at end of file diff --git a/server/src/middleware/rpc/layer/rpc_service.rs b/server/src/middleware/rpc/layer/rpc_service.rs index cb93153921..061908801a 100644 --- a/server/src/middleware/rpc/layer/rpc_service.rs +++ b/server/src/middleware/rpc/layer/rpc_service.rs @@ -98,10 +98,6 @@ impl<'a> RpcServiceT<'a> for RpcService { let rp = (callback)(id, params, max_response_body_size); ResponseFuture::ready(rp) } - MethodCallback::Raw(callback) => { - let rp = (callback)(id, params, conn_id, max_response_body_size); - ResponseFuture::ready(rp) - } MethodCallback::Subscription(callback) => { let RpcServiceCfg::CallsAndSubscriptions { bounded_subscriptions, diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 98dd23d96a..4c0264c3d6 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -137,7 +137,7 @@ pub async fn server() -> SocketAddr { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "hello").unwrap(); - module.register_raw_method("raw_method", |_, connection_id, _| connection_id).unwrap(); + module.register_raw_method("raw_method", |_, connection_id, _| async { connection_id }).unwrap(); module .register_async_method("slow_hello", |_, _| async { diff --git a/tests/tests/proc_macros.rs b/tests/tests/proc_macros.rs index 2dbd977c5f..0dfe210111 100644 --- a/tests/tests/proc_macros.rs +++ b/tests/tests/proc_macros.rs @@ -75,7 +75,7 @@ mod rpc_impl { fn sync_method(&self) -> Result; #[method(name = "syncRaw", raw_method)] - fn sync_raw_method(&self) -> Result; + async fn async_raw_method(&self) -> Result; #[subscription(name = "sub", unsubscribe = "unsub", item = String)] async fn sub(&self) -> SubscriptionResult; @@ -165,7 +165,7 @@ mod rpc_impl { Ok(10) } - fn sync_raw_method(&self, connection_id: usize) -> Result { + async fn async_raw_method(&self, connection_id: usize) -> Result { Ok(connection_id) } @@ -255,12 +255,12 @@ async fn raw_methods_with_different_ws_clients() { let client = WsClientBuilder::default().build(&server_url).await.unwrap(); // Connection ID does not change for the same client. - let connection_id = client.sync_raw_method().await.unwrap(); - assert_eq!(connection_id, client.sync_raw_method().await.unwrap()); + let connection_id = client.async_raw_method().await.unwrap(); + assert_eq!(connection_id, client.async_raw_method().await.unwrap()); // Connection ID is different for different clients. let second_client = WsClientBuilder::default().build(&server_url).await.unwrap(); - let second_connection_id = second_client.sync_raw_method().await.unwrap(); + let second_connection_id = second_client.async_raw_method().await.unwrap(); assert_ne!(connection_id, second_connection_id); } From f5202ef30c6e581a16ca2b4a1f3684bf74eaad21 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Feb 2024 15:34:18 +0200 Subject: [PATCH 18/32] Fix testing Signed-off-by: Alexandru Vasile --- proc-macros/tests/ui/correct/server_with_raw_methods.rs | 2 +- .../ui/incorrect/method/method_sync_raw_incompatible.stderr | 2 +- tests/tests/helpers.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proc-macros/tests/ui/correct/server_with_raw_methods.rs b/proc-macros/tests/ui/correct/server_with_raw_methods.rs index 57800a12f0..e8959ce8f7 100644 --- a/proc-macros/tests/ui/correct/server_with_raw_methods.rs +++ b/proc-macros/tests/ui/correct/server_with_raw_methods.rs @@ -4,7 +4,7 @@ use jsonrpsee::{core::RpcResult, proc_macros::rpc, types::ErrorObjectOwned}; #[rpc(server)] pub trait Rpc { - #[method(name = "foo"1)] + #[method(name = "foo", raw_method)] async fn async_method(&self, param_a: u8, param_b: String) -> RpcResult; #[method(name = "bar")] diff --git a/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr b/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr index a5590f1169..572faafa4c 100644 --- a/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr +++ b/proc-macros/tests/ui/incorrect/method/method_sync_raw_incompatible.stderr @@ -3,4 +3,4 @@ error: Methods must be asynchronous when used with `raw_method`; use `async fn` | 5 | / #[method(name = "a", raw_method)] 6 | | fn a(&self, param: Vec) -> RpcResult; - | |__________________________________________________^ \ No newline at end of file + | |__________________________________________________^ diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 4c0264c3d6..430fbc1377 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -137,7 +137,7 @@ pub async fn server() -> SocketAddr { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "hello").unwrap(); - module.register_raw_method("raw_method", |_, connection_id, _| async { connection_id }).unwrap(); + module.register_raw_method("raw_method", |_, connection_id, _| async move { connection_id }).unwrap(); module .register_async_method("slow_hello", |_, _| async { From 8cf1947ebe2865a2a514d14deb5d0de9e4134b41 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Feb 2024 16:04:35 +0200 Subject: [PATCH 19/32] core: Fix documentation Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 44cb8f195e..bb53261876 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -607,7 +607,7 @@ impl RpcModule { /// use jsonrpsee_core::server::RpcModule; /// /// let mut module = RpcModule::new(()); - /// module.register_raw_method("say_hello", |_params, _connection_id _ctx| async { "lo" }).unwrap(); + /// module.register_raw_method("say_hello", |_params, _connection_id, _ctx| async { "lo" }).unwrap(); /// ``` pub fn register_raw_method( &mut self, From 04dfd25077cdb7e4e90f2d44eee75006299338d8 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 16:30:52 +0200 Subject: [PATCH 20/32] server: Rename raw method to `module.register_async_with_details` Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 4 ++-- proc-macros/src/render_server.rs | 2 +- tests/tests/helpers.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index bb53261876..e834d362fe 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -607,9 +607,9 @@ impl RpcModule { /// use jsonrpsee_core::server::RpcModule; /// /// let mut module = RpcModule::new(()); - /// module.register_raw_method("say_hello", |_params, _connection_id, _ctx| async { "lo" }).unwrap(); + /// module.register_async_with_details("say_hello", |_params, _connection_id, _ctx| async { "lo" }).unwrap(); /// ``` - pub fn register_raw_method( + pub fn register_async_with_details( &mut self, method_name: &'static str, callback: Fun, diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index 5654f72c4c..533ed77549 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -142,7 +142,7 @@ impl RpcDescription { if method.raw_method { handle_register_result(quote! { - rpc.register_raw_method(#rpc_method_name, |params, connection_id, context| async move { + rpc.register_async_with_details(#rpc_method_name, |params, connection_id, context| async move { #parsing #into_response::into_response(context.as_ref().#rust_method_name(connection_id, #params_seq).await) }) diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 430fbc1377..8c6e3668a9 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -137,7 +137,7 @@ pub async fn server() -> SocketAddr { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "hello").unwrap(); - module.register_raw_method("raw_method", |_, connection_id, _| async move { connection_id }).unwrap(); + module.register_async_with_details("raw_method", |_, connection_id, _| async move { connection_id }).unwrap(); module .register_async_method("slow_hello", |_, _| async { From e02ba61e198df41cd31afdc5e4c9e94677e107dc Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 16:35:24 +0200 Subject: [PATCH 21/32] server: Add connection details wrapper Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index e834d362fe..ac2d2ec3f8 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -80,6 +80,23 @@ pub type MaxResponseSize = usize; /// - a [`mpsc::UnboundedReceiver`] to receive future subscription results pub type RawRpcResponse = (String, mpsc::Receiver); +/// The connection details exposed to the server methods. +pub struct ConnectionDetails { + id: ConnectionId, +} + +impl ConnectionDetails { + /// Construct a new [`ConnectionDetails`] with the given connection ID. + pub(crate) fn new(id: ConnectionId) -> Self { + Self { id } + } + + /// Get the connection ID. + pub fn id(&self) -> ConnectionId { + self.id + } +} + /// The error that can occur when [`Methods::call`] or [`Methods::subscribe`] is invoked. #[derive(thiserror::Error, Debug)] pub enum MethodsError { From 7b72d8afe7bdc73ea024c447f873eef0cd46eac8 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 17:16:54 +0200 Subject: [PATCH 22/32] server: Add asyncWithDetails and connection details Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 37 +++++++++++++++++-- .../src/middleware/rpc/layer/rpc_service.rs | 11 +++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index ac2d2ec3f8..45fe2af817 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -60,6 +60,9 @@ pub type SyncMethod = Arc M /// Similar to [`SyncMethod`], but represents an asynchronous handler. pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; +/// Similar to [`SyncMethod`], but represents an asynchronous handler with connection details. +pub type AsyncMethodWithDetails<'a> = + Arc, Params<'a>, ConnectionDetails, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. /// Method callback for subscriptions. pub type SubscriptionMethod<'a> = @@ -80,15 +83,17 @@ pub type MaxResponseSize = usize; /// - a [`mpsc::UnboundedReceiver`] to receive future subscription results pub type RawRpcResponse = (String, mpsc::Receiver); +#[derive(Debug, Clone)] +#[allow(missing_copy_implementations)] /// The connection details exposed to the server methods. pub struct ConnectionDetails { id: ConnectionId, } impl ConnectionDetails { - /// Construct a new [`ConnectionDetails`] with the given connection ID. - pub(crate) fn new(id: ConnectionId) -> Self { - Self { id } + /// Construct a new [`ConnectionDetailsBuilder`]. + pub fn builder() -> ConnectionDetailsBuilder { + ConnectionDetailsBuilder { id: 0 } } /// Get the connection ID. @@ -97,6 +102,26 @@ impl ConnectionDetails { } } +#[derive(Debug, Clone)] +#[allow(missing_copy_implementations)] +/// The connection details exposed to the server methods. +pub struct ConnectionDetailsBuilder { + id: ConnectionId, +} + +impl ConnectionDetailsBuilder { + /// Set the connection ID. + pub fn id(mut self, id: ConnectionId) -> Self { + self.id = id; + self + } + + /// Build the [`ConnectionDetails`]. + pub fn build(self) -> ConnectionDetails { + ConnectionDetails { id: self.id } + } +} + /// The error that can occur when [`Methods::call`] or [`Methods::subscribe`] is invoked. #[derive(thiserror::Error, Debug)] pub enum MethodsError { @@ -149,6 +174,8 @@ pub enum MethodCallback { Sync(SyncMethod), /// Asynchronous method handler. Async(AsyncMethod<'static>), + /// Asynchronous method handler with details. + AsyncWithDetails(AsyncMethodWithDetails<'static>), /// Subscription method handler. Subscription(SubscriptionMethod<'static>), /// Unsubscription method handler. @@ -202,6 +229,7 @@ impl Debug for MethodCallback { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Async(_) => write!(f, "Async"), + Self::AsyncWithDetails(_) => write!(f, "AsyncWithDetails"), Self::Sync(_) => write!(f, "Sync"), Self::Subscription(_) => write!(f, "Subscription"), Self::Unsubscription(_) => write!(f, "Unsubscription"), @@ -373,6 +401,9 @@ impl Methods { None => MethodResponse::error(req.id, ErrorObject::from(ErrorCode::MethodNotFound)), Some(MethodCallback::Sync(cb)) => (cb)(id, params, usize::MAX), Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, + Some(MethodCallback::AsyncWithDetails(cb)) => { + (cb)(id.into_owned(), params.into_owned(), ConnectionDetails::builder().build(), usize::MAX).await + } Some(MethodCallback::Subscription(cb)) => { let conn_state = SubscriptionState { conn_id: 0, id_provider: &RandomIntegerIdProvider, subscription_permit }; diff --git a/server/src/middleware/rpc/layer/rpc_service.rs b/server/src/middleware/rpc/layer/rpc_service.rs index 061908801a..7956a7b0a7 100644 --- a/server/src/middleware/rpc/layer/rpc_service.rs +++ b/server/src/middleware/rpc/layer/rpc_service.rs @@ -32,7 +32,7 @@ use std::sync::Arc; use crate::middleware::rpc::RpcServiceT; use futures_util::future::BoxFuture; use jsonrpsee_core::server::{ - BoundedSubscriptions, MethodCallback, MethodResponse, MethodSink, Methods, SubscriptionState, + BoundedSubscriptions, ConnectionDetails, MethodCallback, MethodResponse, MethodSink, Methods, SubscriptionState, }; use jsonrpsee_core::traits::IdProvider; use jsonrpsee_types::error::{reject_too_many_subscriptions, ErrorCode}; @@ -94,6 +94,15 @@ impl<'a> RpcServiceT<'a> for RpcService { let fut = (callback)(id, params, conn_id, max_response_body_size); ResponseFuture::future(fut) } + MethodCallback::AsyncWithDetails(callback) => { + let params = params.into_owned(); + let id = id.into_owned(); + + // Note: Add the `Request::extensions` to the connection details when available here. + let connection_details = ConnectionDetails::builder().id(conn_id).build(); + let fut = (callback)(id, params, connection_details, max_response_body_size); + ResponseFuture::future(fut) + } MethodCallback::Sync(callback) => { let rp = (callback)(id, params, max_response_body_size); ResponseFuture::ready(rp) From 87585ad948dcdbd7a31773ba8305f38cc9c21fbe Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 17:23:35 +0200 Subject: [PATCH 23/32] proc-macros: Provide connection details to methods Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 8 ++++---- examples/examples/server_with_raw_method.rs | 6 +++--- proc-macros/src/render_server.rs | 6 +++--- tests/tests/helpers.rs | 4 +++- tests/tests/proc_macros.rs | 5 +++-- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 45fe2af817..e56b2ab056 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -655,7 +655,7 @@ impl RpcModule { /// use jsonrpsee_core::server::RpcModule; /// /// let mut module = RpcModule::new(()); - /// module.register_async_with_details("say_hello", |_params, _connection_id, _ctx| async { "lo" }).unwrap(); + /// module.register_async_with_details("say_hello", |_params, _connection_details, _ctx| async { "lo" }).unwrap(); /// ``` pub fn register_async_with_details( &mut self, @@ -665,17 +665,17 @@ impl RpcModule { where R: IntoResponse + 'static, Fut: Future + Send, - Fun: (Fn(Params<'static>, ConnectionId, Arc) -> Fut) + Clone + Send + Sync + 'static, + Fun: (Fn(Params<'static>, ConnectionDetails, Arc) -> Fut) + Clone + Send + Sync + 'static, { let ctx = self.ctx.clone(); self.methods.verify_and_insert( method_name, - MethodCallback::Async(Arc::new(move |id, params, connection_id, max_response_size| { + MethodCallback::AsyncWithDetails(Arc::new(move |id, params, connection_details, max_response_size| { let ctx = ctx.clone(); let callback = callback.clone(); let future = async move { - let rp = callback(params, connection_id, ctx).await.into_response(); + let rp = callback(params, connection_details, ctx).await.into_response(); MethodResponse::response(id, rp, max_response_size) }; future.boxed() diff --git a/examples/examples/server_with_raw_method.rs b/examples/examples/server_with_raw_method.rs index e3d90273d0..26464e9504 100644 --- a/examples/examples/server_with_raw_method.rs +++ b/examples/examples/server_with_raw_method.rs @@ -31,7 +31,7 @@ use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::{PendingSubscriptionSink, Server, SubscriptionMessage}; use jsonrpsee::types::ErrorObjectOwned; use jsonrpsee::ws_client::WsClientBuilder; -use jsonrpsee::ConnectionId; +use jsonrpsee::ConnectionDetails; #[rpc(server, client)] pub trait Rpc { @@ -54,12 +54,12 @@ pub struct RpcServerImpl; impl RpcServer for RpcServerImpl { async fn raw_method( &self, - connection_id: ConnectionId, + connection_details: ConnectionDetails, _first_param: usize, _second_param: u16, ) -> Result { // Return the connection ID from which this method was called. - Ok(connection_id) + Ok(connection_details.id()) } fn normal_method(&self, _first_param: usize, _second_param: u16) -> Result { diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index 533ed77549..305d1989fb 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -64,7 +64,7 @@ impl RpcDescription { let mut method_sig = method.signature.clone(); if method.raw_method { - let context_ty = self.jrps_server_item(quote! { ConnectionId }); + let context_ty = self.jrps_server_item(quote! { ConnectionDetails }); // Add `connection ID` as the second input parameter to the signature. let context: syn::FnArg = syn::parse_quote!(connection_context: #context_ty); method_sig.sig.inputs.insert(1, context); @@ -142,9 +142,9 @@ impl RpcDescription { if method.raw_method { handle_register_result(quote! { - rpc.register_async_with_details(#rpc_method_name, |params, connection_id, context| async move { + rpc.register_async_with_details(#rpc_method_name, |params, connection_details, context| async move { #parsing - #into_response::into_response(context.as_ref().#rust_method_name(connection_id, #params_seq).await) + #into_response::into_response(context.as_ref().#rust_method_name(connection_details, #params_seq).await) }) }) } else { diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 8c6e3668a9..0aeef889e7 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -137,7 +137,9 @@ pub async fn server() -> SocketAddr { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "hello").unwrap(); - module.register_async_with_details("raw_method", |_, connection_id, _| async move { connection_id }).unwrap(); + module + .register_async_with_details("raw_method", |_, connection_details, _| async move { connection_details.id() }) + .unwrap(); module .register_async_method("slow_hello", |_, _| async { diff --git a/tests/tests/proc_macros.rs b/tests/tests/proc_macros.rs index 0dfe210111..d489d7a72d 100644 --- a/tests/tests/proc_macros.rs +++ b/tests/tests/proc_macros.rs @@ -49,6 +49,7 @@ mod rpc_impl { use jsonrpsee::core::{async_trait, SubscriptionResult}; use jsonrpsee::proc_macros::rpc; use jsonrpsee::types::{ErrorObject, ErrorObjectOwned}; + use jsonrpsee::ConnectionDetails; pub struct CustomSubscriptionRet; @@ -165,8 +166,8 @@ mod rpc_impl { Ok(10) } - async fn async_raw_method(&self, connection_id: usize) -> Result { - Ok(connection_id) + async fn async_raw_method(&self, connection_details: ConnectionDetails) -> Result { + Ok(connection_details.id()) } async fn sub(&self, pending: PendingSubscriptionSink) -> SubscriptionResult { From 2c5037552a6725d32ed183a96bdf701645109948 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:41:42 +0200 Subject: [PATCH 24/32] Update core/src/server/rpc_module.rs Co-authored-by: Niklas Adolfsson --- core/src/server/rpc_module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index e56b2ab056..1eb70171f3 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -60,7 +60,7 @@ pub type SyncMethod = Arc M /// Similar to [`SyncMethod`], but represents an asynchronous handler. pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; -/// Similar to [`SyncMethod`], but represents an asynchronous handler with connection details. +/// Similar to [`AsyncMethod`], but represents an asynchronous handler with connection details. pub type AsyncMethodWithDetails<'a> = Arc, Params<'a>, ConnectionDetails, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. From 66b6a3937b13b255624cb270829526d3297696e3 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 18:43:57 +0200 Subject: [PATCH 25/32] server: Remove connection details builder Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 29 ++++--------------- .../src/middleware/rpc/layer/rpc_service.rs | 3 +- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index e56b2ab056..ab3202fb87 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -91,9 +91,10 @@ pub struct ConnectionDetails { } impl ConnectionDetails { - /// Construct a new [`ConnectionDetailsBuilder`]. - pub fn builder() -> ConnectionDetailsBuilder { - ConnectionDetailsBuilder { id: 0 } + /// Construct a new [`ConnectionDetails`]. + #[doc(hidden)] + pub fn _new(id: ConnectionId) -> ConnectionDetails { + Self { id } } /// Get the connection ID. @@ -102,26 +103,6 @@ impl ConnectionDetails { } } -#[derive(Debug, Clone)] -#[allow(missing_copy_implementations)] -/// The connection details exposed to the server methods. -pub struct ConnectionDetailsBuilder { - id: ConnectionId, -} - -impl ConnectionDetailsBuilder { - /// Set the connection ID. - pub fn id(mut self, id: ConnectionId) -> Self { - self.id = id; - self - } - - /// Build the [`ConnectionDetails`]. - pub fn build(self) -> ConnectionDetails { - ConnectionDetails { id: self.id } - } -} - /// The error that can occur when [`Methods::call`] or [`Methods::subscribe`] is invoked. #[derive(thiserror::Error, Debug)] pub enum MethodsError { @@ -402,7 +383,7 @@ impl Methods { Some(MethodCallback::Sync(cb)) => (cb)(id, params, usize::MAX), Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), 0, usize::MAX).await, Some(MethodCallback::AsyncWithDetails(cb)) => { - (cb)(id.into_owned(), params.into_owned(), ConnectionDetails::builder().build(), usize::MAX).await + (cb)(id.into_owned(), params.into_owned(), ConnectionDetails::_new(0), usize::MAX).await } Some(MethodCallback::Subscription(cb)) => { let conn_state = diff --git a/server/src/middleware/rpc/layer/rpc_service.rs b/server/src/middleware/rpc/layer/rpc_service.rs index 7956a7b0a7..f5bae98ede 100644 --- a/server/src/middleware/rpc/layer/rpc_service.rs +++ b/server/src/middleware/rpc/layer/rpc_service.rs @@ -99,8 +99,7 @@ impl<'a> RpcServiceT<'a> for RpcService { let id = id.into_owned(); // Note: Add the `Request::extensions` to the connection details when available here. - let connection_details = ConnectionDetails::builder().id(conn_id).build(); - let fut = (callback)(id, params, connection_details, max_response_body_size); + let fut = (callback)(id, params, ConnectionDetails::_new(conn_id), max_response_body_size); ResponseFuture::future(fut) } MethodCallback::Sync(callback) => { From cfe1aeccf35d7df6f9fed62d3ebf4efca9ee9f79 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 18:45:02 +0200 Subject: [PATCH 26/32] server: Refactor `.register_async_with_details` to `.register_async_method_with_details` Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 4 ++-- proc-macros/src/render_server.rs | 2 +- tests/tests/helpers.rs | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index ab3202fb87..07b4c57c2b 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -636,9 +636,9 @@ impl RpcModule { /// use jsonrpsee_core::server::RpcModule; /// /// let mut module = RpcModule::new(()); - /// module.register_async_with_details("say_hello", |_params, _connection_details, _ctx| async { "lo" }).unwrap(); + /// module.register_async_method_with_details("say_hello", |_params, _connection_details, _ctx| async { "lo" }).unwrap(); /// ``` - pub fn register_async_with_details( + pub fn register_async_method_with_details( &mut self, method_name: &'static str, callback: Fun, diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index 305d1989fb..03e175bd60 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -142,7 +142,7 @@ impl RpcDescription { if method.raw_method { handle_register_result(quote! { - rpc.register_async_with_details(#rpc_method_name, |params, connection_details, context| async move { + rpc.register_async_method_with_details(#rpc_method_name, |params, connection_details, context| async move { #parsing #into_response::into_response(context.as_ref().#rust_method_name(connection_details, #params_seq).await) }) diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 0aeef889e7..88ed9ed799 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -138,7 +138,10 @@ pub async fn server() -> SocketAddr { module.register_method("say_hello", |_, _| "hello").unwrap(); module - .register_async_with_details("raw_method", |_, connection_details, _| async move { connection_details.id() }) + .register_async_method_with_details( + "raw_method", + |_, connection_details, _| async move { connection_details.id() }, + ) .unwrap(); module From 7327d8b52deb59fce72b8fb90a67d93d32aeafa6 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 4 Mar 2024 18:46:11 +0200 Subject: [PATCH 27/32] proc-macro: Clarify comment Signed-off-by: Alexandru Vasile --- proc-macros/src/render_server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proc-macros/src/render_server.rs b/proc-macros/src/render_server.rs index 03e175bd60..2be84da7c8 100644 --- a/proc-macros/src/render_server.rs +++ b/proc-macros/src/render_server.rs @@ -65,8 +65,8 @@ impl RpcDescription { if method.raw_method { let context_ty = self.jrps_server_item(quote! { ConnectionDetails }); - // Add `connection ID` as the second input parameter to the signature. - let context: syn::FnArg = syn::parse_quote!(connection_context: #context_ty); + // Add `ConnectionDetails` as the second parameter to the signature. + let context: syn::FnArg = syn::parse_quote!(connection_details: #context_ty); method_sig.sig.inputs.insert(1, context); } From 650e24aea663ef1a280636eaf5065c1e06759a9f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 5 Mar 2024 14:05:08 +0200 Subject: [PATCH 28/32] core: Doc hidden for async with details Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 452e342420..64dc3ae3f8 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -60,7 +60,9 @@ pub type SyncMethod = Arc M /// Similar to [`SyncMethod`], but represents an asynchronous handler. pub type AsyncMethod<'a> = Arc, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; + /// Similar to [`AsyncMethod`], but represents an asynchronous handler with connection details. +#[doc(hidden)] pub type AsyncMethodWithDetails<'a> = Arc, Params<'a>, ConnectionDetails, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; /// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. @@ -83,9 +85,10 @@ pub type MaxResponseSize = usize; /// - a [`mpsc::UnboundedReceiver`] to receive future subscription results pub type RawRpcResponse = (String, mpsc::Receiver); +/// The connection details exposed to the server methods. #[derive(Debug, Clone)] #[allow(missing_copy_implementations)] -/// The connection details exposed to the server methods. +#[doc(hidden)] pub struct ConnectionDetails { id: ConnectionId, } @@ -98,6 +101,7 @@ impl ConnectionDetails { } /// Get the connection ID. + #[doc(hidden)] pub fn id(&self) -> ConnectionId { self.id } @@ -638,6 +642,7 @@ impl RpcModule { /// let mut module = RpcModule::new(()); /// module.register_async_method_with_details("say_hello", |_params, _connection_details, _ctx| async { "lo" }).unwrap(); /// ``` + #[doc(hidden)] pub fn register_async_method_with_details( &mut self, method_name: &'static str, From f4d9085d7eed8519f6846cd2b737ecaba2a03cca Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 5 Mar 2024 15:35:52 +0200 Subject: [PATCH 29/32] Rename example Signed-off-by: Alexandru Vasile --- ...erver_with_raw_method.rs => server_with_connection_details.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/examples/{server_with_raw_method.rs => server_with_connection_details.rs} (100%) diff --git a/examples/examples/server_with_raw_method.rs b/examples/examples/server_with_connection_details.rs similarity index 100% rename from examples/examples/server_with_raw_method.rs rename to examples/examples/server_with_connection_details.rs From 40d2bcfd9b67a1e28f90fd655d2cf773f4df49e7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:36:03 +0200 Subject: [PATCH 30/32] Update core/src/server/rpc_module.rs Co-authored-by: Niklas Adolfsson --- core/src/server/rpc_module.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 64dc3ae3f8..ce7eea6fd5 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -160,6 +160,7 @@ pub enum MethodCallback { /// Asynchronous method handler. Async(AsyncMethod<'static>), /// Asynchronous method handler with details. + #[doc(hidden)] AsyncWithDetails(AsyncMethodWithDetails<'static>), /// Subscription method handler. Subscription(SubscriptionMethod<'static>), From 11ef18cd28b9e4cf2660ae5244c7778671165d61 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 5 Mar 2024 15:41:15 +0200 Subject: [PATCH 31/32] core: Remove doc(hidden) from ConnectionDetails::id Signed-off-by: Alexandru Vasile --- core/src/server/rpc_module.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 8252ad5699..1550e63838 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -101,7 +101,6 @@ impl ConnectionDetails { } /// Get the connection ID. - #[doc(hidden)] pub fn id(&self) -> ConnectionId { self.id } From 4f459ac79ed6d6546f87b1874c3c6d4f8121260e Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 5 Mar 2024 16:00:57 +0100 Subject: [PATCH 32/32] Update core/src/server/rpc_module.rs --- core/src/server/rpc_module.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 1550e63838..2cd8e3ca7b 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -65,7 +65,6 @@ pub type AsyncMethod<'a> = #[doc(hidden)] pub type AsyncMethodWithDetails<'a> = Arc, Params<'a>, ConnectionDetails, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>; -/// Similar to [`SyncMethod`], but represents a raw handler that has access to the connection Id. /// Method callback for subscriptions. pub type SubscriptionMethod<'a> = Arc BoxFuture<'a, MethodResponse>>;