nonblocking.rs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. use crate::{
  2. AsSigner, ClientError, Config, EventContext, EventUnsubscriber, Program,
  3. ProgramAccountsIterator, RequestBuilder,
  4. };
  5. use anchor_lang::{prelude::Pubkey, AccountDeserialize, Discriminator};
  6. use solana_client::nonblocking::rpc_client::RpcClient as AsyncRpcClient;
  7. use solana_client::{rpc_config::RpcSendTransactionConfig, rpc_filter::RpcFilterType};
  8. use solana_sdk::{
  9. commitment_config::CommitmentConfig, signature::Signature, signer::Signer,
  10. transaction::Transaction,
  11. };
  12. use std::{marker::PhantomData, ops::Deref, sync::Arc};
  13. use tokio::sync::RwLock;
  14. impl<'a> EventUnsubscriber<'a> {
  15. /// Unsubscribe gracefully.
  16. pub async fn unsubscribe(self) {
  17. self.unsubscribe_internal().await
  18. }
  19. }
  20. pub trait ThreadSafeSigner: Signer + Send + Sync + 'static {
  21. fn to_signer(&self) -> &dyn Signer;
  22. }
  23. impl<T: Signer + Send + Sync + 'static> ThreadSafeSigner for T {
  24. fn to_signer(&self) -> &dyn Signer {
  25. self
  26. }
  27. }
  28. impl AsSigner for Arc<dyn ThreadSafeSigner> {
  29. fn as_signer(&self) -> &dyn Signer {
  30. self.to_signer()
  31. }
  32. }
  33. impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
  34. pub fn new(
  35. program_id: Pubkey,
  36. cfg: Config<C>,
  37. #[cfg(feature = "mock")] rpc_client: AsyncRpcClient,
  38. ) -> Result<Self, ClientError> {
  39. #[cfg(not(feature = "mock"))]
  40. let rpc_client = {
  41. let comm_config = cfg.options.unwrap_or_default();
  42. let cluster_url = cfg.cluster.url().to_string();
  43. AsyncRpcClient::new_with_commitment(cluster_url.clone(), comm_config)
  44. };
  45. Ok(Self {
  46. program_id,
  47. cfg,
  48. sub_client: Arc::new(RwLock::new(None)),
  49. internal_rpc_client: rpc_client,
  50. })
  51. }
  52. // We disable the `rpc` method for `mock` feature because otherwise we'd either have to
  53. // return a new `RpcClient` instance (which is different to the one used internally)
  54. // or require the user to pass another one in for blocking (since we use the non-blocking one under the hood).
  55. // The former of these would be confusing and the latter would be very annoying, especially since a user
  56. // using the mock feature likely already has a `RpcClient` instance at hand anyway.
  57. #[cfg(not(feature = "mock"))]
  58. pub fn rpc(&self) -> AsyncRpcClient {
  59. AsyncRpcClient::new_with_commitment(
  60. self.cfg.cluster.url().to_string(),
  61. self.cfg.options.unwrap_or_default(),
  62. )
  63. }
  64. /// Returns a threadsafe request builder
  65. pub fn request(&self) -> RequestBuilder<'_, C, Arc<dyn ThreadSafeSigner>> {
  66. RequestBuilder::from(
  67. self.program_id,
  68. self.cfg.cluster.url(),
  69. self.cfg.payer.clone(),
  70. self.cfg.options,
  71. &self.internal_rpc_client,
  72. )
  73. }
  74. /// Returns the account at the given address.
  75. pub async fn account<T: AccountDeserialize>(&self, address: Pubkey) -> Result<T, ClientError> {
  76. self.account_internal(address).await
  77. }
  78. /// Returns all program accounts of the given type matching the given filters
  79. pub async fn accounts<T: AccountDeserialize + Discriminator>(
  80. &self,
  81. filters: Vec<RpcFilterType>,
  82. ) -> Result<Vec<(Pubkey, T)>, ClientError> {
  83. self.accounts_lazy(filters).await?.collect()
  84. }
  85. /// Returns all program accounts of the given type matching the given filters as an iterator
  86. /// Deserialization is executed lazily
  87. pub async fn accounts_lazy<T: AccountDeserialize + Discriminator>(
  88. &self,
  89. filters: Vec<RpcFilterType>,
  90. ) -> Result<ProgramAccountsIterator<T>, ClientError> {
  91. self.accounts_lazy_internal(filters).await
  92. }
  93. /// Subscribe to program logs.
  94. ///
  95. /// Returns an [`EventUnsubscriber`] to unsubscribe and close connection gracefully.
  96. pub async fn on<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
  97. &self,
  98. f: impl Fn(&EventContext, T) + Send + 'static,
  99. ) -> Result<EventUnsubscriber, ClientError> {
  100. let (handle, rx) = self.on_internal(f).await?;
  101. Ok(EventUnsubscriber {
  102. handle,
  103. rx,
  104. _lifetime_marker: PhantomData,
  105. })
  106. }
  107. }
  108. impl<'a, C: Deref<Target = impl Signer> + Clone> RequestBuilder<'a, C, Arc<dyn ThreadSafeSigner>> {
  109. pub fn from(
  110. program_id: Pubkey,
  111. cluster: &str,
  112. payer: C,
  113. options: Option<CommitmentConfig>,
  114. rpc_client: &'a AsyncRpcClient,
  115. ) -> Self {
  116. Self {
  117. program_id,
  118. payer,
  119. cluster: cluster.to_string(),
  120. accounts: Vec::new(),
  121. options: options.unwrap_or_default(),
  122. instructions: Vec::new(),
  123. instruction_data: None,
  124. signers: Vec::new(),
  125. internal_rpc_client: rpc_client,
  126. _phantom: PhantomData,
  127. }
  128. }
  129. #[must_use]
  130. pub fn signer<T: ThreadSafeSigner>(mut self, signer: T) -> Self {
  131. self.signers.push(Arc::new(signer));
  132. self
  133. }
  134. pub async fn signed_transaction(&self) -> Result<Transaction, ClientError> {
  135. self.signed_transaction_internal().await
  136. }
  137. pub async fn send(self) -> Result<Signature, ClientError> {
  138. self.send_internal().await
  139. }
  140. pub async fn send_with_spinner_and_config(
  141. self,
  142. config: RpcSendTransactionConfig,
  143. ) -> Result<Signature, ClientError> {
  144. self.send_with_spinner_and_config_internal(config).await
  145. }
  146. }