Skip to content
Open
4 changes: 2 additions & 2 deletions client/http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,8 @@ where
let id_range = generate_batch_id_range(id, batch.len() as u64)?;

let mut batch_request = Vec::with_capacity(batch.len());
for ((method, params), id) in batch.into_iter().zip(id_range.clone()) {
let id = self.id_manager.as_id_kind().into_id(id);
for ((method, params), _id) in batch.into_iter().zip(id_range.clone()) {
let id = self.id_manager.next_request_id();
batch_request.push(RequestSer {
jsonrpc: TwoPointZero,
id,
Expand Down
6 changes: 3 additions & 3 deletions core/src/client/async_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ use tokio::sync::{mpsc, oneshot};
use tracing::instrument;

use self::utils::{InactivityCheck, IntervalStream};
use super::{generate_batch_id_range, subscription_channel, FrontToBack, IdKind, RequestIdManager};
use super::{FrontToBack, IdKind, RequestIdManager, generate_batch_id_range, subscription_channel};

pub(crate) type Notification<'a> = jsonrpsee_types::Notification<'a, Option<serde_json::Value>>;

Expand Down Expand Up @@ -536,8 +536,8 @@ impl ClientT for Client {
let id_range = generate_batch_id_range(id, batch.len() as u64)?;

let mut batches = Vec::with_capacity(batch.len());
for ((method, params), id) in batch.into_iter().zip(id_range.clone()) {
let id = self.id_manager.as_id_kind().into_id(id);
for ((method, params), _id) in batch.into_iter().zip(id_range.clone()) {
let id = self.id_manager.next_request_id();
batches.push(RequestSer {
jsonrpc: TwoPointZero,
id,
Expand Down
25 changes: 14 additions & 11 deletions core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

pub mod error;
pub use error::Error;
use jsonrpsee_types::request::IdGeneratorFn;

use std::fmt;
use std::ops::Range;
Expand Down Expand Up @@ -425,7 +426,7 @@
type Item = Result<Notif, serde_json::Error>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Option<Self::Item>> {
let res = match futures_util::ready!(self.rx.poll_next_unpin(cx)) {
Some(v) => Some(serde_json::from_value::<Notif>(v).map_err(Into::into)),

Check warning on line 429 in core/src/client/mod.rs

View workflow job for this annotation

GitHub Actions / Check style

useless conversion to the same type: `serde_json::Error`
None => {
self.is_closed = true;
None
Expand Down Expand Up @@ -469,7 +470,17 @@

/// Attempts to get the next request ID.
pub fn next_request_id(&self) -> Id<'static> {
self.id_kind.into_id(self.current_id.next())
match self.id_kind {
IdKind::Number => {
let id = self.current_id.next();
Id::Number(id)
}
IdKind::String => {
let id = self.current_id.next();
Id::Str(format!("{id}").into())
}
IdKind::Custom(generator) => generator.call(),
}
}

/// Get a handle to the `IdKind`.
Expand All @@ -485,16 +496,8 @@
String,
/// Number.
Number,
}

impl IdKind {
/// Generate an `Id` from number.
pub fn into_id(self, id: u64) -> Id<'static> {
match self {
IdKind::Number => Id::Number(id),
IdKind::String => Id::Str(format!("{id}").into()),
}
}
/// Custom generator.
Custom(IdGeneratorFn),
}

#[derive(Debug)]
Expand Down
75 changes: 75 additions & 0 deletions examples/examples/core_client_with_request_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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::client_transport::ws::{Url, WsTransportClientBuilder};
use jsonrpsee::core::client::{Client, ClientBuilder, ClientT, IdKind};
use jsonrpsee::rpc_params;
use jsonrpsee::server::{RpcModule, Server};
use jsonrpsee::types::{Id, IdGeneratorFn};

#[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 addr = run_server().await?;
let uri = Url::parse(&format!("ws://{}", addr))?;

let custom_generator = IdGeneratorFn::new(generate_timestamp_id);

let (tx, rx) = WsTransportClientBuilder::default().build(uri).await?;
let client: Client = ClientBuilder::default().id_format(IdKind::Custom(custom_generator)).build_with_tokio(tx, rx);

let response: String = client.request("say_hello", rpc_params![]).await?;
tracing::info!("response: {:?}", response);

Ok(())
}

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")?;
let addr = server.local_addr()?;

let handle = server.start(module);

// 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)
}

fn generate_timestamp_id() -> Id<'static> {
let timestamp =
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Time went backwards").as_secs();
Id::Number(timestamp)
}
2 changes: 1 addition & 1 deletion types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ pub mod error;

pub use error::{ErrorCode, ErrorObject, ErrorObjectOwned};
pub use params::{Id, InvalidRequestId, Params, ParamsSequence, SubscriptionId, TwoPointZero};
pub use request::{InvalidRequest, Notification, NotificationSer, Request, RequestSer};
pub use request::{IdGeneratorFn, InvalidRequest, Notification, NotificationSer, Request, RequestSer};
pub use response::{Response, ResponsePayload, SubscriptionPayload, SubscriptionResponse, Success as ResponseSuccess};
34 changes: 33 additions & 1 deletion types/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
//! Types to handle JSON-RPC requests according to the [spec](https://www.jsonrpc.org/specification#request-object).
//! Some types come with a "*Ser" variant that implements [`serde::Serialize`]; these are used in the client.

use std::borrow::Cow;
use std::{
borrow::Cow,
fmt::{Debug, Formatter, Result},
};

use crate::{
Params,
Expand Down Expand Up @@ -173,6 +176,35 @@ impl<'a> NotificationSer<'a> {
}
}

/// Custom id generator function
pub struct IdGeneratorFn(fn() -> Id<'static>);

impl IdGeneratorFn {
/// Creates a new `IdGeneratorFn` from a function pointer.
pub fn new(generator: fn() -> Id<'static>) -> Self {
IdGeneratorFn(generator)
}

/// Calls the id generator function
pub fn call(&self) -> Id<'static> {
(self.0)()
}
}

impl Copy for IdGeneratorFn {}

impl Clone for IdGeneratorFn {
fn clone(&self) -> Self {
*self
}
}

impl Debug for IdGeneratorFn {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.write_str("<CustomIdGenerator>")
}
}

#[cfg(test)]
mod test {
use super::{Cow, Id, InvalidRequest, Notification, NotificationSer, Request, RequestSer, TwoPointZero};
Expand Down
Loading