Simple example using json-rpc over a websocket

I am a beginner to rust, but have read most of "The Rust Programming Language"[1] and "Asynchronous Pogramming in Rust"[2]. I am trying to write code to interact with a json-rpc API over a websocket transport. The jsonrpc-core-client[3] crate seems to support this but I can't find any documentation on how to use it, and the code examples[4] I have found using it have a lot of other things going on. Any pointers would be greatly appreciated.

  1. https://doc.rust-lang.org/book/
  2. https://rust-lang.github.io/async-book/
  3. https://crates.io/crates/jsonrpc-core-client
  4. https://github.com/satellitex/test-substrate-rpc

I'm not aware of any complete examples. If you have more specific questions, I'd be glad to try and answer them.

OK, I am trying to convert the example client code they have in the readme (using a server directly connected to the client) to use the websocket transport.

use jsonrpc_core_client::transports::local;
use jsonrpc_core::futures::future::{self, Future, FutureResult};
use jsonrpc_core::{Error, IoHandler, Result};
use jsonrpc_derive::rpc;

/// Rpc trait
#[rpc]
pub trait Rpc {
	/// Returns a protocol version
	#[rpc(name = "protocolVersion")]
	fn protocol_version(&self) -> Result<String>;

	/// Adds two numbers and returns a result
	#[rpc(name = "add", alias("callAsyncMetaAlias"))]
	fn add(&self, a: u64, b: u64) -> Result<u64>;

	/// Performs asynchronous operation
	#[rpc(name = "callAsync")]
	fn call(&self, a: u64) -> FutureResult<String, Error>;
}

struct RpcImpl;

impl Rpc for RpcImpl {
	fn protocol_version(&self) -> Result<String> {
		Ok("version1".into())
	}

	fn add(&self, a: u64, b: u64) -> Result<u64> {
		Ok(a + b)
	}

	fn call(&self, _: u64) -> FutureResult<String, Error> {
		future::ok("OK".to_owned())
	}
}

fn main() {
	let mut io = IoHandler::new();
	io.extend_with(RpcImpl.to_delegate());

	let fut = {
		let (client, server) = local::connect::<gen_client::Client, _, _>(io);
		client.add(5, 6).map(|res| println!("5 + 6 = {}", res)).join(server)
	};
	fut.wait().unwrap();
}

I made the following changes and it compiles but

use jsonrpc_core::futures::future::Future;
use jsonrpc_core_client::transports::ws;
use jsonrpc_derive::rpc;
use serde_json::json;
use tokio::runtime::Runtime;
use url::Url;

/// Rpc trait
#[rpc(client)]
pub trait Rpc {
	/// Returns a protocol version
	#[rpc(name = "protocolVersion")]
	fn protocol_version(&self) -> Result<String>;

	/// Adds two numbers and returns a result
	#[rpc(name = "add", alias("callAsyncMetaAlias"))]
	fn add(&self, a: u64, b: u64) -> Result<u64>;

	/// Ping server expect return in interval ms
	#[rpc(name = "ping", raw_params)]
	fn ping(&self, params: Value) -> Result<String>;

	/// Performs asynchronous operation
	#[rpc(name = "callAsync")]
	fn call(&self, a: u64) -> FutureResult<String, Error>;
}

fn main() {
        let mut rt = Runtime::new().unwrap();

	let client_url = Url::parse("ws://127.0.0.1:8888/kurento").unwrap();
	let client = rt.block_on(ws::connect::<gen_client::Client>(&client_url)).unwrap();

	let mut interval = serde_json::map::Map::new();
	map.insert("interval".to_string(), 1000.into());

	client
           .clone()
           .ping(json!({"interval": 1000}).into())
           .map(|res| println!("ping = {}", res))
           .wait()
	   .unwrap();

	rt.shutdown_now().wait().unwrap();
}

I am having problems working out how to parse named json-rpc params, I am getting the bellow error.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: JsonRpcError(Error { code: InternalError, message: "Unexpected error while processing method: in Json::Value::find(key, end, found): requires objectValue or nullValue", data: None })', src/main.rs:65:5

I have connected to the server using websocat and have manually entered json-rpc and the server responded correctly.

Thanks for any help.