mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 20:27:58 +00:00
Add subxt-historic crate for accesing historic (non head-of-chain) blocks (#2040)
* WIP subxt-historic * WIP subxt-historic * WIP subxt-historic; flesh out basic foundations * WIP filling in extrinsic decoding functionality * iter and decode transaction extensions * Fill in the Online/OfflineClient APIs and move more things to be part of the chain Config * WIP storage * clippy, fmt, finish extrinsics example * prep for 0.0.1 release to claim crate name * fix README link * fmt * WIP thinking about storage APIs * WIP working out storage APIs * Storage plain value fetching first pass * WIP storage: first pass iterating over values done * First apss finishing storage APIs * fmt and clippy * Create a storage example showing fetch and iteration * Bump to frame-decode 0.9.0 * Bump subxt-historic to 0.0.3 for preview release * Remove unused deps * fix import * clippy * doc fixes * tweak CI and fix some cargo hack findings * Update README: subxt-historic is prerelease
This commit is contained in:
@@ -14,6 +14,11 @@ use jsonrpsee::{
|
||||
};
|
||||
use serde_json::value::RawValue;
|
||||
|
||||
/// Construct a `jsonrpsee` RPC client with some sane defaults.
|
||||
pub async fn client(url: &str) -> Result<Client, Error> {
|
||||
jsonrpsee_helpers::client(url).await.map_err(|e| Error::Client(Box::new(e)))
|
||||
}
|
||||
|
||||
struct Params(Option<Box<RawValue>>);
|
||||
|
||||
impl ToRpcParams for Params {
|
||||
@@ -82,3 +87,51 @@ impl From<JsonrpseeError> for Error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helpers for a jsonrpsee specific RPC client.
|
||||
#[cfg(all(feature = "jsonrpsee", feature = "native"))]
|
||||
mod jsonrpsee_helpers {
|
||||
pub use jsonrpsee::{
|
||||
client_transport::ws::{self, EitherStream, Url, WsTransportClientBuilder},
|
||||
core::client::{Client, Error},
|
||||
};
|
||||
use tokio_util::compat::Compat;
|
||||
|
||||
pub type Sender = ws::Sender<Compat<EitherStream>>;
|
||||
pub type Receiver = ws::Receiver<Compat<EitherStream>>;
|
||||
|
||||
/// Build WS RPC client from URL
|
||||
pub async fn client(url: &str) -> Result<Client, Error> {
|
||||
let (sender, receiver) = ws_transport(url).await?;
|
||||
Ok(Client::builder()
|
||||
.max_buffer_capacity_per_subscription(4096)
|
||||
.build_with_tokio(sender, receiver))
|
||||
}
|
||||
|
||||
async fn ws_transport(url: &str) -> Result<(Sender, Receiver), Error> {
|
||||
let url = Url::parse(url).map_err(|e| Error::Transport(e.into()))?;
|
||||
WsTransportClientBuilder::default()
|
||||
.build(url)
|
||||
.await
|
||||
.map_err(|e| Error::Transport(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
// helpers for a jsonrpsee specific RPC client.
|
||||
#[cfg(all(feature = "jsonrpsee", feature = "web", target_arch = "wasm32"))]
|
||||
mod jsonrpsee_helpers {
|
||||
pub use jsonrpsee::{
|
||||
client_transport::web,
|
||||
core::client::{Client, ClientBuilder, Error},
|
||||
};
|
||||
|
||||
/// Build web RPC client from URL
|
||||
pub async fn client(url: &str) -> Result<Client, Error> {
|
||||
let (sender, receiver) = web::connect(url)
|
||||
.await
|
||||
.map_err(|e| Error::Transport(e.into()))?;
|
||||
Ok(ClientBuilder::default()
|
||||
.max_buffer_capacity_per_subscription(4096)
|
||||
.build_with_wasm(sender, receiver))
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,13 @@
|
||||
crate::macros::cfg_jsonrpsee! {
|
||||
mod jsonrpsee_impl;
|
||||
pub use jsonrpsee::core::client::Client as JsonrpseeRpcClient;
|
||||
pub use jsonrpsee_impl::client as jsonrpsee_client;
|
||||
}
|
||||
|
||||
crate::macros::cfg_unstable_light_client! {
|
||||
mod lightclient_impl;
|
||||
pub use subxt_lightclient::LightClientRpc as LightClientRpcClient;
|
||||
pub use subxt_lightclient::LightClient;
|
||||
}
|
||||
|
||||
crate::macros::cfg_reconnecting_rpc_client! {
|
||||
@@ -45,6 +47,9 @@ crate::macros::cfg_mock_rpc_client! {
|
||||
pub use mock_rpc_client::MockRpcClient;
|
||||
}
|
||||
|
||||
pub mod round_robin_rpc_client;
|
||||
pub use round_robin_rpc_client::RoundRobinRpcClient;
|
||||
|
||||
mod rpc_client;
|
||||
mod rpc_client_t;
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! This module exposes a [`RoundRobinRpcClient`], which is useful for load balancing
|
||||
//! requests across multiple RPC clients.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use subxt_rpcs::client::{RpcClient, RoundRobinRpcClient, jsonrpsee_client};
|
||||
//!
|
||||
//! // Construct some RpcClients (we'll make some jsonrpsee clients here, but
|
||||
//! // you could use anything which implements `RpcClientT`).
|
||||
//! let client1 = jsonrpsee_client("http://localhost:8080").await.unwrap();
|
||||
//! let client2 = jsonrpsee_client("http://localhost:8081").await.unwrap();
|
||||
//! let client3 = jsonrpsee_client("http://localhost:8082").await.unwrap();
|
||||
//!
|
||||
//! let round_robin_client = RoundRobinRpcClient::new(vec![client1, client2, client3]);
|
||||
//!
|
||||
//! // Build an RPC Client that can be used in Subxt or in conjunction with
|
||||
//! // the RPC methods provided in this crate.
|
||||
//! let rpc_client = RpcClient::new(round_robin_client);
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
use super::{RawRpcFuture, RawRpcSubscription, RpcClientT};
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
/// A simple RPC client which is provided a set of clients on initialization and
|
||||
/// will round-robin through them for each request.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoundRobinRpcClient<Client> {
|
||||
inner: Arc<RoundRobinRpcClientInner<Client>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RoundRobinRpcClientInner<Client> {
|
||||
clients: Vec<Client>,
|
||||
next_index: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<Client: RpcClientT> RoundRobinRpcClient<Client> {
|
||||
/// Create a new `RoundRobinRpcClient` with the given clients.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the `clients` vector is empty.
|
||||
pub fn new(clients: Vec<Client>) -> Self {
|
||||
assert!(!clients.is_empty(), "At least one client must be provided");
|
||||
Self {
|
||||
inner: Arc::new(RoundRobinRpcClientInner {
|
||||
clients,
|
||||
next_index: AtomicUsize::new(0),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_client(&self) -> &Client {
|
||||
let idx = self.next_index();
|
||||
&self.inner.clients[idx]
|
||||
}
|
||||
|
||||
fn next_index(&self) -> usize {
|
||||
// Note: fetch_add wraps on overflow so no need to handle this.
|
||||
self.inner.next_index.fetch_add(1, Ordering::Relaxed) % self.inner.clients.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client: RpcClientT> RpcClientT for RoundRobinRpcClient<Client> {
|
||||
fn request_raw<'a>(
|
||||
&'a self,
|
||||
method: &'a str,
|
||||
params: Option<Box<serde_json::value::RawValue>>,
|
||||
) -> RawRpcFuture<'a, Box<serde_json::value::RawValue>> {
|
||||
let client = self.next_client();
|
||||
client.request_raw(method, params)
|
||||
}
|
||||
|
||||
fn subscribe_raw<'a>(
|
||||
&'a self,
|
||||
sub: &'a str,
|
||||
params: Option<Box<serde_json::value::RawValue>>,
|
||||
unsub: &'a str,
|
||||
) -> RawRpcFuture<'a, RawRpcSubscription> {
|
||||
let client = self.next_client();
|
||||
client.subscribe_raw(sub, params, unsub)
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ impl RpcClient {
|
||||
///
|
||||
/// Allows insecure URLs without SSL encryption, e.g. (http:// and ws:// URLs).
|
||||
pub async fn from_insecure_url<U: AsRef<str>>(url: U) -> Result<Self, Error> {
|
||||
let client = jsonrpsee_helpers::client(url.as_ref())
|
||||
let client = super::jsonrpsee_client(url.as_ref())
|
||||
.await
|
||||
.map_err(|e| Error::Client(Box::new(e)))?;
|
||||
Ok(Self::new(client))
|
||||
@@ -242,51 +242,3 @@ impl<Res: DeserializeOwned> Stream for RpcSubscription<Res> {
|
||||
Poll::Ready(res)
|
||||
}
|
||||
}
|
||||
|
||||
// helpers for a jsonrpsee specific RPC client.
|
||||
#[cfg(all(feature = "jsonrpsee", feature = "native"))]
|
||||
mod jsonrpsee_helpers {
|
||||
pub use jsonrpsee::{
|
||||
client_transport::ws::{self, EitherStream, Url, WsTransportClientBuilder},
|
||||
core::client::{Client, Error},
|
||||
};
|
||||
use tokio_util::compat::Compat;
|
||||
|
||||
pub type Sender = ws::Sender<Compat<EitherStream>>;
|
||||
pub type Receiver = ws::Receiver<Compat<EitherStream>>;
|
||||
|
||||
/// Build WS RPC client from URL
|
||||
pub async fn client(url: &str) -> Result<Client, Error> {
|
||||
let (sender, receiver) = ws_transport(url).await?;
|
||||
Ok(Client::builder()
|
||||
.max_buffer_capacity_per_subscription(4096)
|
||||
.build_with_tokio(sender, receiver))
|
||||
}
|
||||
|
||||
async fn ws_transport(url: &str) -> Result<(Sender, Receiver), Error> {
|
||||
let url = Url::parse(url).map_err(|e| Error::Transport(e.into()))?;
|
||||
WsTransportClientBuilder::default()
|
||||
.build(url)
|
||||
.await
|
||||
.map_err(|e| Error::Transport(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
// helpers for a jsonrpsee specific RPC client.
|
||||
#[cfg(all(feature = "jsonrpsee", feature = "web", target_arch = "wasm32"))]
|
||||
mod jsonrpsee_helpers {
|
||||
pub use jsonrpsee::{
|
||||
client_transport::web,
|
||||
core::client::{Client, ClientBuilder, Error},
|
||||
};
|
||||
|
||||
/// Build web RPC client from URL
|
||||
pub async fn client(url: &str) -> Result<Client, Error> {
|
||||
let (sender, receiver) = web::connect(url)
|
||||
.await
|
||||
.map_err(|e| Error::Transport(e.into()))?;
|
||||
Ok(ClientBuilder::default()
|
||||
.max_buffer_capacity_per_subscription(4096)
|
||||
.build_with_wasm(sender, receiver))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user