@@ -12,10 +12,11 @@ use std::collections::HashMap;
12
12
use std:: fs:: File ;
13
13
use std:: iter:: FromIterator ;
14
14
use std:: path:: PathBuf ;
15
+ use std:: str:: FromStr ;
16
+ use std:: sync:: atomic;
15
17
use std:: { fmt, result} ;
16
18
17
19
use crate :: { bitcoin, deserialize_hex} ;
18
- use jsonrpc;
19
20
use serde;
20
21
use serde_json;
21
22
@@ -1195,12 +1196,14 @@ pub trait RpcApi: Sized {
1195
1196
1196
1197
/// Client implements a JSON-RPC client for the Bitcoin Core daemon or compatible APIs.
1197
1198
pub struct Client {
1198
- client : jsonrpc:: client:: Client ,
1199
+ url : String ,
1200
+ auth : Auth ,
1201
+ nonce : atomic:: AtomicUsize ,
1199
1202
}
1200
1203
1201
1204
impl fmt:: Debug for Client {
1202
1205
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
1203
- write ! ( f, "bitcoincore_rpc::Client({:?})" , self . client )
1206
+ write ! ( f, "bitcoincore_rpc::Client()" )
1204
1207
}
1205
1208
}
1206
1209
@@ -1209,25 +1212,20 @@ impl Client {
1209
1212
///
1210
1213
/// Can only return [Err] when using cookie authentication.
1211
1214
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 ( ) ) )
1218
- }
1219
-
1220
- /// Create a new Client using the given [jsonrpc::Client].
1221
- pub fn from_jsonrpc ( client : jsonrpc:: client:: Client ) -> Client {
1222
- Client {
1223
- client,
1224
- }
1215
+ Ok ( Self {
1216
+ auth : auth,
1217
+ url : String :: from_str ( url) . unwrap ( ) ,
1218
+ nonce : atomic:: AtomicUsize :: new ( 1 ) ,
1219
+ } )
1225
1220
}
1221
+ }
1226
1222
1227
- /// Get the underlying JSONRPC client.
1228
- pub fn get_jsonrpc_client ( & self ) -> & jsonrpc:: client:: Client {
1229
- & self . client
1230
- }
1223
+ fn auth_token ( user : & String , password : & String ) -> String {
1224
+ let mut auth = String :: new ( ) ;
1225
+ auth. push_str ( user) ;
1226
+ auth. push ( ':' ) ;
1227
+ auth. push_str ( password) ;
1228
+ base64:: encode ( auth. as_bytes ( ) )
1231
1229
}
1232
1230
1233
1231
impl RpcApi for Client {
@@ -1245,14 +1243,44 @@ impl RpcApi for Client {
1245
1243
} )
1246
1244
. map ( |a| a. map_err ( |e| Error :: Json ( e) ) )
1247
1245
. 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) ) ;
1246
+
1247
+ let nonce = self . nonce . fetch_add ( 1 , atomic:: Ordering :: Relaxed ) ;
1248
+ let body = jsonrpc:: Request {
1249
+ method : cmd,
1250
+ params : raw_args. as_slice ( ) ,
1251
+ id : serde_json:: Value :: from ( nonce) ,
1252
+ jsonrpc : Some ( "2.0" ) ,
1253
+ } ;
1254
+ let id = body. id . clone ( ) ;
1255
+
1256
+ let mut request = minreq:: post ( self . url . as_str ( ) )
1257
+ . with_body ( serde_json:: to_vec ( & body) ?) ;
1258
+
1259
+ request = match & self . auth {
1260
+ Auth :: UserPass ( user, pass) => request. with_header ( "Authorization" , format ! ( "Basic {}" , auth_token( user, pass) ) ) ,
1261
+ Auth :: CookieFile ( _) => {
1262
+ let ( user, pass) = self . auth . clone ( ) . get_user_pass ( ) ?;
1263
+ request. with_header ( "Authorization" , format ! ( "Basic {}" , auth_token( user. as_ref( ) . unwrap( ) , pass. as_ref( ) . unwrap( ) ) ) )
1264
+ }
1265
+ Auth :: None => request,
1266
+ } ;
1267
+
1268
+ let response = request. send ( ) ;
1269
+ let response = response. map_err ( |e| Error :: Http ( e) ) ?;
1270
+
1271
+ let buffer = response. as_bytes ( ) ;
1272
+ let jsonrpc_response_maybe: Result < jsonrpc:: Response > = serde_json:: from_slice ( & buffer) . map_err ( |e| Error :: Json ( e) ) ;
1273
+ log_response ( cmd, & jsonrpc_response_maybe) ;
1274
+ let jsonrpc_response = jsonrpc_response_maybe?;
1275
+
1276
+ if jsonrpc_response. jsonrpc . is_some ( ) && jsonrpc_response. jsonrpc != Some ( From :: from ( "2.0" ) ) {
1277
+ return Err ( Error :: JsonRpc ( jsonrpc:: error:: Error :: VersionMismatch ) ) ;
1278
+ }
1279
+ if jsonrpc_response. id != id {
1280
+ return Err ( Error :: JsonRpc ( jsonrpc:: error:: Error :: NonceMismatch ) ) ;
1251
1281
}
1252
1282
1253
- let resp = self . client . send_request ( req) . map_err ( Error :: from) ;
1254
- log_response ( cmd, & resp) ;
1255
- Ok ( resp?. result ( ) ?)
1283
+ jsonrpc_response. result ( ) . map_err ( Error :: JsonRpc )
1256
1284
}
1257
1285
}
1258
1286
0 commit comments