neo3/neo_clients/rpc/transports/
rw.rs

1//! A [JsonRpcProvider] implementation that serves as a wrapper around two different [JsonRpcProvider]
2//! and uses a dedicated client for read and the other for write operations
3
4use crate::neo_clients::{JsonRpcProvider, ProviderError};
5use async_trait::async_trait;
6use serde::{de::DeserializeOwned, Serialize};
7use std::fmt::Display;
8use thiserror::Error;
9
10/// A client containing two clients.
11///
12/// One is used for _read_ operations
13/// One is used for _write_ operations that consume gas `["neo_sendTransaction",
14/// "neo_sendRawTransaction"]`
15///
16/// **Note**: if the method is unknown this client falls back to the _read_ client
17// # Example
18#[derive(Debug, Clone)]
19pub struct RwClient<Read, Write> {
20	/// client used to read
21	r: Read,
22	/// client used to write
23	w: Write,
24}
25
26impl<Read, Write> RwClient<Read, Write> {
27	/// Creates a new client using two different clients
28	///
29	/// # Example
30	///
31	/// ```no_run
32	/// use neo3::neo_clients::{HttpProvider, RwClient};
33	/// use url::Url;
34	///
35	/// # #[cfg(feature = "ws")]
36	/// async fn t() -> Result<(), Box<dyn std::error::Error>> {
37	///     let http = HttpProvider::new(Url::parse("http://localhost:8545").unwrap())?;
38	///     # #[cfg(feature = "ws")]
39	///     let ws = neo3::neo_clients::Ws::connect("ws://localhost:8545").await?;
40	///     # #[cfg(feature = "ws")]
41	///     let rw = RwClient::new(http, ws);
42	///     Ok(())
43	/// }
44	/// ```
45	pub fn new(r: Read, w: Write) -> RwClient<Read, Write> {
46		Self { r, w }
47	}
48
49	/// Returns the client used for read operations
50	pub fn read_client(&self) -> &Read {
51		&self.r
52	}
53
54	/// Returns the client used for write operations
55	pub fn write_client(&self) -> &Write {
56		&self.w
57	}
58
59	/// Returns a new `RwClient` with transposed clients
60	pub fn transpose(self) -> RwClient<Write, Read> {
61		let RwClient { r, w } = self;
62		RwClient::new(w, r)
63	}
64
65	/// Consumes the client and returns the underlying clients
66	pub fn split(self) -> (Read, Write) {
67		let RwClient { r, w } = self;
68		(r, w)
69	}
70}
71
72#[derive(Error, Debug)]
73/// Error thrown when using either read or write client
74pub enum RwClientError<Read, Write>
75where
76	Read: JsonRpcProvider,
77	<Read as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
78	Write: JsonRpcProvider,
79	<Write as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
80{
81	/// Thrown if the _read_ request failed
82	#[error("Read error: {0}")]
83	Read(Read::Error),
84	#[error("Write error: {0}")]
85	/// Thrown if the _write_ request failed
86	Write(Write::Error),
87}
88
89impl<Read, Write> From<RwClientError<Read, Write>> for ProviderError
90where
91	Read: JsonRpcProvider + 'static,
92	<Read as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
93	Write: JsonRpcProvider + 'static,
94	<Write as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
95{
96	fn from(src: RwClientError<Read, Write>) -> Self {
97		ProviderError::CustomError(src.to_string())
98	}
99}
100
101#[cfg_attr(target_arch = "wasm32", async_trait(? Send))]
102#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
103impl<Read, Write> JsonRpcProvider for RwClient<Read, Write>
104where
105	Read: JsonRpcProvider + 'static,
106	<Read as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
107	Write: JsonRpcProvider + 'static,
108	<Write as JsonRpcProvider>::Error: Sync + Send + 'static + Display,
109{
110	type Error = RwClientError<Read, Write>;
111
112	/// Sends a POST request with the provided method and the params serialized as JSON
113	/// over HTTP
114	async fn fetch<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
115	where
116		T: std::fmt::Debug + Serialize + Send + Sync,
117		R: DeserializeOwned + Send,
118	{
119		match method {
120			"neo_sendTransaction" | "neo_sendRawTransaction" =>
121				self.w.fetch(method, params).await.map_err(RwClientError::Write),
122			_ => self.r.fetch(method, params).await.map_err(RwClientError::Read),
123		}
124	}
125}