use crate::{
AsGear, Blocks, Events, ProgramStateChanges, Result, TxInBlock, UserMessageSentFilter,
UserMessageSentSubscription, config::GearConfig, gear::Event, signer::Signer,
};
use core::ops::{Deref, DerefMut};
use jsonrpsee::{client_transport::ws::Url, ws_client::WsClientBuilder};
use sp_core::H256;
use std::{borrow::Cow, time::Duration};
use subxt::{
OnlineClient,
backend::rpc::RpcClient,
ext::subxt_rpcs::{LegacyRpcMethods, rpc_params},
};
const ONE_HUNDRED_MEGABYTES: u32 = 100 * 1024 * 1024;
#[derive(Debug, Clone)]
pub struct Api {
rpc: RpcClient,
legacy_methods: LegacyRpcMethods<GearConfig>,
client: OnlineClient<GearConfig>,
}
#[derive(Debug, Clone, Default)]
pub struct ApiBuilder<'a> {
uri: Option<Cow<'a, str>>,
timeout: Option<Duration>,
}
impl Api {
pub const DEFAULT_ENDPOINT: &str = "wss://rpc.vara.network:443";
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
pub const fn builder<'a>() -> ApiBuilder<'a> {
ApiBuilder {
uri: None,
timeout: None,
}
}
}
impl<'a> ApiBuilder<'a> {
pub fn uri(mut self, uri: impl Into<Cow<'a, str>>) -> Self {
self.uri = Some(uri.into());
self
}
pub const fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub async fn build(self) -> Result<Api> {
Api::from_rpc_client(self.rpc_client().await?).await
}
async fn rpc_client(self) -> Result<RpcClient> {
let uri = self.uri.as_ref().map_or(Api::DEFAULT_ENDPOINT, Cow::as_ref);
let uri = Url::parse(uri)?;
let timeout = self.timeout.unwrap_or(Api::DEFAULT_TIMEOUT);
let client = WsClientBuilder::new()
.max_request_size(ONE_HUNDRED_MEGABYTES)
.connection_timeout(timeout)
.request_timeout(timeout)
.build(uri)
.await?;
Ok(RpcClient::new(client))
}
}
impl Api {
pub async fn new(uri: &str) -> Result<Self> {
Self::builder().uri(uri).build().await
}
pub async fn from_rpc_client(rpc: RpcClient) -> Result<Self> {
let legacy_methods = LegacyRpcMethods::new(rpc.clone());
let client = OnlineClient::from_rpc_client(rpc.clone()).await?;
Ok(Self {
rpc,
client,
legacy_methods,
})
}
pub async fn subscribe_blocks(&self) -> Result<Blocks> {
Ok(self.blocks().subscribe_all().await?.into())
}
pub async fn subscribe_finalized_blocks(&self) -> Result<Blocks> {
Ok(self.client.blocks().subscribe_finalized().await?.into())
}
pub async fn events(&self) -> Result<Events> {
Ok(self.client.blocks().subscribe_all().await?.into())
}
pub async fn events_of(&self, tx: &TxInBlock) -> Result<Vec<Event>> {
tx.fetch_events()
.await?
.iter()
.map(|e| -> Result<Event> { e?.as_gear() })
.collect::<Result<Vec<Event>>>()
}
pub async fn finalized_events(&self) -> Result<Events> {
Ok(self.client.blocks().subscribe_finalized().await?.into())
}
pub async fn subscribe_program_state_changes(
&self,
program_ids: Option<Vec<H256>>,
) -> Result<ProgramStateChanges> {
let subscription = self
.rpc()
.subscribe(
"gear_subscribeProgramStateChanges",
rpc_params![program_ids],
"gear_unsubscribeProgramStateChanges",
)
.await?;
Ok(ProgramStateChanges::new(subscription))
}
pub async fn subscribe_user_message_sent(
&self,
filter: UserMessageSentFilter,
) -> Result<UserMessageSentSubscription> {
let subscription = self
.rpc()
.subscribe(
"gear_subscribeUserMessageSent",
rpc_params![filter],
"gear_unsubscribeUserMessageSent",
)
.await?;
Ok(UserMessageSentSubscription::new(subscription))
}
pub fn signer(self, suri: &str, passwd: Option<&str>) -> Result<Signer> {
Signer::new(self, suri, passwd)
}
pub fn rpc(&self) -> &RpcClient {
&self.rpc
}
pub fn legacy(&self) -> &LegacyRpcMethods<GearConfig> {
&self.legacy_methods
}
}
impl Deref for Api {
type Target = OnlineClient<GearConfig>;
fn deref(&self) -> &Self::Target {
&self.client
}
}
impl DerefMut for Api {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.client
}
}