use core::sync::atomic::{AtomicUsize, Ordering};
use jsonrpc::serde;
use jsonrpc::serde_json::value::RawValue;
use jsonrpc::serde_json::{self, Value, json};
use jsonrpc::{Request, Response};
use crate::Error;
const JSONRPC: &str = "2.0";
#[derive(Debug, Default)]
pub struct Client {
id: AtomicUsize,
}
impl Client {
pub fn new() -> Self {
Self {
id: AtomicUsize::new(0),
}
}
pub fn call<T, E>(
&self,
method: &str,
params: &[Value],
send_fn: impl Fn(Request) -> Result<Response, E>,
) -> Result<T, Error>
where
T: for<'de> serde::Deserialize<'de>,
E: core::error::Error + Send + Sync + 'static,
{
let raw = if params.is_empty() {
None
} else {
Some(serde_json::value::to_raw_value(params)?)
};
let request = self.build_request(method, raw.as_deref());
let request_id = request.id.clone();
let response = send_fn(request).map_err(Error::transport)?;
if response.id != request_id {
return Err(Error::JsonRpc(jsonrpc::Error::NonceMismatch));
}
Ok(response.result()?)
}
fn build_request<'a>(&self, method: &'a str, params: Option<&'a RawValue>) -> Request<'a> {
let id = self.id.fetch_add(1, Ordering::Relaxed);
Request {
method,
params,
id: json!(id),
jsonrpc: Some(JSONRPC),
}
}
}