Skip to content

Commit 0d4f49b

Browse files
authored
Extract client plumbing from derive, fix circular dependency (paritytech#417)
* Update core-client name in publish script * Remove circular dependency for client-core test * Use TypedClient in client derive macro * Remove generate_client_method, inline the code * Fix derive client compilation * Don't panic * Remove unused log dependency from derive * Make RpcMessage fields private * Remove redundant intos
1 parent a1c3bbe commit 0d4f49b

File tree

6 files changed

+116
-72
lines changed

6 files changed

+116
-72
lines changed

_automate/publish.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
set -exu
44

5-
ORDER=(core client server-utils tcp ws ws/client http ipc stdio pubsub derive test)
5+
ORDER=(core core-client server-utils tcp ws ws/client http ipc stdio pubsub derive test)
66

77
for crate in ${ORDER[@]}; do
88
cd $crate

core-client/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ failure = "0.1"
2323
futures = "~0.1.6"
2424
jsonrpc-core = { version = "11.0", path = "../core" }
2525
log = "0.4"
26+
serde = "1.0"
2627
serde_json = "1.0"
2728

2829
[dev-dependencies]
2930
jsonrpc-derive = { version = "11.0", path = "../derive" }
30-
jsonrpc-core-client = { version = "11.0", path = "." }
3131
serde = "1.0"
3232
tokio = "0.1"
3333

core-client/src/lib.rs

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
#![deny(missing_docs)]
33

44
use failure::{format_err, Fail};
5-
use futures::prelude::*;
5+
use futures::{future, prelude::*};
66
use futures::sync::{mpsc, oneshot};
77
use jsonrpc_core::{Call, Error, Id, MethodCall, Output, Params, Request, Response, Version};
88
use log::debug;
99
use serde_json::Value;
1010
use std::collections::HashMap;
1111
use std::collections::VecDeque;
12+
use serde::de::DeserializeOwned;
13+
use serde::Serialize;
1214

1315
/// The errors returned by the client.
1416
#[derive(Debug, Fail)]
@@ -67,12 +69,12 @@ impl Future for RpcFuture {
6769
/// the derive crate can generate a client.
6870
pub struct RpcMessage {
6971
/// The rpc method name.
70-
pub method: String,
72+
method: String,
7173
/// The rpc method parameters.
72-
pub params: Params,
74+
params: Params,
7375
/// The oneshot channel to send the result of the rpc
7476
/// call to.
75-
pub sender: oneshot::Sender<Result<Value, Error>>,
77+
sender: oneshot::Sender<Result<Value, Error>>,
7678
}
7779

7880
/// A channel to a `RpcClient`.
@@ -202,6 +204,83 @@ where
202204
}
203205
}
204206

207+
/// Client for raw JSON RPC requests
208+
#[derive(Clone)]
209+
pub struct RawClient(RpcChannel);
210+
211+
impl From<RpcChannel> for RawClient {
212+
fn from(channel: RpcChannel) -> Self {
213+
RawClient(channel)
214+
}
215+
}
216+
217+
impl RawClient {
218+
/// Call RPC with raw JSON
219+
pub fn call_method(&self, method: &str, params: Params) -> impl Future<Item=Value, Error=RpcError> {
220+
let (sender, receiver) = oneshot::channel();
221+
let msg = RpcMessage {
222+
method: method.into(),
223+
params,
224+
sender,
225+
};
226+
self.0
227+
.to_owned()
228+
.send(msg)
229+
.map_err(|error| RpcError::Other(error.into()))
230+
.and_then(|_| RpcFuture::new(receiver))
231+
}
232+
}
233+
234+
/// Client for typed JSON RPC requests
235+
#[derive(Clone)]
236+
pub struct TypedClient(RawClient);
237+
238+
impl From<RpcChannel> for TypedClient {
239+
fn from(channel: RpcChannel) -> Self {
240+
TypedClient(channel.into())
241+
}
242+
}
243+
244+
impl TypedClient {
245+
/// Create new TypedClient
246+
pub fn new(raw_cli: RawClient) -> Self {
247+
TypedClient(raw_cli)
248+
}
249+
250+
/// Call RPC with serialization of request and deserialization of response
251+
pub fn call_method<T: Serialize, R: DeserializeOwned + 'static>(
252+
&self,
253+
method: &str,
254+
returns: &'static str,
255+
args: T,
256+
) -> impl Future<Item=R, Error=RpcError> {
257+
let args = serde_json::to_value(args)
258+
.expect("Only types with infallible serialisation can be used for JSON-RPC");
259+
let params = match args {
260+
Value::Array(vec) => Params::Array(vec),
261+
Value::Null => Params::None,
262+
_ => return future::Either::A(future::err(RpcError::Other(
263+
format_err!("RPC params should serialize to a JSON array, or null")))),
264+
};
265+
266+
future::Either::B(
267+
self.0
268+
.call_method(method, params)
269+
.and_then(move |value: Value| {
270+
log::debug!("response: {:?}", value);
271+
let result = serde_json::from_value::<R>(value)
272+
.map_err(|error| {
273+
RpcError::ParseError(
274+
returns.into(),
275+
error.into(),
276+
)
277+
});
278+
future::done(result)
279+
})
280+
)
281+
}
282+
}
283+
205284
/// Rpc client implementation for `Deref<Target=MetaIoHandler<Metadata + Default>>`.
206285
pub mod local {
207286
use super::*;
@@ -284,12 +363,12 @@ pub mod local {
284363

285364
#[cfg(test)]
286365
mod tests {
287-
use futures::prelude::*;
288-
use jsonrpc_core_client::local;
366+
use super::*;
289367
use jsonrpc_core::{IoHandler, Result};
290368
use jsonrpc_derive::rpc;
369+
use crate::{TypedClient, RpcError, RpcChannel};
291370

292-
#[rpc]
371+
#[rpc(server)]
293372
pub trait Rpc {
294373
#[rpc(name = "add")]
295374
fn add(&self, a: u64, b: u64) -> Result<u64>;
@@ -303,11 +382,26 @@ mod tests {
303382
}
304383
}
305384

385+
#[derive(Clone)]
386+
struct AddClient(TypedClient);
387+
388+
impl From<RpcChannel> for AddClient {
389+
fn from(channel: RpcChannel) -> Self {
390+
AddClient(channel.into())
391+
}
392+
}
393+
394+
impl AddClient {
395+
fn add(&self, a: u64, b: u64) -> impl Future<Item=u64, Error=RpcError> {
396+
self.0.call_method("add", "u64", (a, b))
397+
}
398+
}
399+
306400
#[test]
307401
fn test_client_terminates() {
308402
let mut handler = IoHandler::new();
309403
handler.extend_with(RpcServer.to_delegate());
310-
let (client, rpc_client) = local::connect::<gen_client::Client, _, _>(handler);
404+
let (client, rpc_client) = local::connect::<AddClient, _, _>(handler);
311405
let fut = client
312406
.clone()
313407
.add(3, 4)

derive/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ jsonrpc-core = { version = "11.0", path = "../core" }
2323
jsonrpc-core-client = { version = "11.0", path = "../core-client" }
2424
jsonrpc-pubsub = { version = "11.0", path = "../pubsub" }
2525
jsonrpc-tcp-server = { version = "11.0", path = "../tcp" }
26-
log = "0.4"
2726
serde = "1.0"
2827
serde_derive = "1.0"
2928
serde_json = "1.0"

derive/src/to_client.rs

Lines changed: 12 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ pub fn generate_client_module(methods: &[MethodRegistration], item_trait: &syn::
4949
use _jsonrpc_core::futures::{future, Future, Sink};
5050
use _jsonrpc_core::futures::sync::oneshot;
5151
use _jsonrpc_core::serde_json::{self, Value};
52-
use _jsonrpc_core_client::{RpcChannel, RpcError, RpcFuture, RpcMessage};
52+
use _jsonrpc_core_client::{RpcChannel, RpcError, RpcFuture, RpcMessage, TypedClient};
5353

5454
/// The Client.
5555
#[derive(Clone)]
5656
pub struct Client#generics {
57-
sender: RpcChannel,
57+
inner: TypedClient,
5858
#(#markers_decl),*
5959
}
6060

@@ -65,38 +65,20 @@ pub fn generate_client_module(methods: &[MethodRegistration], item_trait: &syn::
6565
/// Creates a new `Client`.
6666
pub fn new(sender: RpcChannel) -> Self {
6767
Client {
68-
sender,
68+
inner: sender.into(),
6969
#(#markers_impl),*
7070
}
7171
}
7272

7373
#(#client_methods)*
74-
75-
fn call_method(
76-
&self,
77-
method: String,
78-
params: Params,
79-
) -> impl Future<Item=Value, Error=RpcError> {
80-
let (sender, receiver) = oneshot::channel();
81-
let msg = RpcMessage {
82-
method,
83-
params,
84-
sender,
85-
};
86-
self.sender
87-
.to_owned()
88-
.send(msg)
89-
.map_err(|error| RpcError::Other(error.into()))
90-
.and_then(|_| RpcFuture::new(receiver))
91-
}
9274
}
9375

9476
impl#generics From<RpcChannel> for Client#generics
9577
where
9678
#(#where_clause2),*
9779
{
9880
fn from(channel: RpcChannel) -> Self {
99-
Client::new(channel)
81+
Client::new(channel.into())
10082
}
10183
}
10284
}
@@ -119,7 +101,14 @@ fn generate_client_methods(methods: &[MethodRegistration]) -> Result<Vec<syn::Im
119101
continue;
120102
}
121103
};
122-
let client_method = generate_client_method(&attrs, rpc_name, name, &args, &arg_names, &returns);
104+
let returns_str = quote!(#returns).to_string();
105+
let client_method = syn::parse_quote! {
106+
#(#attrs)*
107+
pub fn #name(&self, #args) -> impl Future<Item=#returns, Error=RpcError> {
108+
let args_tuple = (#(#arg_names,)*);
109+
self.inner.call_method(#rpc_name, #returns_str, args_tuple)
110+
}
111+
};
123112
client_methods.push(client_method);
124113
}
125114
MethodRegistration::PubSub { .. } => {
@@ -130,43 +119,6 @@ fn generate_client_methods(methods: &[MethodRegistration]) -> Result<Vec<syn::Im
130119
Ok(client_methods)
131120
}
132121

133-
fn generate_client_method(
134-
attrs: &[syn::Attribute],
135-
rpc_name: &str,
136-
name: &syn::Ident,
137-
args: &Punctuated<syn::FnArg, syn::token::Comma>,
138-
arg_names: &[&syn::Ident],
139-
returns: &syn::Type,
140-
) -> syn::ImplItem {
141-
let returns_str = quote!(#returns).to_string();
142-
syn::parse_quote! {
143-
#(#attrs)*
144-
pub fn #name(&self, #args) -> impl Future<Item=#returns, Error=RpcError> {
145-
let args_tuple = (#(#arg_names,)*);
146-
let args = serde_json::to_value(args_tuple)
147-
.expect("Only types with infallible serialisation can be used for JSON-RPC");
148-
let method = #rpc_name.to_owned();
149-
let params = match args {
150-
Value::Array(vec) => Some(Params::Array(vec)),
151-
Value::Null => Some(Params::None),
152-
_ => None,
153-
}.expect("should never happen");
154-
self.call_method(method, params)
155-
.and_then(|value: Value| {
156-
log::debug!("response: {:?}", value);
157-
let result = serde_json::from_value::<#returns>(value)
158-
.map_err(|error| {
159-
RpcError::ParseError(
160-
#returns_str.to_string(),
161-
error.into(),
162-
)
163-
});
164-
future::done(result)
165-
})
166-
}
167-
}
168-
}
169-
170122
fn get_doc_comments(attrs: &[syn::Attribute]) -> Vec<syn::Attribute> {
171123
let mut doc_comments = vec![];
172124
for attr in attrs {

derive/tests/run-pass/client_only.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ extern crate jsonrpc_core;
33
extern crate jsonrpc_core_client;
44
#[macro_use]
55
extern crate jsonrpc_derive;
6-
extern crate log;
76

87
use jsonrpc_core::futures::future::Future;
98
use jsonrpc_core::futures::sync::mpsc;

0 commit comments

Comments
 (0)