128 lines
3.1 KiB
Rust
128 lines
3.1 KiB
Rust
mod entities;
|
|
mod utils;
|
|
|
|
use entities::BatchRequestBuilder;
|
|
use entities::RawRequest;
|
|
use entities::RawResponse;
|
|
pub use entities::RpcError;
|
|
|
|
use utils::generate_id;
|
|
|
|
pub struct Client {
|
|
client: reqwest::Client,
|
|
host_url: String,
|
|
}
|
|
|
|
///Creates a new client
|
|
pub fn new(host: &str) -> Client {
|
|
let client = reqwest::Client::new();
|
|
Client {
|
|
client,
|
|
host_url: host.to_string(),
|
|
}
|
|
}
|
|
|
|
/// Creates a new BatchRequestBuilder object which can be used to build a batch request which
|
|
/// may contain both requests and notifications(i.e. requests without an id)
|
|
pub fn batch_request() -> BatchRequestBuilder {
|
|
BatchRequestBuilder::new()
|
|
}
|
|
|
|
impl Client {
|
|
///Send a request
|
|
pub async fn send_request<T: serde::de::DeserializeOwned + std::fmt::Debug>(
|
|
&self,
|
|
method: &str,
|
|
params: serde_json::Value,
|
|
) -> Result<T, RpcError> {
|
|
let request = RawRequest::new(Some(generate_id()), method.to_string(), Some(params));
|
|
|
|
println!(
|
|
"Request: {}",
|
|
serde_json::to_string_pretty(&request).unwrap()
|
|
);
|
|
|
|
//TODO: maybe check the response better as well??
|
|
let resp: serde_json::Value = self
|
|
.client
|
|
.post(&self.host_url)
|
|
.json(&request)
|
|
.send()
|
|
.await?
|
|
.json()
|
|
.await?;
|
|
|
|
println!(
|
|
"Response to `{}`: {}",
|
|
method,
|
|
serde_json::to_string_pretty(&resp).unwrap()
|
|
);
|
|
let resp: RawResponse<T> = serde_json::value::from_value(resp).unwrap();
|
|
resp.result()
|
|
}
|
|
|
|
/// Send a notification
|
|
pub async fn send_notification(
|
|
&self,
|
|
method: &str,
|
|
params: serde_json::Value,
|
|
) -> Result<(), RpcError> {
|
|
let request = RawRequest::new(None, method.to_string(), Some(params));
|
|
|
|
// dbg!(
|
|
// "Request: {}",
|
|
// serde_json::to_string_pretty(&request).unwrap()
|
|
// );
|
|
|
|
self.client
|
|
.post(&self.host_url)
|
|
.json(&request)
|
|
.send()
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<T> RawResponse<T> {
|
|
fn result(self) -> Result<T, RpcError> {
|
|
if let Some(res) = self.result {
|
|
return Ok(res);
|
|
}
|
|
if let Some(err) = self.error {
|
|
return Err(err);
|
|
}
|
|
Err(RpcError {
|
|
code: -1,
|
|
message: Some(format!(
|
|
"Neither result nor error was found. ID = {:?}",
|
|
self.id
|
|
)),
|
|
data: None,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl RpcError {
|
|
/// Get error code for the RPC Error
|
|
pub fn code(&self) -> i32 {
|
|
self.code
|
|
}
|
|
|
|
//Returns the message in the error if it exists or returns `"none"`
|
|
pub fn message(&self) -> &str {
|
|
self.message.as_ref().map_or("none", AsRef::as_ref)
|
|
}
|
|
}
|
|
|
|
impl std::convert::From<reqwest::Error> for RpcError {
|
|
/// Convert a Reqwest error to an RPC Error with code -1
|
|
fn from(error: reqwest::Error) -> Self {
|
|
RpcError {
|
|
code: -1,
|
|
message: Some(format!("Reqwest error: {:?}", error)),
|
|
data: None,
|
|
}
|
|
}
|
|
}
|