use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::method::Method;
use crate::prelude::reqwest::Client as HttpClient;
use crate::protos::rings_node::*;
pub struct Client {
client: HttpClient,
endpoint_url: String,
}
#[derive(Debug, thiserror::Error)]
pub enum RpcError {
#[error("Server returned rpc error {0}")]
JsonClientError(jsonrpc_core::Error),
#[error("Failed to parse server response as {0}: {1}")]
ParseError(String, Box<dyn std::error::Error + Send>),
#[error("Request timed out")]
Timeout,
#[error("Client error: {0}")]
Client(String),
#[error("{0}")]
Other(Box<dyn std::error::Error + Send>),
}
type Result<T> = std::result::Result<T, RpcError>;
impl Client {
pub fn new(endpoint_url: &str) -> Self {
Self {
client: HttpClient::default(),
endpoint_url: endpoint_url.to_string(),
}
}
pub async fn call_method<T>(&self, method: Method, req: &impl Serialize) -> Result<T>
where T: DeserializeOwned {
use jsonrpc_core::*;
let params = serde_json::to_value(req)
.map_err(|e| RpcError::Client(e.to_string()))?
.as_object()
.ok_or(RpcError::Client("params should be an object".to_string()))?
.clone();
let jsonrpc_request = Request::Single(Call::MethodCall(MethodCall {
jsonrpc: Some(Version::V2),
method: method.to_string(),
params: Params::Map(params),
id: Id::Num(1),
}));
let result = self.do_jsonrpc_request(&jsonrpc_request).await?;
serde_json::from_value(result).map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))
}
async fn do_jsonrpc_request(&self, req: &jsonrpc_core::Request) -> Result<serde_json::Value> {
let body = serde_json::to_string(req).map_err(|e| RpcError::Client(e.to_string()))?;
let req = self
.client
.post(self.endpoint_url.as_str())
.header("content-type", "application/json")
.header("accept", "application/json")
.body(body);
let resp = req
.send()
.await
.map_err(|e| RpcError::Client(e.to_string()))?
.error_for_status()
.map_err(|e| RpcError::Client(e.to_string()))?
.bytes()
.await
.map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))?;
let jsonrpc_resp = jsonrpc_core::Response::from_json(&String::from_utf8_lossy(&resp))
.map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))?;
match jsonrpc_resp {
jsonrpc_core::Response::Single(resp) => match resp {
jsonrpc_core::Output::Success(success) => Ok(success.result),
jsonrpc_core::Output::Failure(failure) => {
Err(RpcError::JsonClientError(failure.error))
}
},
jsonrpc_core::Response::Batch(_) => Err(RpcError::Client(
"Batch response is not supported".to_string(),
)),
}
}
pub async fn connect_peer_via_http(
&self,
req: &ConnectPeerViaHttpRequest,
) -> Result<ConnectPeerViaHttpResponse> {
self.call_method(Method::ConnectPeerViaHttp, req).await
}
pub async fn connect_with_did(
&self,
req: &ConnectWithDidRequest,
) -> Result<ConnectWithSeedResponse> {
self.call_method(Method::ConnectWithDid, req).await
}
pub async fn connect_with_seed(
&self,
req: &ConnectWithSeedRequest,
) -> Result<ConnectWithSeedResponse> {
self.call_method(Method::ConnectWithSeed, req).await
}
pub async fn list_peers(&self, req: &ListPeersRequest) -> Result<ListPeersResponse> {
self.call_method(Method::ListPeers, req).await
}
pub async fn create_offer(&self, req: &CreateOfferRequest) -> Result<CreateOfferResponse> {
self.call_method(Method::CreateOffer, req).await
}
pub async fn answer_offer(&self, req: &AnswerOfferRequest) -> Result<AnswerOfferResponse> {
self.call_method(Method::AnswerOffer, req).await
}
pub async fn accept_answer(&self, req: &AcceptAnswerRequest) -> Result<AcceptAnswerResponse> {
self.call_method(Method::AcceptAnswer, req).await
}
pub async fn disconnect(&self, req: &DisconnectRequest) -> Result<DisconnectResponse> {
self.call_method(Method::Disconnect, req).await
}
pub async fn send_backend_message(
&self,
req: &SendBackendMessageRequest,
) -> Result<SendBackendMessageResponse> {
self.call_method(Method::SendBackendMessage, req).await
}
pub async fn send_e2e_handshake(
&self,
req: &SendE2eHandshakeRequest,
) -> Result<SendE2eHandshakeResponse> {
self.call_method(Method::SendE2eHandshake, req).await
}
pub async fn send_e2e_message(
&self,
req: &SendE2eMessageRequest,
) -> Result<SendE2eMessageResponse> {
self.call_method(Method::SendE2eMessage, req).await
}
pub async fn publish_message_to_topic(
&self,
req: &PublishMessageToTopicRequest,
) -> Result<PublishMessageToTopicResponse> {
self.call_method(Method::PublishMessageToTopic, req).await
}
pub async fn fetch_topic_messages(
&self,
req: &FetchTopicMessagesRequest,
) -> Result<FetchTopicMessagesResponse> {
self.call_method(Method::FetchTopicMessages, req).await
}
pub async fn register_service(
&self,
req: &RegisterServiceRequest,
) -> Result<RegisterServiceResponse> {
self.call_method(Method::RegisterService, req).await
}
pub async fn lookup_service(
&self,
req: &LookupServiceRequest,
) -> Result<LookupServiceResponse> {
self.call_method(Method::LookupService, req).await
}
pub async fn node_info(&self, req: &NodeInfoRequest) -> Result<NodeInfoResponse> {
self.call_method(Method::NodeInfo, req).await
}
pub async fn node_did(&self, req: &NodeDidRequest) -> Result<NodeDidResponse> {
self.call_method(Method::NodeDid, req).await
}
}