Skip to main content

bitcoind_client/
client.rs

1//! [`Client`]
2
3use alloc::string::ToString;
4use core::future::Future;
5use core::sync::atomic::{AtomicUsize, Ordering};
6
7use jsonrpc::serde_json;
8use jsonrpc::{Request, Response};
9use serde::Deserialize;
10use serde_json::{
11    json,
12    value::{RawValue, Value},
13};
14
15use crate::Error;
16use crate::Rpc;
17
18/// JSONRPC protocol version.
19const JSONRPC: &str = "2.0";
20
21/// Client
22#[derive(Debug)]
23pub struct Client {
24    /// Unique ID of the request, increments atomically for each new request.
25    id: AtomicUsize,
26}
27
28impl Default for Client {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl Client {
35    /// New.
36    pub fn new() -> Self {
37        Self {
38            id: AtomicUsize::new(0),
39        }
40    }
41
42    /// Execute the RPC.
43    pub fn call<T, E>(
44        &self,
45        rpc: Rpc,
46        params: &[Value],
47        send_fn: impl Fn(Request) -> Result<Response, E>,
48    ) -> Result<T, Error>
49    where
50        T: for<'de> Deserialize<'de>,
51        E: core::error::Error + Send + Sync + 'static,
52    {
53        let method = rpc.to_string();
54        let raw_value = if params.is_empty() {
55            None
56        } else {
57            Some(serde_json::value::to_raw_value(params)?)
58        };
59        let request = self.request(&method, raw_value.as_deref());
60        let request_id = request.id.clone();
61        let response = send_fn(request).map_err(Error::transport)?;
62        if response.id != request_id {
63            return Err(Error::IdMismatch);
64        }
65        Ok(response.result()?)
66    }
67
68    /// Execute the RPC asynchronously.
69    pub async fn call_async<T, E, F, Fut>(
70        &self,
71        rpc: Rpc,
72        params: &[Value],
73        send_fn: F,
74    ) -> Result<T, Error>
75    where
76        T: for<'de> Deserialize<'de>,
77        E: core::error::Error + Send + Sync + 'static,
78        F: Fn(Value) -> Fut,
79        Fut: Future<Output = Result<Response, E>>,
80    {
81        let method = rpc.to_string();
82        let raw_value = if params.is_empty() {
83            None
84        } else {
85            Some(serde_json::value::to_raw_value(params)?)
86        };
87        let request = self.request(&method, raw_value.as_deref());
88        let request_id = request.id.clone();
89        let value = serde_json::to_value(request)?;
90        let response = send_fn(value).await.map_err(Error::transport)?;
91        if response.id != request_id {
92            return Err(Error::IdMismatch);
93        }
94        Ok(response.result()?)
95    }
96
97    /// Forms the [`Request`] and increments the internal request id.
98    fn request<'a>(&self, method: &'a str, params: Option<&'a RawValue>) -> Request<'a> {
99        let id = self.id.fetch_add(1, Ordering::Relaxed);
100        Request {
101            method,
102            params,
103            id: json!(id),
104            jsonrpc: Some(JSONRPC),
105        }
106    }
107}