123 lines
4.2 KiB
Rust
123 lines
4.2 KiB
Rust
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any
|
|
// person obtaining a copy of this software and associated
|
|
// documentation files (the "Software"), to deal in the
|
|
// Software without restriction, including without
|
|
// limitation the rights to use, copy, modify, merge,
|
|
// publish, distribute, sublicense, and/or sell copies of
|
|
// the Software, and to permit persons to whom the Software
|
|
// is furnished to do so, subject to the following
|
|
// conditions:
|
|
//
|
|
// The above copyright notice and this permission notice
|
|
// shall be included in all copies or substantial portions
|
|
// of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
use jsonrpsee::core::client::ClientT;
|
|
use jsonrpsee::server::{ServerHandle, serve_with_graceful_shutdown, stop_channel};
|
|
use jsonrpsee::ws_client::WsClientBuilder;
|
|
use jsonrpsee::{RpcModule, rpc_params};
|
|
use std::net::SocketAddr;
|
|
use tokio::net::TcpListener;
|
|
use tracing_subscriber::util::SubscriberInitExt;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
let filter = tracing_subscriber::EnvFilter::try_from_default_env()?
|
|
.add_directive("jsonrpsee[method_call{name = \"say_hello\"}]=trace".parse()?)
|
|
.add_directive("jsonrpsee-client=trace".parse()?);
|
|
|
|
tracing_subscriber::FmtSubscriber::builder().with_env_filter(filter).finish().try_init()?;
|
|
|
|
let (_server_hdl, addrs) = run_server().await?;
|
|
let url_v4 = format!("ws://{}", addrs.v4);
|
|
let url_v6 = format!("ws://{}", addrs.v6);
|
|
|
|
let client_v4 = WsClientBuilder::default().build(&url_v4).await?;
|
|
let client_v6 = WsClientBuilder::default().build(&url_v6).await?;
|
|
|
|
let response_v4: String = client_v4.request("say_hello", rpc_params![]).await?;
|
|
let response_v6: String = client_v6.request("say_hello", rpc_params![]).await?;
|
|
|
|
tracing::info!("response V4: {:?}", response_v4);
|
|
tracing::info!("response V6: {:?}", response_v6);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn run_server() -> anyhow::Result<(ServerHandle, Addrs)> {
|
|
let port = 9944;
|
|
// V4 address
|
|
let v4_addr = SocketAddr::from(([127, 0, 0, 1], port));
|
|
// V6 address
|
|
let v6_addr = SocketAddr::new("::1".parse().unwrap(), port);
|
|
|
|
let mut module = RpcModule::new(());
|
|
module.register_method("say_hello", |_, _, _| "lo")?;
|
|
|
|
// Bind to both IPv4 and IPv6 addresses.
|
|
let listener_v4 = TcpListener::bind(&v4_addr).await?;
|
|
let listener_v6 = TcpListener::bind(&v6_addr).await?;
|
|
|
|
// Each RPC call/connection get its own `stop_handle`
|
|
// to able to determine whether the server has been stopped or not.
|
|
//
|
|
// To keep the server running the `server_handle`
|
|
// must be kept and it can also be used to stop the server.
|
|
let (stop_hdl, server_hdl) = stop_channel();
|
|
|
|
// Create and finalize a server configuration from a TowerServiceBuilder
|
|
// given an RpcModule and the stop handle.
|
|
let svc = jsonrpsee::server::Server::builder().to_service_builder().build(module, stop_hdl.clone());
|
|
|
|
tokio::spawn(async move {
|
|
loop {
|
|
// The `tokio::select!` macro is used to wait for either of the
|
|
// listeners to accept a new connection or for the server to be
|
|
// stopped.
|
|
let stream = tokio::select! {
|
|
res = listener_v4.accept() => {
|
|
match res {
|
|
Ok((stream, _remote_addr)) => stream,
|
|
Err(e) => {
|
|
tracing::error!("failed to accept v4 connection: {:?}", e);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
res = listener_v6.accept() => {
|
|
match res {
|
|
Ok((stream, _remote_addr)) => stream,
|
|
Err(e) => {
|
|
tracing::error!("failed to accept v6 connection: {:?}", e);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
_ = stop_hdl.clone().shutdown() => break,
|
|
};
|
|
|
|
// Spawn a new task to serve each respective (Hyper) connection.
|
|
tokio::spawn(serve_with_graceful_shutdown(stream, svc.clone(), stop_hdl.clone().shutdown()));
|
|
}
|
|
});
|
|
|
|
Ok((server_hdl, Addrs { v4: v4_addr, v6: v6_addr }))
|
|
}
|
|
|
|
struct Addrs {
|
|
v4: SocketAddr,
|
|
v6: SocketAddr,
|
|
}
|