Skip to content

Commit

Permalink
Bump to 12.0 and change core-client transports a bit. (#440)
Browse files Browse the repository at this point in the history
* Rename http client method, tls enables http.

* Bump version.

* Add tagging to publish script.

* Make sure we generate nice docs for transports as well.

* Add transports to publish script.
  • Loading branch information
tomusdrw committed Jun 4, 2019
1 parent 1bbd403 commit 12b6210
Show file tree
Hide file tree
Showing 29 changed files with 338 additions and 291 deletions.
3 changes: 0 additions & 3 deletions .travis.yml
Expand Up @@ -32,9 +32,6 @@ before_script:
script:
- cargo build --all
- cargo test --all
- cargo test --manifest-path=core-client/Cargo.toml --features "http"
- cargo test --manifest-path=core-client/Cargo.toml --features "http, tls"
- cargo test --manifest-path=core-client/Cargo.toml --features "ws"
- |
([ $TRAVIS_RUST_VERSION = stable ] && cargo fmt --all -- --check) || true
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -2,6 +2,7 @@
members = [
"core",
"core-client",
"core-client/transports",
"http",
"ipc",
"derive",
Expand Down
11 changes: 10 additions & 1 deletion _automate/publish.sh
Expand Up @@ -2,11 +2,20 @@

set -exu

ORDER=(core core-client server-utils tcp ws ws/client http ipc stdio pubsub derive test)
VERSION=$(grep "^version" ./core/Cargo.toml | sed -e 's/.*"\(.*\)"/\1/')
ORDER=(core core-client/transports core-client server-utils tcp ws ws/client http ipc stdio pubsub derive test)

echo "Publishing version $VERSION"
cargo clean

for crate in ${ORDER[@]}; do
cd $crate
echo "Publishing $crate@$VERSION"
sleep 5
cargo publish $@
cd -
done

echo "Tagging version $VERSION"
git tag -a v$VERSION -m "Version $VERSION"
git push --tags
29 changes: 5 additions & 24 deletions core-client/Cargo.toml
Expand Up @@ -8,7 +8,7 @@ keywords = ["jsonrpc", "json-rpc", "json", "rpc", "serde"]
license = "MIT"
name = "jsonrpc-core-client"
repository = "https://github.com/paritytech/jsonrpc"
version = "11.0.0"
version = "12.0.0"

categories = [
"asynchronous",
Expand All @@ -19,31 +19,12 @@ categories = [
]

[features]
tls = ["hyper-tls"]
http = ["hyper"]
ws = [
"websocket",
"tokio",
]
tls = ["jsonrpc-client-transports/tls"]
http = ["jsonrpc-client-transports/http"]
ws = ["jsonrpc-client-transports/ws"]

[dependencies]
failure = "0.1"
futures = "0.1.26"
hyper = { version = "0.12", optional = true }
hyper-tls = { version = "0.3.2", optional = true }
jsonrpc-core = { version = "11.0", path = "../core" }
log = "0.4"
serde = "1.0"
serde_json = "1.0"
tokio = { version = "0.1", optional = true }
websocket = { version = "0.22", optional = true }

[dev-dependencies]
assert_matches = "1.1"
jsonrpc-http-server = { version = "11.0", path = "../http" }
lazy_static = "1.0"
env_logger = "0.6"
tokio = "0.1"
jsonrpc-client-transports = { version = "12.0", path = "./transports", default-features = false }

[badges]
travis-ci = { repository = "paritytech/jsonrpc", branch = "master"}
225 changes: 8 additions & 217 deletions core-client/src/lib.rs
@@ -1,217 +1,8 @@
//! JSON-RPC client implementation.
#![deny(missing_docs)]

use failure::{format_err, Fail};
use futures::sync::{mpsc, oneshot};
use futures::{future, prelude::*};
use jsonrpc_core::{Error, Params};
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::Value;

pub mod transports;

#[cfg(test)]
mod logger;

/// The errors returned by the client.
#[derive(Debug, Fail)]
pub enum RpcError {
/// An error returned by the server.
#[fail(display = "Server returned rpc error {}", _0)]
JsonRpcError(Error),
/// Failure to parse server response.
#[fail(display = "Failed to parse server response as {}: {}", _0, _1)]
ParseError(String, failure::Error),
/// Request timed out.
#[fail(display = "Request timed out")]
Timeout,
/// The server returned a response with an unknown id.
#[fail(display = "Server returned a response with an unknown id")]
UnknownId,
/// Not rpc specific errors.
#[fail(display = "{}", _0)]
Other(failure::Error),
}

impl From<Error> for RpcError {
fn from(error: Error) -> Self {
RpcError::JsonRpcError(error)
}
}

/// A message sent to the `RpcClient`. This is public so that
/// the derive crate can generate a client.
struct RpcMessage {
/// The rpc method name.
method: String,
/// The rpc method parameters.
params: Params,
/// The oneshot channel to send the result of the rpc
/// call to.
sender: oneshot::Sender<Result<Value, RpcError>>,
}

/// A channel to a `RpcClient`.
#[derive(Clone)]
pub struct RpcChannel(mpsc::Sender<RpcMessage>);

impl RpcChannel {
fn send(
&self,
msg: RpcMessage,
) -> impl Future<Item = mpsc::Sender<RpcMessage>, Error = mpsc::SendError<RpcMessage>> {
self.0.to_owned().send(msg)
}
}

impl From<mpsc::Sender<RpcMessage>> for RpcChannel {
fn from(sender: mpsc::Sender<RpcMessage>) -> Self {
RpcChannel(sender)
}
}

/// The future returned by the rpc call.
pub struct RpcFuture {
recv: oneshot::Receiver<Result<Value, RpcError>>,
}

impl RpcFuture {
/// Creates a new `RpcFuture`.
pub fn new(recv: oneshot::Receiver<Result<Value, RpcError>>) -> Self {
RpcFuture { recv }
}
}

impl Future for RpcFuture {
type Item = Value;
type Error = RpcError;

fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
// TODO should timeout (#410)
match self.recv.poll() {
Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)),
Ok(Async::Ready(Err(error))) => Err(error),
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(error) => Err(RpcError::Other(error.into())),
}
}
}

/// Client for raw JSON RPC requests
#[derive(Clone)]
pub struct RawClient(RpcChannel);

impl From<RpcChannel> for RawClient {
fn from(channel: RpcChannel) -> Self {
RawClient(channel)
}
}

impl RawClient {
/// Call RPC with raw JSON
pub fn call_method(&self, method: &str, params: Params) -> impl Future<Item = Value, Error = RpcError> {
let (sender, receiver) = oneshot::channel();
let msg = RpcMessage {
method: method.into(),
params,
sender,
};
self.0
.send(msg)
.map_err(|error| RpcError::Other(error.into()))
.and_then(|_| RpcFuture::new(receiver))
}
}

/// Client for typed JSON RPC requests
#[derive(Clone)]
pub struct TypedClient(RawClient);

impl From<RpcChannel> for TypedClient {
fn from(channel: RpcChannel) -> Self {
TypedClient(channel.into())
}
}

impl TypedClient {
/// Create new TypedClient
pub fn new(raw_cli: RawClient) -> Self {
TypedClient(raw_cli)
}

/// Call RPC with serialization of request and deserialization of response
pub fn call_method<T: Serialize, R: DeserializeOwned + 'static>(
&self,
method: &str,
returns: &'static str,
args: T,
) -> impl Future<Item = R, Error = RpcError> {
let args =
serde_json::to_value(args).expect("Only types with infallible serialisation can be used for JSON-RPC");
let params = match args {
Value::Array(vec) => Params::Array(vec),
Value::Null => Params::None,
_ => {
return future::Either::A(future::err(RpcError::Other(format_err!(
"RPC params should serialize to a JSON array, or null"
))))
}
};

future::Either::B(self.0.call_method(method, params).and_then(move |value: Value| {
log::debug!("response: {:?}", value);
let result =
serde_json::from_value::<R>(value).map_err(|error| RpcError::ParseError(returns.into(), error.into()));
future::done(result)
}))
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::transports::local;
use crate::{RpcChannel, RpcError, TypedClient};
use jsonrpc_core::{self, IoHandler};

#[derive(Clone)]
struct AddClient(TypedClient);

impl From<RpcChannel> for AddClient {
fn from(channel: RpcChannel) -> Self {
AddClient(channel.into())
}
}

impl AddClient {
fn add(&self, a: u64, b: u64) -> impl Future<Item = u64, Error = RpcError> {
self.0.call_method("add", "u64", (a, b))
}
}

#[test]
fn test_client_terminates() {
let mut handler = IoHandler::new();
handler.add_method("add", |params: Params| {
let (a, b) = params.parse::<(u64, u64)>()?;
let res = a + b;
Ok(jsonrpc_core::to_value(res).unwrap())
});

let (client, rpc_client) = local::connect::<AddClient, _, _>(handler);
let fut = client
.clone()
.add(3, 4)
.and_then(move |res| client.add(res, 5))
.join(rpc_client)
.map(|(res, ())| {
assert_eq!(res, 12);
})
.map_err(|err| {
eprintln!("{:?}", err);
assert!(false);
});
tokio::run(fut);
}
}
//! JSON-RPC client implementation primitives.
//!
//! By default this crate does not implement any transports,
//! use corresponding features (`tls`, `http` or `ws`) to opt-in for them.
//!
//! See documentation of [`jsonrpc-client-transports`](../jsonrpc_client_transports/) for more details.

pub use jsonrpc_client_transports::*;
50 changes: 50 additions & 0 deletions core-client/transports/Cargo.toml
@@ -0,0 +1,50 @@
[package]
authors = ["Parity Technologies <admin@parity.io>"]
description = "Transport agnostic JSON-RPC 2.0 client implementation."
documentation = "https://docs.rs/jsonrpc-client-transports/"
edition = "2018"
homepage = "https://github.com/paritytech/jsonrpc"
keywords = ["jsonrpc", "json-rpc", "json", "rpc", "serde"]
license = "MIT"
name = "jsonrpc-client-transports"
repository = "https://github.com/paritytech/jsonrpc"
version = "12.0.0"

categories = [
"asynchronous",
"network-programming",
"web-programming::http-client",
"web-programming::http-server",
"web-programming::websocket",
]

[features]
default = ["http", "tls", "ws"]
tls = ["hyper-tls", "http"]
http = ["hyper"]
ws = [
"websocket",
"tokio",
]

[dependencies]
failure = "0.1"
futures = "0.1.26"
hyper = { version = "0.12", optional = true }
hyper-tls = { version = "0.3.2", optional = true }
jsonrpc-core = { version = "12.0", path = "../../core" }
log = "0.4"
serde = "1.0"
serde_json = "1.0"
tokio = { version = "0.1", optional = true }
websocket = { version = "0.22", optional = true }

[dev-dependencies]
assert_matches = "1.1"
jsonrpc-http-server = { version = "12.0", path = "../../http" }
lazy_static = "1.0"
env_logger = "0.6"
tokio = "0.1"

[badges]
travis-ci = { repository = "paritytech/jsonrpc", branch = "master"}

0 comments on commit 12b6210

Please sign in to comment.