Skip to content

Commit 4ade38c

Browse files
committed
use reqwest instead of jsonrpc http implementation
1 parent bde02d7 commit 4ade38c

File tree

3 files changed

+60
-19
lines changed

3 files changed

+60
-19
lines changed

client/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ bitcoincore-rpc-json = { version = "0.16.0", path = "../json" }
2323

2424
log = "0.4.5"
2525
jsonrpc = "0.13.0"
26+
reqwest = { version = "0.11", features = ["blocking", "json"] }
2627

2728
# Used for deserialization of JSON.
2829
serde = "1"
29-
serde_json = "1"
30+
serde_json = {version = "1", features = ["raw_value"]}

client/src/client.rs

+56-17
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ use std::collections::HashMap;
1212
use std::fs::File;
1313
use std::iter::FromIterator;
1414
use std::path::PathBuf;
15+
use std::str::FromStr;
16+
use std::sync::atomic;
1517
use std::{fmt, result};
1618

1719
use crate::{bitcoin, deserialize_hex};
18-
use jsonrpc;
1920
use serde;
2021
use serde_json;
2122

@@ -1195,7 +1196,10 @@ pub trait RpcApi: Sized {
11951196

11961197
/// Client implements a JSON-RPC client for the Bitcoin Core daemon or compatible APIs.
11971198
pub struct Client {
1198-
client: jsonrpc::client::Client,
1199+
client: reqwest::blocking::Client,
1200+
url: String,
1201+
auth: Auth,
1202+
nonce: atomic::AtomicUsize,
11991203
}
12001204

12011205
impl fmt::Debug for Client {
@@ -1209,23 +1213,27 @@ impl Client {
12091213
///
12101214
/// Can only return [Err] when using cookie authentication.
12111215
pub fn new(url: &str, auth: Auth) -> Result<Self> {
1212-
let (user, pass) = auth.get_user_pass()?;
1213-
jsonrpc::client::Client::simple_http(url, user, pass)
1214-
.map(|client| Client {
1215-
client,
1216-
})
1217-
.map_err(|e| super::error::Error::JsonRpc(e.into()))
1216+
let client = reqwest::blocking::Client::builder().build().map_err(|e| super::error::Error::Http(e))?;
1217+
Ok(Self{
1218+
client,
1219+
auth: auth,
1220+
url: String::from_str(url).unwrap(),
1221+
nonce: atomic::AtomicUsize::new(1),
1222+
})
12181223
}
12191224

1220-
/// Create a new Client using the given [jsonrpc::Client].
1221-
pub fn from_jsonrpc(client: jsonrpc::client::Client) -> Client {
1225+
/// Create a new Client using the given [reqwest::blocking::Client].
1226+
pub fn from_reqwest(client: reqwest::blocking::Client, url: &str) -> Client {
12221227
Client {
12231228
client,
1229+
url: String::from_str(url).unwrap(),
1230+
auth: Auth::None,
1231+
nonce: atomic::AtomicUsize::new(1),
12241232
}
12251233
}
12261234

12271235
/// Get the underlying JSONRPC client.
1228-
pub fn get_jsonrpc_client(&self) -> &jsonrpc::client::Client {
1236+
pub fn get_reqwest_client(&self) -> &reqwest::blocking::Client {
12291237
&self.client
12301238
}
12311239
}
@@ -1245,14 +1253,45 @@ impl RpcApi for Client {
12451253
})
12461254
.map(|a| a.map_err(|e| Error::Json(e)))
12471255
.collect::<Result<Vec<_>>>()?;
1248-
let req = self.client.build_request(&cmd, &raw_args);
1249-
if log_enabled!(Debug) {
1250-
debug!(target: "bitcoincore_rpc", "JSON-RPC request: {} {}", cmd, serde_json::Value::from(args));
1256+
1257+
let nonce = self.nonce.fetch_add(1, atomic::Ordering::Relaxed);
1258+
let body = jsonrpc::Request{
1259+
method: cmd,
1260+
params: raw_args.as_slice(),
1261+
id: serde_json::Value::from(nonce),
1262+
jsonrpc: Some("2.0"),
1263+
};
1264+
let id = body.id.clone();
1265+
let mut request = self.client
1266+
.post(self.url.as_str())
1267+
.body(serde_json::to_vec(&body)?);
1268+
1269+
1270+
request = match &self.auth {
1271+
Auth::UserPass(user, pass) => request.basic_auth(user, Some(pass)),
1272+
Auth::CookieFile(_)=> {
1273+
let (user, pass) = self.auth.clone().get_user_pass()?;
1274+
request.basic_auth(user.unwrap(), pass)
1275+
}
1276+
Auth::None => request,
1277+
};
1278+
1279+
let response = request.send();
1280+
1281+
let response = response.map_err(|e| Error::Http(e))?;
1282+
let buffer = response.bytes().unwrap();
1283+
let jsonrpc_response_maybe: Result<jsonrpc::Response> = serde_json::from_slice(&buffer).map_err(|e| Error::Json(e));
1284+
log_response(cmd, &jsonrpc_response_maybe);
1285+
let jsonrpc_response = jsonrpc_response_maybe?;
1286+
1287+
if jsonrpc_response.jsonrpc.is_some() && jsonrpc_response.jsonrpc != Some(From::from("2.0")) {
1288+
return Err(Error::JsonRpc(jsonrpc::error::Error::VersionMismatch));
1289+
}
1290+
if jsonrpc_response.id != id {
1291+
return Err(Error::JsonRpc(jsonrpc::error::Error::NonceMismatch));
12511292
}
12521293

1253-
let resp = self.client.send_request(req).map_err(Error::from);
1254-
log_response(cmd, &resp);
1255-
Ok(resp?.result()?)
1294+
jsonrpc_response.result().map_err(Error::JsonRpc)
12561295
}
12571296
}
12581297

client/src/error.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ use std::{error, fmt, io};
1313
use crate::bitcoin;
1414
use crate::bitcoin::hashes::hex;
1515
use crate::bitcoin::secp256k1;
16-
use jsonrpc;
1716
use serde_json;
1817

1918
/// The error type for errors produced in this library.
2019
#[derive(Debug)]
2120
pub enum Error {
2221
JsonRpc(jsonrpc::error::Error),
22+
Http(reqwest::Error),
2323
Hex(hex::Error),
2424
Json(serde_json::error::Error),
2525
BitcoinSerialization(bitcoin::consensus::encode::Error),
@@ -79,6 +79,7 @@ impl fmt::Display for Error {
7979
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8080
match *self {
8181
Error::JsonRpc(ref e) => write!(f, "JSON-RPC error: {}", e),
82+
Error::Http(ref e) => write!(f, "HTTP error: {}", e),
8283
Error::Hex(ref e) => write!(f, "hex decode error: {}", e),
8384
Error::Json(ref e) => write!(f, "JSON error: {}", e),
8485
Error::BitcoinSerialization(ref e) => write!(f, "Bitcoin serialization error: {}", e),

0 commit comments

Comments
 (0)