#![deny(missing_docs)]
#[macro_use]
pub extern crate error_chain;
#[macro_use]
extern crate futures;
extern crate jsonrpc_core;
#[macro_use]
extern crate log;
extern crate serde;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
use futures::future::Future;
use futures::Async;
use jsonrpc_core::types::{Id, MethodCall, Params, Version};
use serde_json::Value as JsonValue;
#[macro_use]
mod macros;
mod response;
pub mod example;
error_chain! {
errors {
TransportError {
description("Unable to send the JSON-RPC 2.0 request")
}
SerializeError {
description("Unable to serialize the method parameters")
}
ResponseError(msg: &'static str) {
description("Unable to deserialize the response into the desired type")
display("Unable to deserialize the response: {}", msg)
}
JsonRpcError(error: jsonrpc_core::Error) {
description("Method call returned JSON-RPC 2.0 error")
display("JSON-RPC 2.0 Error: {} ({})", error.code.description(), error.message)
}
}
}
pub struct RpcRequest<T, F>(::std::result::Result<InnerRpcRequest<T, F>, Option<Error>>);
impl<T, E, F> RpcRequest<T, F>
where
T: serde::de::DeserializeOwned + Send + 'static,
E: ::std::error::Error + Send + 'static,
F: Future<Item = Vec<u8>, Error = E> + Send + 'static,
{
pub fn call(self) -> Result<T> {
self.wait()
}
}
impl<T, E, F> Future for RpcRequest<T, F>
where
T: serde::de::DeserializeOwned + Send + 'static,
E: ::std::error::Error + Send + 'static,
F: Future<Item = Vec<u8>, Error = E> + Send + 'static,
{
type Item = T;
type Error = Error;
fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
match self.0 {
Ok(ref mut inner) => inner.poll(),
Err(ref mut error_option) => Err(error_option
.take()
.expect("Cannot call RpcRequest poll twice when in error state")),
}
}
}
struct InnerRpcRequest<T, F> {
transport_future: F,
id: Id,
_marker: ::std::marker::PhantomData<T>,
}
impl<T, F> InnerRpcRequest<T, F> {
fn new(transport_future: F, id: Id) -> Self {
Self {
transport_future,
id,
_marker: ::std::marker::PhantomData,
}
}
}
impl<T, E, F> Future for InnerRpcRequest<T, F>
where
T: serde::de::DeserializeOwned + Send + 'static,
E: ::std::error::Error + Send + 'static,
F: Future<Item = Vec<u8>, Error = E> + Send + 'static,
{
type Item = T;
type Error = Error;
fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
let response_raw = try_ready!(
self.transport_future
.poll()
.chain_err(|| ErrorKind::TransportError)
);
trace!(
"Deserializing {} byte response to request with id {:?}",
response_raw.len(),
self.id
);
response::parse(&response_raw, &self.id).map(|t| Async::Ready(t))
}
}
pub trait Transport {
type Future: Future<Item = Vec<u8>, Error = Self::Error> + Send + 'static;
type Error: ::std::error::Error + Send + 'static;
fn get_next_id(&mut self) -> u64;
fn send(&self, json_data: Vec<u8>) -> Self::Future;
}
pub fn call_method<T, P, R>(
transport: &mut T,
method: String,
params: P,
) -> RpcRequest<R, T::Future>
where
T: Transport,
P: serde::Serialize,
R: serde::de::DeserializeOwned + Send + 'static,
{
let id = Id::Num(transport.get_next_id());
trace!("Serializing call to method \"{}\" with id {:?}", method, id);
let request_serialization_result =
serialize_request(id.clone(), method, params).chain_err(|| ErrorKind::SerializeError);
match request_serialization_result {
Err(e) => RpcRequest(Err(Some(e))),
Ok(request_raw) => {
let transport_future = transport.send(request_raw);
RpcRequest(Ok(InnerRpcRequest::new(transport_future, id)))
}
}
}
fn serialize_request<P>(
id: Id,
method: String,
params: P,
) -> ::std::result::Result<Vec<u8>, serde_json::error::Error>
where
P: serde::Serialize,
{
let serialized_params = match serde_json::to_value(params)? {
JsonValue::Null => None,
JsonValue::Array(vec) => Some(Params::Array(vec)),
JsonValue::Object(obj) => Some(Params::Map(obj)),
value => Some(Params::Array(vec![value])),
};
let method_call = MethodCall {
jsonrpc: Some(Version::V2),
method,
params: serialized_params,
id,
};
serde_json::to_vec(&method_call)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io;
pub type BoxFuture<T, E> = Box<Future<Item = T, Error = E> + Send>;
#[derive(Clone)]
struct EchoTransport;
impl Transport for EchoTransport {
type Future = BoxFuture<Vec<u8>, io::Error>;
type Error = io::Error;
fn get_next_id(&mut self) -> u64 {
1
}
fn send(&self, json_data: Vec<u8>) -> Self::Future {
let json = json!({
"jsonrpc": "2.0",
"id": 1,
"result": serde_json::from_slice::<JsonValue>(&json_data).unwrap(),
});
Box::new(futures::future::ok(serde_json::to_vec(&json).unwrap()))
}
}
#[derive(Clone)]
struct InvalidRequestTransport;
impl Transport for InvalidRequestTransport {
type Future = BoxFuture<Vec<u8>, io::Error>;
type Error = io::Error;
fn get_next_id(&mut self) -> u64 {
1
}
fn send(&self, _json_data: Vec<u8>) -> Self::Future {
let json = json!({
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "This was an invalid request",
"data": [1, 2, 3],
}
});
Box::new(futures::future::ok(serde_json::to_vec(&json).unwrap()))
}
}
#[derive(Clone)]
struct ErrorTransport;
impl Transport for ErrorTransport {
type Future = BoxFuture<Vec<u8>, io::Error>;
type Error = io::Error;
fn get_next_id(&mut self) -> u64 {
1
}
fn send(&self, _json_data: Vec<u8>) -> Self::Future {
Box::new(futures::future::err(io::Error::new(
io::ErrorKind::Other,
"Internal transport error",
)))
}
}
jsonrpc_client!(pub struct TestRpcClient {
pub fn ping(&mut self, arg0: &str) -> RpcRequest<JsonValue>;
});
#[test]
fn echo() {
let mut client = TestRpcClient::new(EchoTransport);
let result = client.ping("Hello").call().unwrap();
if let JsonValue::Object(map) = result {
assert_eq!(Some(&JsonValue::from("2.0")), map.get("jsonrpc"));
assert_eq!(Some(&JsonValue::from(1)), map.get("id"));
assert_eq!(Some(&JsonValue::from("ping")), map.get("method"));
assert_eq!(Some(&JsonValue::from(vec!["Hello"])), map.get("params"));
assert_eq!(4, map.len());
} else {
panic!("Invalid response type: {:?}", result);
}
}
#[test]
fn invalid_request() {
let mut client = TestRpcClient::new(InvalidRequestTransport);
let error = client.ping("").call().unwrap_err();
if let &ErrorKind::JsonRpcError(ref json_error) = error.kind() {
use jsonrpc_core::ErrorCode;
assert_eq!(ErrorCode::InvalidRequest, json_error.code);
assert_eq!("This was an invalid request", json_error.message);
assert_eq!(Some(json!{[1, 2, 3]}), json_error.data);
} else {
panic!("Wrong error kind");
}
}
#[test]
fn transport_error() {
let mut client = TestRpcClient::new(ErrorTransport);
match client.ping("").call().unwrap_err().kind() {
&ErrorKind::TransportError => (),
_ => panic!("Wrong error kind"),
}
}
}