use super::request::{parse_response, RequestBuilder};
use crate::prelude::reqwest::Client as HttpClient;
use jsonrpc_core::{Error, Params, Value};
use std::sync::Arc;
#[derive(Clone)]
pub struct SimpleClient {
client: Arc<HttpClient>,
url: String,
}
impl SimpleClient {
pub fn new(client: Arc<HttpClient>, url: &str) -> Self {
Self {
client,
url: url.to_owned(),
}
}
pub fn new_with_url(url: &str) -> Self {
Self {
client: Arc::new(HttpClient::default()),
url: url.to_string(),
}
}
pub async fn call_method(&self, method: &str, params: Params) -> RpcResult<Value> {
let msg = CallMessage {
method: method.into(),
params,
};
self.do_request(&RpcMessage::Call(msg)).await
}
pub async fn notify(&self, method: &str, params: Params) -> RpcResult<()> {
let msg = NotifyMessage {
method: method.into(),
params,
};
self.do_request(&RpcMessage::Notify(msg)).await?;
Ok(())
}
async fn do_request(&self, msg: &RpcMessage) -> RpcResult<Value> {
let mut request_builder = RequestBuilder::new();
let request = match msg {
RpcMessage::Call(call) => request_builder.call_request(call).1,
RpcMessage::Notify(notify) => request_builder.notification(notify),
RpcMessage::Subscribe(_) => {
return Err(RpcError::Client(
"Unsupported `RpcMessage` type `Subscribe`.".to_owned(),
));
}
};
let resp = self
.client
.post(self.url.as_str())
.header(
http::header::CONTENT_TYPE,
http::header::HeaderValue::from_static("application/json"),
)
.header(
http::header::ACCEPT,
http::header::HeaderValue::from_static("application/json"),
)
.body(request)
.send()
.await
.map_err(|e| RpcError::Client(e.to_string()))?;
let resp = resp
.error_for_status()
.map_err(|e| RpcError::Client(e.to_string()))?;
let resp = resp
.bytes()
.await
.map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))?;
let resp_str = String::from_utf8_lossy(&resp).into_owned();
parse_response(&resp_str)
.map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))?
.1
}
}
#[derive(Debug, thiserror::Error)]
pub enum RpcError {
#[error("Server returned rpc error {0}")]
JsonRpcError(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>),
}
impl From<Error> for RpcError {
fn from(error: Error) -> Self {
RpcError::JsonRpcError(error)
}
}
pub type RpcResult<T> = Result<T, RpcError>;
pub struct CallMessage {
pub method: String,
pub params: Params,
}
pub struct NotifyMessage {
pub method: String,
pub params: Params,
}
pub struct Subscription {
pub subscribe: String,
pub subscribe_params: Params,
pub notification: String,
pub unsubscribe: String,
}
pub struct SubscribeMessage {
pub subscription: Subscription,
}
pub enum RpcMessage {
Call(CallMessage),
Notify(NotifyMessage),
Subscribe(SubscribeMessage),
}
impl From<CallMessage> for RpcMessage {
fn from(msg: CallMessage) -> Self {
RpcMessage::Call(msg)
}
}
impl From<NotifyMessage> for RpcMessage {
fn from(msg: NotifyMessage) -> Self {
RpcMessage::Notify(msg)
}
}
impl From<SubscribeMessage> for RpcMessage {
fn from(msg: SubscribeMessage) -> Self {
RpcMessage::Subscribe(msg)
}
}