2019-11-06 13:15:00 -08:00
|
|
|
use crate::{
|
2020-03-12 23:20:49 -07:00
|
|
|
client_error::Result,
|
2020-11-03 14:37:41 -08:00
|
|
|
rpc_custom_error,
|
|
|
|
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
|
|
|
|
rpc_response::RpcSimulateTransactionResult,
|
2020-05-20 18:40:45 -07:00
|
|
|
rpc_sender::RpcSender,
|
2019-11-06 13:15:00 -08:00
|
|
|
};
|
2019-03-16 21:51:41 -07:00
|
|
|
use log::*;
|
2020-05-22 08:53:53 -07:00
|
|
|
use reqwest::{self, header::CONTENT_TYPE, StatusCode};
|
2019-11-06 13:15:00 -08:00
|
|
|
use std::{thread::sleep, time::Duration};
|
2019-03-16 21:51:41 -07:00
|
|
|
|
2020-05-20 18:40:45 -07:00
|
|
|
pub struct HttpSender {
|
2020-01-08 12:31:43 -08:00
|
|
|
client: reqwest::blocking::Client,
|
2019-03-16 21:51:41 -07:00
|
|
|
url: String,
|
|
|
|
}
|
|
|
|
|
2020-05-20 18:40:45 -07:00
|
|
|
impl HttpSender {
|
2019-03-16 21:51:41 -07:00
|
|
|
pub fn new(url: String) -> Self {
|
2020-05-20 16:15:03 -07:00
|
|
|
Self::new_with_timeout(url, Duration::from_secs(30))
|
2019-03-16 21:51:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
|
2020-01-08 12:31:43 -08:00
|
|
|
let client = reqwest::blocking::Client::builder()
|
2019-09-24 13:10:59 -07:00
|
|
|
.timeout(timeout)
|
|
|
|
.build()
|
|
|
|
.expect("build rpc client");
|
|
|
|
|
|
|
|
Self { client, url }
|
2019-03-16 21:51:41 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-12 17:47:06 -07:00
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct RpcErrorObject {
|
|
|
|
code: i64,
|
|
|
|
message: String,
|
2020-11-03 14:37:41 -08:00
|
|
|
data: serde_json::Value,
|
2020-10-12 17:47:06 -07:00
|
|
|
}
|
|
|
|
|
2020-05-20 18:40:45 -07:00
|
|
|
impl RpcSender for HttpSender {
|
2020-05-22 08:53:53 -07:00
|
|
|
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
|
2019-03-16 21:51:41 -07:00
|
|
|
// Concurrent requests are not supported so reuse the same request id for all requests
|
|
|
|
let request_id = 1;
|
|
|
|
|
2019-12-18 21:26:11 -08:00
|
|
|
let request_json = request.build_request_json(request_id, params);
|
2019-03-16 21:51:41 -07:00
|
|
|
|
2020-05-22 08:53:53 -07:00
|
|
|
let mut too_many_requests_retries = 5;
|
2019-03-16 21:51:41 -07:00
|
|
|
loop {
|
2019-09-24 13:10:59 -07:00
|
|
|
match self
|
2019-03-16 21:51:41 -07:00
|
|
|
.client
|
|
|
|
.post(&self.url)
|
2019-09-24 13:10:59 -07:00
|
|
|
.header(CONTENT_TYPE, "application/json")
|
|
|
|
.body(request_json.to_string())
|
|
|
|
.send()
|
|
|
|
{
|
2020-01-08 12:31:43 -08:00
|
|
|
Ok(response) => {
|
2019-12-02 09:01:25 -08:00
|
|
|
if !response.status().is_success() {
|
2020-05-22 08:53:53 -07:00
|
|
|
if response.status() == StatusCode::TOO_MANY_REQUESTS
|
|
|
|
&& too_many_requests_retries > 0
|
|
|
|
{
|
|
|
|
too_many_requests_retries -= 1;
|
|
|
|
debug!(
|
|
|
|
"Server responded with {:?}, {} retries left",
|
|
|
|
response, too_many_requests_retries
|
|
|
|
);
|
|
|
|
|
|
|
|
// Sleep for 500ms to give the server a break
|
|
|
|
sleep(Duration::from_millis(500));
|
|
|
|
continue;
|
|
|
|
}
|
2019-12-02 09:01:25 -08:00
|
|
|
return Err(response.error_for_status().unwrap_err().into());
|
|
|
|
}
|
|
|
|
|
2019-09-24 13:10:59 -07:00
|
|
|
let json: serde_json::Value = serde_json::from_str(&response.text()?)?;
|
|
|
|
if json["error"].is_object() {
|
2020-10-12 17:47:06 -07:00
|
|
|
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone())
|
|
|
|
{
|
2020-11-03 14:37:41 -08:00
|
|
|
Ok(rpc_error_object) => {
|
|
|
|
let data = match rpc_error_object.code {
|
|
|
|
rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
|
|
|
|
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
|
|
|
|
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
|
|
|
|
Err(err) => {
|
|
|
|
debug!("Failed to deserialize RpcSimulateTransactionResult: {:?}", err);
|
|
|
|
RpcResponseErrorData::Empty
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2021-01-14 21:45:11 -08:00
|
|
|
rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY => {
|
|
|
|
match serde_json::from_value::<rpc_custom_error::RpcNodeUnhealthyErrorData>(json["error"]["data"].clone()) {
|
|
|
|
Ok(rpc_custom_error::RpcNodeUnhealthyErrorData { num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind},
|
|
|
|
Err(_err) => {
|
|
|
|
RpcResponseErrorData::Empty
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-11-03 14:37:41 -08:00
|
|
|
_ => RpcResponseErrorData::Empty
|
|
|
|
};
|
|
|
|
|
|
|
|
Err(RpcError::RpcResponseError {
|
|
|
|
code: rpc_error_object.code,
|
|
|
|
message: rpc_error_object.message,
|
|
|
|
data,
|
|
|
|
}
|
|
|
|
.into())
|
2020-10-12 17:47:06 -07:00
|
|
|
}
|
|
|
|
Err(err) => Err(RpcError::RpcRequestError(format!(
|
|
|
|
"Failed to deserialize RPC error response: {} [{}]",
|
|
|
|
serde_json::to_string(&json["error"]).unwrap(),
|
|
|
|
err
|
|
|
|
))
|
|
|
|
.into()),
|
|
|
|
};
|
2019-09-24 13:10:59 -07:00
|
|
|
}
|
|
|
|
return Ok(json["result"].clone());
|
2019-03-16 21:51:41 -07:00
|
|
|
}
|
2020-05-22 08:53:53 -07:00
|
|
|
Err(err) => {
|
|
|
|
return Err(err.into());
|
2019-09-24 13:10:59 -07:00
|
|
|
}
|
2019-03-16 21:51:41 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|