Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions benches/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,22 +169,22 @@ pub async fn ws_server(handle: tokio::runtime::Handle) -> (String, jsonrpsee::se
fn gen_rpc_module() -> jsonrpsee::RpcModule<()> {
let mut module = jsonrpsee::RpcModule::new(());

module.register_method(SYNC_FAST_CALL, |_, _| "lo").unwrap();
module.register_async_method(ASYNC_FAST_CALL, |_, _| async { "lo" }).unwrap();
module.register_method(SYNC_FAST_CALL, |_, _, _| "lo").unwrap();
module.register_async_method(ASYNC_FAST_CALL, |_, _, _| async { "lo" }).unwrap();

module.register_method(SYNC_MEM_CALL, |_, _| "A".repeat(MIB)).unwrap();
module.register_method(SYNC_MEM_CALL, |_, _, _| "A".repeat(MIB)).unwrap();

module.register_async_method(ASYNC_MEM_CALL, |_, _| async move { "A".repeat(MIB) }).unwrap();
module.register_async_method(ASYNC_MEM_CALL, |_, _, _| async move { "A".repeat(MIB) }).unwrap();

module
.register_method(SYNC_SLOW_CALL, |_, _| {
.register_method(SYNC_SLOW_CALL, |_, _, _| {
std::thread::sleep(SLOW_CALL);
"slow call"
})
.unwrap();

module
.register_async_method(ASYNC_SLOW_CALL, |_, _| async move {
.register_async_method(ASYNC_SLOW_CALL, |_, _, _| async move {
tokio::time::sleep(SLOW_CALL).await;
"slow call async"
})
Expand Down
61 changes: 61 additions & 0 deletions core/src/server/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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.

//! The context of a JSON-RPC server implementation.

/// The context of a JSON-RPC server that is passed to methods and subscriptions
/// that enabled the `with_context` attribute.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ConnectionContext {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather re-name this to PerConnectionContext or something to easily distinguish from the other context

/// The ID of the connection.
connection_id: ConnectionId,
/// The maximum response size.
max_response_size: MaxResponseSize,
}

impl ConnectionContext {
/// Create a new context.
pub fn new(connection_id: ConnectionId, max_response_size: MaxResponseSize) -> Self {
Self { connection_id: connection_id, max_response_size }
}

/// Get the connection ID.
pub fn connection_id(&self) -> ConnectionId {
self.connection_id
}

/// Get the maximum response size.
pub fn max_response_size(&self) -> MaxResponseSize {
self.max_response_size
}
}

/// Connection ID, used for stateful protocol such as WebSockets.
/// For stateless protocols such as http it's unused, so feel free to set it some hardcoded value.
pub type ConnectionId = usize;

/// Max response size.
pub type MaxResponseSize = usize;
3 changes: 3 additions & 0 deletions core/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

//! Shared modules for the JSON-RPC servers.

/// Connection context types.
mod context;
/// Error types.
mod error;
/// Helpers.
Expand All @@ -37,6 +39,7 @@ mod rpc_module;
/// Subscription related types.
mod subscription;

pub use context::*;
pub use error::*;
pub use helpers::*;
pub use method_response::*;
Expand Down
49 changes: 25 additions & 24 deletions core/src/server/rpc_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::server::subscription::{
SubNotifResultOrError, Subscribers, Subscription, SubscriptionCloseResponse, SubscriptionKey, SubscriptionPermit,
SubscriptionState,
};
use crate::server::ConnectionContext;
use crate::server::{ResponsePayload, LOG_TARGET};
use crate::traits::ToRpcParams;
use futures_util::{future::BoxFuture, FutureExt};
Expand All @@ -56,22 +57,15 @@ use super::IntoResponse;
/// implemented as a function pointer to a `Fn` function taking four arguments:
/// the `id`, `params`, a channel the function uses to communicate the result (or error)
/// back to `jsonrpsee`, and the connection ID (useful for the websocket transport).
pub type SyncMethod = Arc<dyn Send + Sync + Fn(Id, Params, MaxResponseSize) -> MethodResponse>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another option is to add new MethodKind here such as:

RawMethod = Arc<dyn Send + Sync + Fn(Id, Params, ConnectionContext) -> MethodResponse>

then let folks spawn futures and stuff them selves if they need and just provide a new attribute in the procs macros as you already did.

then register_blocking, async, etc are not needed.

Copy link
Copy Markdown
Contributor

@niklasad1 niklasad1 Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then we don't have break the existing APIs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, I've implemented that in: https://github.com/paritytech/jsonrpsee/pull/1297/files#diff-dc533588250ea236f580d7fdaf87cdfce2ec80da031de9067b1088465a555998R64

One downside with doing a RawMethod like this is that we lose the ability to have:

  • async methods (since this is a SyncMethod that receives an extra connection ID)
  • blocking methods (since the server-context is passed differently to a blocking method -- its need to be Arc<Context> instead of &Context so our callbacks are different)

This makes me wonder if I should also add the counter-part RawAsyncMethod and another register_raw_blocking. I think a single RawMethod would solve the connection ID exposure to complete the chainHead issue in substrate; but it might require us to extend it in the future.

At some point in the future , if we choose to implement RawAsyncMethod, it might be more beneficial to make a breaking change and add the connection Id to every method, for now I think we could avoid that

pub type SyncMethod = Arc<dyn Send + Sync + Fn(Id, Params, ConnectionContext) -> MethodResponse>;
/// Similar to [`SyncMethod`], but represents an asynchronous handler.
pub type AsyncMethod<'a> =
Arc<dyn Send + Sync + Fn(Id<'a>, Params<'a>, ConnectionId, MaxResponseSize) -> BoxFuture<'a, MethodResponse>>;
Arc<dyn Send + Sync + Fn(Id<'a>, Params<'a>, ConnectionContext) -> BoxFuture<'a, MethodResponse>>;
/// Method callback for subscriptions.
pub type SubscriptionMethod<'a> =
Arc<dyn Send + Sync + Fn(Id, Params, MethodSink, SubscriptionState) -> BoxFuture<'a, MethodResponse>>;
// Method callback to unsubscribe.
type UnsubscriptionMethod = Arc<dyn Send + Sync + Fn(Id, Params, ConnectionId, MaxResponseSize) -> MethodResponse>;

/// Connection ID, used for stateful protocol such as WebSockets.
/// For stateless protocols such as http it's unused, so feel free to set it some hardcoded value.
pub type ConnectionId = usize;

/// Max response size.
pub type MaxResponseSize = usize;
type UnsubscriptionMethod = Arc<dyn Send + Sync + Fn(Id, Params, ConnectionContext) -> MethodResponse>;

/// Raw response from an RPC
/// A tuple containing:
Expand Down Expand Up @@ -351,10 +345,11 @@ impl Methods {
let id = req.id.clone();
let params = Params::new(req.params.as_ref().map(|params| params.as_ref().get()));

let connection_context = ConnectionContext::new(0, usize::MAX);
let response = match self.method(&req.method) {
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::Sync(cb)) => (cb)(id, params, connection_context),
Some(MethodCallback::Async(cb)) => (cb)(id.into_owned(), params.into_owned(), connection_context).await,
Some(MethodCallback::Subscription(cb)) => {
let conn_state =
SubscriptionState { conn_id: 0, id_provider: &RandomIntegerIdProvider, subscription_permit };
Expand All @@ -368,7 +363,7 @@ impl Methods {

res
}
Some(MethodCallback::Unsubscription(cb)) => (cb)(id, params, 0, usize::MAX),
Some(MethodCallback::Unsubscription(cb)) => (cb)(id, params, connection_context),
};

let is_success = response.is_success();
Expand Down Expand Up @@ -500,7 +495,7 @@ impl<Context: Send + Sync + 'static> RpcModule<Context> {
/// use jsonrpsee_core::server::RpcModule;
///
/// let mut module = RpcModule::new(());
/// module.register_method("say_hello", |_params, _ctx| "lo").unwrap();
/// module.register_method("say_hello", |_params, _connection_ctx, _ctx| "lo").unwrap();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @jsdw so basically this is the grumble

we expose now two context's here one conn_ctx which isn't exclusively connection stuff and then ctx which is completely controlled by the user.

however, the ctx is shared state per "rpc per server" and conn_ctx is per connection....

Copy link
Copy Markdown
Collaborator

@jsdw jsdw Feb 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah ok I see!

My general grumble is that I think we should have some way to pass generic data from middleware or whatever into RPC calls. If we had that then we wouldn't need to expose eg the internal connection ID as a hardcoded thing, because the user could just create their own connection ID counter in middleware and pass that in.

Methods might want access to a bunch of other stuff from middleware that we haven't yet exposed or forseen, and I wouldn't want us to always have to work around it by trying to provide those things in a hardcoded way; I'd rather that we foudn a way to solve the problem generically :)

A couple of ideas for how:

  1. Have eg a type map (ie map from type to value) that one can attach arbitrary data into in middlewares and then pull out in the method if they have access to the relevant type, and perhaps this sort of thing could be exposed via a per connection context.
  2. Make jsonrpsee server generic over some Context type that is then passed through middlewares and exposed in handlers and can be whatever concrete type the user needs. I could see that being way harder to add though)

But @niklasad1 you've mentioned that maybe this is possible via low level APIs so perhaps there's a way to achieve this already?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the first idea, I've been exploring with a custom type as field to the PerConnectionContext: Arc<Mutex<anymap::Map<dyn anymap::any::Any + Send + Sync>>>. This should allow users to insert in the map any type they want.

I might be missing something here, but the trick part with this comes from the fact that the PerConnectionContext is constructed as the last step in our RpcServiceT middleware. This means that users will only access it from methods, but cannot alter its state from another RpcServiceT middleware.
From my perspective, if the PerConnectionContext can only be accessed / altered from within methods, I think this brings the same usefulness as connection: usize. Since chainHead_* methods could store internally a Map<connection, Data>.

pub trait RpcServiceT<'a> {
/// The future response value.
type Future: Future<Output = MethodResponse> + Send;
/// Process a single JSON-RPC call it may be a subscription or regular call.
/// In this interface they are treated in the same way but it's possible to
/// distinguish those based on the `MethodResponse`.
fn call(&self, request: Request<'a>) -> Self::Future;
}

For this to be useful outside the method call; we'd probably need to extend the call function to include the (per connection) context : fn call(&self, request: Request<'a>, context: PerConnectionContext) -> Self::Future;. I do remember this was the original design for the middleware, but I think we had some difficulties implementing it?
And I think an extension of this is the second idea, however I don't know how much harder that is to implement.

Copy link
Copy Markdown
Contributor

@niklasad1 niklasad1 Feb 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is tricky and I don't think it's a nice way to solve currently generic right now.

so the flow is like this:

let shared_state = Arc::new(Mutex::(HashMap::new::<ConnectionId, State>()));
let rpc_api = ChainHeadRpc::new(shared_state.clone());
// one could also write middleware but no way to share that middleware with the actual RPC implementation
// other then inject connection ID as params in the JSON-RPC call itself
// such as having an extra param: Option<ConnectionId>
start_rpc(rpc_api, shared_state);

#[rpc]
trait ChainHeadRpcApi {
   #[method(name = "chainHead_unstable_call")] 
   fn f(&self, params: Vec<u8>) -> String;
}

impl ChainHeadRpcApi for ChainHeadRpc {
   fn f(&self, params: Vec<u8>) -> String {
        // no way to know which connection made the call
        // but we can access the HashMap as shared state here
        todo!(); 
    }
}

fn start_rpc(rpc_api, shared_state) {
     for conn in server.accept() {
         // could also enable middleware but the state can't 
         // really be shared per connection in the rpc_api...
         shared_state.lock.insert(conn.id, State);
         tokio::spawn(upgrade_to_tower_service(conn));
      }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thus, it would be neat to have a have closure similar for the context/user defined data in the rpc API such that users can decide whether the state for rpc impl should be shared or per connection...

/// ```
pub fn register_method<R, F>(
&mut self,
Expand All @@ -510,13 +505,14 @@ impl<Context: Send + Sync + 'static> RpcModule<Context> {
where
Context: Send + Sync + 'static,
R: IntoResponse + 'static,
F: Fn(Params, &Context) -> R + Send + Sync + 'static,
F: Fn(Params, ConnectionContext, &Context) -> R + Send + Sync + 'static,
{
let ctx = self.ctx.clone();
self.methods.verify_and_insert(
method_name,
MethodCallback::Sync(Arc::new(move |id, params, max_response_size| {
let rp = callback(params, &*ctx).into_response();
MethodCallback::Sync(Arc::new(move |id, params, connection_context| {
let max_response_size = connection_context.max_response_size();
let rp = callback(params, connection_context, &*ctx).into_response();
MethodResponse::response(id, rp, max_response_size)
})),
)
Expand All @@ -542,17 +538,18 @@ impl<Context: Send + Sync + 'static> RpcModule<Context> {
where
R: IntoResponse + 'static,
Fut: Future<Output = R> + Send,
Fun: (Fn(Params<'static>, Arc<Context>) -> Fut) + Clone + Send + Sync + 'static,
Fun: (Fn(Params<'static>, ConnectionContext, Arc<Context>) -> Fut) + Clone + Send + Sync + 'static,
{
let ctx = self.ctx.clone();
self.methods.verify_and_insert(
method_name,
MethodCallback::Async(Arc::new(move |id, params, _, max_response_size| {
MethodCallback::Async(Arc::new(move |id, params, connection_context| {
let ctx = ctx.clone();
let callback = callback.clone();
let max_response_size = connection_context.max_response_size();

let future = async move {
let rp = callback(params, ctx).await.into_response();
let rp = callback(params, connection_context, ctx).await.into_response();
MethodResponse::response(id, rp, max_response_size)
};
future.boxed()
Expand All @@ -571,17 +568,18 @@ impl<Context: Send + Sync + 'static> RpcModule<Context> {
where
Context: Send + Sync + 'static,
R: IntoResponse + 'static,
F: Fn(Params, Arc<Context>) -> R + Clone + Send + Sync + 'static,
F: Fn(Params, ConnectionContext, Arc<Context>) -> R + Clone + Send + Sync + 'static,
{
let ctx = self.ctx.clone();
let callback = self.methods.verify_and_insert(
method_name,
MethodCallback::Async(Arc::new(move |id, params, _, max_response_size| {
MethodCallback::Async(Arc::new(move |id, params, connection_context| {
let ctx = ctx.clone();
let callback = callback.clone();
let max_response_size = connection_context.max_response_size();

tokio::task::spawn_blocking(move || {
let rp = callback(params, ctx).into_response();
let rp = callback(params, connection_context, ctx).into_response();
MethodResponse::response(id, rp, max_response_size)
})
.map(|result| match result {
Expand Down Expand Up @@ -899,7 +897,10 @@ impl<Context: Send + Sync + 'static> RpcModule<Context> {
let subscribers = subscribers.clone();
self.methods.mut_callbacks().insert(
unsubscribe_method_name,
MethodCallback::Unsubscription(Arc::new(move |id, params, conn_id, max_response_size| {
MethodCallback::Unsubscription(Arc::new(move |id, params, connection_context| {
let conn_id = connection_context.connection_id();
let max_response_size = connection_context.max_response_size();

let sub_id = match params.one::<RpcSubscriptionId>() {
Ok(sub_id) => sub_id,
Err(_) => {
Expand Down
2 changes: 1 addition & 1 deletion core/src/server/subscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
use super::helpers::MethodSink;
use super::{MethodResponse, MethodsError, ResponsePayload};
use crate::server::error::{DisconnectError, PendingSubscriptionAcceptError, SendTimeoutError, TrySendError};
use crate::server::rpc_module::ConnectionId;
use crate::server::ConnectionId;
use crate::server::LOG_TARGET;
use crate::{error::StringError, traits::IdProvider};
use jsonrpsee_types::SubscriptionPayload;
Expand Down
2 changes: 1 addition & 1 deletion examples/examples/core_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async fn main() -> anyhow::Result<()> {
async fn run_server() -> anyhow::Result<SocketAddr> {
let server = Server::builder().build("127.0.0.1:0").await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("say_hello", |_, _, _| "lo")?;
let addr = server.local_addr()?;

let handle = server.start(module);
Expand Down
2 changes: 1 addition & 1 deletion examples/examples/cors_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
let server = Server::builder().set_http_middleware(middleware).build("127.0.0.1:0".parse::<SocketAddr>()?).await?;

let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| {
module.register_method("say_hello", |_, _, _| {
println!("say_hello method called!");
"Hello there!!"
})?;
Expand Down
2 changes: 1 addition & 1 deletion examples/examples/host_filter_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
let addr = server.local_addr()?;

let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo").unwrap();
module.register_method("say_hello", |_, _, _| "lo").unwrap();

let handle = server.start(module);

Expand Down
2 changes: 1 addition & 1 deletion examples/examples/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async fn main() -> anyhow::Result<()> {
async fn run_server() -> anyhow::Result<SocketAddr> {
let server = Server::builder().build("127.0.0.1:0".parse::<SocketAddr>()?).await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("say_hello", |_, _, _| "lo")?;

let addr = server.local_addr()?;
let handle = server.start(module);
Expand Down
2 changes: 1 addition & 1 deletion examples/examples/http_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
let addr = server.local_addr()?;

let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo").unwrap();
module.register_method("say_hello", |_, _, _| "lo").unwrap();

let handle = server.start(module);

Expand Down
4 changes: 2 additions & 2 deletions examples/examples/http_proxy_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
let addr = server.local_addr()?;

let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo").unwrap();
module.register_method("system_health", |_, _| serde_json::json!({ "health": true })).unwrap();
module.register_method("say_hello", |_, _, _| "lo").unwrap();
module.register_method("system_health", |_, _, _| serde_json::json!({ "health": true })).unwrap();

let handle = server.start(module);

Expand Down
4 changes: 2 additions & 2 deletions examples/examples/rpc_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
.layer_fn(move |service| GlobalCalls { service, count: global_cnt.clone() });
let server = Server::builder().set_rpc_middleware(rpc_middleware).build("127.0.0.1:0").await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("thready", |params, _| {
module.register_method("say_hello", |_, _, _| "lo")?;
module.register_method("thready", |params, _, _| {
let thread_count: usize = params.one().unwrap();
for _ in 0..thread_count {
std::thread::spawn(|| std::thread::sleep(std::time::Duration::from_secs(1)));
Expand Down
4 changes: 2 additions & 2 deletions examples/examples/rpc_middleware_modify_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
let rpc_middleware = RpcServiceBuilder::new().layer_fn(ModifyRequestIf);
let server = Server::builder().set_rpc_middleware(rpc_middleware).build("127.0.0.1:0").await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("say_goodbye", |_, _| "goodbye")?;
module.register_method("say_hello", |_, _, _| "lo")?;
module.register_method("say_goodbye", |_, _, _| "goodbye")?;
let addr = server.local_addr()?;

let handle = server.start(module);
Expand Down
4 changes: 2 additions & 2 deletions examples/examples/rpc_middleware_rate_limiting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ async fn run_server() -> anyhow::Result<SocketAddr> {

let server = Server::builder().set_rpc_middleware(rpc_middleware).build("127.0.0.1:0").await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("say_goodbye", |_, _| "goodbye")?;
module.register_method("say_hello", |_, _, _| "lo")?;
module.register_method("say_goodbye", |_, _, _| "goodbye")?;
let addr = server.local_addr()?;

let handle = server.start(module);
Expand Down
6 changes: 3 additions & 3 deletions examples/examples/tokio_console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ async fn main() -> anyhow::Result<()> {
async fn run_server() -> anyhow::Result<SocketAddr> {
let server = Server::builder().build("127.0.0.1:9944").await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("memory_call", |_, _| "A".repeat(1024 * 1024))?;
module.register_async_method("sleep", |_, _| async {
module.register_method("say_hello", |_, _, _| "lo")?;
module.register_method("memory_call", |_, _, _| "A".repeat(1024 * 1024))?;
module.register_async_method("sleep", |_, _, _| async {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
"lo"
})?;
Expand Down
2 changes: 1 addition & 1 deletion examples/examples/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
let rpc_middleware = RpcServiceBuilder::new().rpc_logger(1024);
let server = Server::builder().set_rpc_middleware(rpc_middleware).build("127.0.0.1:0").await?;
let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo")?;
module.register_method("say_hello", |_, _, _| "lo")?;
let addr = server.local_addr()?;
let handle = server.start(module);

Expand Down
Loading