feat: add reconnecting-rpc-client (#1396)

* initial commit

* update to reconnecting-ws-client v0.2

* re-export: reconnecting_rpc_client behind feature

* add helper function for reconnect

* fix nit in example

* simplify code without weird error fmt

* address grumbles

* address grumbles

* update reconnecting-ws-client 0.3

* cleanup error message
This commit is contained in:
Niklas Adolfsson
2024-02-08 13:19:06 +01:00
committed by GitHub
parent 61ab6b915e
commit cb67f94455
7 changed files with 287 additions and 16 deletions
+6 -2
View File
@@ -60,9 +60,13 @@ crate::macros::cfg_jsonrpsee! {
mod jsonrpsee_impl;
}
crate::macros::cfg_reconnecting_rpc_client! {
mod reconnecting_jsonrpsee_impl;
pub use reconnecting_jsonrpsee_ws_client as reconnecting_rpc_client;
}
mod rpc_client;
mod rpc_client_t;
pub use rpc_client_t::{RawRpcFuture, RawRpcSubscription, RawValue, RpcClientT};
pub use rpc_client::{rpc_params, RpcClient, RpcParams, RpcSubscription};
pub use rpc_client_t::{RawRpcFuture, RawRpcSubscription, RawValue, RpcClientT};
@@ -0,0 +1,52 @@
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use super::{RawRpcFuture, RawRpcSubscription, RpcClientT};
use crate::error::RpcError;
use futures::{FutureExt, StreamExt, TryStreamExt};
use reconnecting_jsonrpsee_ws_client::SubscriptionId;
use serde_json::value::RawValue;
impl RpcClientT for reconnecting_jsonrpsee_ws_client::Client {
fn request_raw<'a>(
&'a self,
method: &'a str,
params: Option<Box<RawValue>>,
) -> RawRpcFuture<'a, Box<RawValue>> {
async {
self.request_raw(method.to_string(), params)
.await
.map_err(|e| RpcError::ClientError(Box::new(e)))
}
.boxed()
}
fn subscribe_raw<'a>(
&'a self,
sub: &'a str,
params: Option<Box<RawValue>>,
unsub: &'a str,
) -> RawRpcFuture<'a, RawRpcSubscription> {
async {
let sub = self
.subscribe_raw(sub.to_string(), params, unsub.to_string())
.await
.map_err(|e| RpcError::ClientError(Box::new(e)))?;
let id = match sub.id() {
SubscriptionId::Num(n) => n.to_string(),
SubscriptionId::Str(s) => s.to_string(),
};
let stream = sub
.map_err(|e| RpcError::DisconnectedWillReconnect(e.to_string()))
.boxed();
Ok(RawRpcSubscription {
stream,
id: Some(id),
})
}
.boxed()
}
}
+10 -2
View File
@@ -6,8 +6,6 @@
mod dispatch_error;
use core::fmt::Debug;
crate::macros::cfg_unstable_light_client! {
pub use crate::client::LightClientError;
}
@@ -100,6 +98,13 @@ impl From<std::convert::Infallible> for Error {
}
}
impl Error {
/// Checks whether the error was caused by a RPC re-connection.
pub fn is_disconnected_will_reconnect(&self) -> bool {
matches!(self, Error::Rpc(RpcError::DisconnectedWillReconnect(_)))
}
}
/// An RPC error. Since we are generic over the RPC client that is used,
/// the error is boxed and could be casted.
#[derive(Debug, thiserror::Error)]
@@ -120,6 +125,9 @@ pub enum RpcError {
/// The requested URL is insecure.
#[error("RPC error: insecure URL: {0}")]
InsecureUrl(String),
/// The connection was lost and automatically reconnected.
#[error("RPC error: the connection was lost `{0}`; reconnect automatically initiated")]
DisconnectedWillReconnect(String),
}
impl RpcError {
+15 -1
View File
@@ -52,7 +52,21 @@ macro_rules! cfg_jsonrpsee_web {
}
}
pub(crate) use {cfg_feature, cfg_jsonrpsee, cfg_substrate_compat, cfg_unstable_light_client};
#[allow(unused)]
macro_rules! cfg_reconnecting_rpc_client {
($($item:item)*) => {
$(
#[cfg(all(feature = "unstable-reconnecting-rpc-client"))]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-reconnecting-rpc-client")))]
$item
)*
}
}
pub(crate) use {
cfg_feature, cfg_jsonrpsee, cfg_reconnecting_rpc_client, cfg_substrate_compat,
cfg_unstable_light_client,
};
// Only used by light-client.
#[allow(unused)]