Skip to content
Open
6 changes: 5 additions & 1 deletion core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ cfg_async_client! {

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

use std::fmt;
use std::ops::Range;
Expand Down Expand Up @@ -485,14 +486,17 @@ pub enum IdKind {
String,
/// Number.
Number,
/// Custom generator.
Custom(IdGeneratorFn),
}

impl IdKind {
/// Generate an `Id` from number.
/// Generate an `Id` from number or from a registered generator.
pub fn into_id(self, id: u64) -> Id<'static> {
match self {
IdKind::Number => Id::Number(id),
IdKind::String => Id::Str(format!("{id}").into()),
IdKind::Custom(generator) => generator.call(),
}
}
}
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