Skip to content

Commit e4c4577

Browse files
committed
POC generalized requests
1 parent d9a1dd0 commit e4c4577

File tree

1 file changed

+97
-25
lines changed

1 file changed

+97
-25
lines changed

client/src/client.rs

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use bitcoin;
1818
use jsonrpc;
1919
use serde;
2020
use serde_json;
21+
use serde_json::value::RawValue;
2122

2223
use bitcoin::hashes::hex::{FromHex, ToHex};
2324
use bitcoin::secp256k1::Signature;
@@ -215,14 +216,46 @@ impl Auth {
215216
}
216217
}
217218

218-
pub trait RpcApi: Sized {
219+
pub struct Request<'c, T: 'static> {
220+
method: &'static str,
221+
args: Vec<serde_json::Value>, //TODO(stevenroose) something more efficient?
222+
converter: &'static dyn Fn(&RawValue) -> Result<T>,
223+
client: &'c dyn RpcClient,
224+
}
225+
226+
impl<'c, T> Request<'c, T> {
227+
pub fn sync(self) -> Result<T> {
228+
let raw = self.client.call(self.method, &self.args)?;
229+
let conv = self.converter;
230+
conv(&raw)
231+
}
232+
233+
fn async(self) -> Result<T> {
234+
// use the async function of the client
235+
unimplemented!()
236+
}
237+
238+
fn batch(self, batch: &mut Batch<Self>) {
239+
batch.insert(self);
240+
}
241+
}
242+
243+
fn converter_hex<T: bitcoin::consensus::encode::Decodable>(raw: &RawValue) -> Result<T> {
244+
let hex: &str = serde_json::from_str(raw.get())?;
245+
let bytes = Vec::<u8>::from_hex(&hex)?;
246+
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
247+
}
248+
249+
fn converter_json<T: serde::de::DeserializeOwned>(raw: &RawValue) -> Result<T> {
250+
Ok(serde_json::from_str(raw.get())?)
251+
}
252+
253+
pub trait RpcClient {
219254
/// Call a `cmd` rpc with given `args` list
220-
fn call<T: for<'a> serde::de::Deserialize<'a>>(
221-
&self,
222-
cmd: &str,
223-
args: &[serde_json::Value],
224-
) -> Result<T>;
255+
fn call(&self, cmd: &str, args: &[serde_json::Value]) -> Result<Box<RawValue>>;
256+
}
225257

258+
pub trait RpcApi: RpcClient + Sized {
226259
/// Query an object implementing `Querable` type
227260
fn get_by_id<T: queryable::Queryable<Self>>(
228261
&self,
@@ -231,17 +264,58 @@ pub trait RpcApi: Sized {
231264
T::query(&self, &id)
232265
}
233266

267+
// this method could be moved outside of the trait
268+
fn get_network_info_request(&self) -> Request<json::GetNetworkInfoResult> {
269+
Request {
270+
method: "getnetworkinfo",
271+
args: vec![],
272+
converter: &|raw| converter_json::<json::GetNetworkInfoResult>(raw),
273+
client: self,
274+
}
275+
}
276+
#[cfg(not(feature = "async"))]
234277
fn get_network_info(&self) -> Result<json::GetNetworkInfoResult> {
235-
self.call("getnetworkinfo", &[])
278+
self.get_network_info_request().sync()
279+
}
280+
#[cfg(feature = "async")]
281+
async fn get_network_info(&self) -> Result<json::GetNetworkInfoResult> {
282+
self.get_network_info_request().async()
283+
}
284+
// this is some way through which it would be possible to have an API with both sync and async
285+
// methods when async is supported
286+
#[cfg(feature = "both-sync-async")]
287+
fn get_network_info_sync(&self) -> Result<json::GetNetworkInfoResult> {
288+
self.get_network_info_request().sync()
289+
}
290+
fn batch_get_network_info<R>(&self, batch: &mut Batch<R>) where Self: Sized {
291+
self.get_network_info_request().batch(batch);
236292
}
237293

238-
fn version(&self) -> Result<usize> {
239-
#[derive(Deserialize)]
240-
struct Response {
241-
pub version: usize,
294+
fn version_request(&self) -> Request<usize> {
295+
Request {
296+
method: "getnetworkinfo",
297+
args: vec![],
298+
converter: &|raw| {
299+
#[derive(Deserialize)]
300+
struct Response {
301+
pub version: usize,
302+
}
303+
let ret: Response = serde_json::from_str(raw.get())?;
304+
Ok(ret.version)
305+
},
306+
client: self,
242307
}
243-
let res: Response = self.call("getnetworkinfo", &[])?;
244-
Ok(res.version)
308+
}
309+
#[cfg(not(feature = "async"))]
310+
fn version(&self) -> Result<usize> {
311+
self.version_request().sync()
312+
}
313+
#[cfg(feature = "async")]
314+
fn version(&self) -> Result<usize> {
315+
self.version_request().async()
316+
}
317+
fn batch_version<R>(&self, batch: &mut Batch<R>) where Self: Sized {
318+
self.version_request().batch(batch);
245319
}
246320

247321
fn add_multisig_address(
@@ -747,7 +821,7 @@ pub trait RpcApi: Sized {
747821
tx: R,
748822
options: Option<&json::FundRawTransactionOptions>,
749823
is_witness: Option<bool>,
750-
) -> Result<json::FundRawTransactionResult> {
824+
) -> Result<json::FundRawTransactionResult> where Self: Sized {
751825
let mut args = [tx.raw_hex().into(), opt_into_json(options)?, opt_into_json(is_witness)?];
752826
let defaults = [empty_obj(), null()];
753827
self.call("fundrawtransaction", handle_defaults(&mut args, &defaults))
@@ -760,7 +834,7 @@ pub trait RpcApi: Sized {
760834
utxos: Option<&[json::SignRawTransactionInput]>,
761835
private_keys: Option<&[PrivateKey]>,
762836
sighash_type: Option<json::SigHashType>,
763-
) -> Result<json::SignRawTransactionResult> {
837+
) -> Result<json::SignRawTransactionResult> where Self: Sized {
764838
let mut args = [
765839
tx.raw_hex().into(),
766840
opt_into_json(utxos)?,
@@ -776,7 +850,7 @@ pub trait RpcApi: Sized {
776850
tx: R,
777851
utxos: Option<&[json::SignRawTransactionInput]>,
778852
sighash_type: Option<json::SigHashType>,
779-
) -> Result<json::SignRawTransactionResult> {
853+
) -> Result<json::SignRawTransactionResult> where Self: Sized {
780854
let mut args = [tx.raw_hex().into(), opt_into_json(utxos)?, opt_into_json(sighash_type)?];
781855
let defaults = [empty_arr(), null()];
782856
self.call("signrawtransactionwithwallet", handle_defaults(&mut args, &defaults))
@@ -788,7 +862,7 @@ pub trait RpcApi: Sized {
788862
privkeys: &[PrivateKey],
789863
prevtxs: Option<&[json::SignRawTransactionInput]>,
790864
sighash_type: Option<json::SigHashType>,
791-
) -> Result<json::SignRawTransactionResult> {
865+
) -> Result<json::SignRawTransactionResult> where Self: Sized {
792866
let mut args = [
793867
tx.raw_hex().into(),
794868
into_json(privkeys)?,
@@ -802,7 +876,7 @@ pub trait RpcApi: Sized {
802876
fn test_mempool_accept<R: RawTx>(
803877
&self,
804878
rawtxs: &[R],
805-
) -> Result<Vec<json::TestMempoolAcceptResult>> {
879+
) -> Result<Vec<json::TestMempoolAcceptResult>> where Self: Sized {
806880
let hexes: Vec<serde_json::Value> =
807881
rawtxs.to_vec().into_iter().map(|r| r.raw_hex().into()).collect();
808882
self.call("testmempoolaccept", &[hexes.into()])
@@ -999,7 +1073,7 @@ pub trait RpcApi: Sized {
9991073
self.call("ping", &[])
10001074
}
10011075

1002-
fn send_raw_transaction<R: RawTx>(&self, tx: R) -> Result<bitcoin::Txid> {
1076+
fn send_raw_transaction<R: RawTx>(&self, tx: R) -> Result<bitcoin::Txid> where Self: Sized {
10031077
self.call("sendrawtransaction", &[tx.raw_hex().into()])
10041078
}
10051079

@@ -1188,13 +1262,9 @@ impl Client {
11881262
}
11891263
}
11901264

1191-
impl RpcApi for Client {
1265+
impl RpcClient for Client {
11921266
/// Call an `cmd` rpc with given `args` list
1193-
fn call<T: for<'a> serde::de::Deserialize<'a>>(
1194-
&self,
1195-
cmd: &str,
1196-
args: &[serde_json::Value],
1197-
) -> Result<T> {
1267+
fn call(&self, cmd: &str, args: &[serde_json::Value]) -> Result<Box<RawValue>> {
11981268
let raw_args: Vec<_> = args
11991269
.iter()
12001270
.map(|a| {
@@ -1213,6 +1283,8 @@ impl RpcApi for Client {
12131283
Ok(resp?.result()?)
12141284
}
12151285
}
1286+
impl RpcApi for Client {
1287+
}
12161288

12171289
fn log_response(cmd: &str, resp: &Result<jsonrpc::Response>) {
12181290
if log_enabled!(Warn) || log_enabled!(Debug) || log_enabled!(Trace) {

0 commit comments

Comments
 (0)