-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This pull request introduces the HTTP Upstream client. The main goal is to be backward compatible and introduce an HTTP upstream client. If the config has any HTTP/s server to connect to, the HttpClient struct will handle them. Any WebSocket will use the existing upstream client code. If one or more HTTP clients are configured, they route all requests, and Websocket clients will be used for subscriptions. If no HTTP clients are configured, the fallback behavior is used, and all requests and subscriptions are routed through the WebSocket upstream client. If no WebSocket upstream clients are configured, then subscriptions are not enabled, only method requests.
- Loading branch information
1 parent
a97673b
commit dbbd473
Showing
2 changed files
with
140 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use crate::middlewares::CallResult; | ||
use jsonrpsee::{ | ||
core::{ | ||
client::{ClientT, Error}, | ||
JsonValue, | ||
}, | ||
http_client::HttpClient as RpcClient, | ||
types::{error::INTERNAL_ERROR_CODE, ErrorObject}, | ||
}; | ||
use std::sync::atomic::{AtomicUsize, Ordering}; | ||
|
||
/// Very simple struct to have a set of JsonRpsee HTTP clients and send requests to them | ||
pub struct HttpClient { | ||
clients: Vec<RpcClient>, | ||
last_sent: AtomicUsize, | ||
} | ||
|
||
impl HttpClient { | ||
pub fn new(endpoints: Vec<String>) -> Result<(Option<Self>, Vec<String>), Error> { | ||
let mut other_urls = vec![]; | ||
let clients = endpoints | ||
.into_iter() | ||
.filter_map(|url| { | ||
let t_url = url.to_lowercase(); | ||
if t_url.starts_with("http://") || t_url.starts_with("https://") { | ||
Some(RpcClient::builder().build(url)) | ||
} else { | ||
other_urls.push(url); | ||
None | ||
} | ||
}) | ||
.collect::<Result<Vec<_>, _>>()?; | ||
|
||
if clients.is_empty() { | ||
Ok((None, other_urls)) | ||
} else { | ||
Ok(( | ||
Some(Self { | ||
clients, | ||
last_sent: AtomicUsize::new(0), | ||
}), | ||
other_urls, | ||
)) | ||
} | ||
} | ||
|
||
/// Sends a request to one of the clients | ||
/// | ||
/// The client is selected in a round-robin fashion as fair as possible | ||
pub async fn request(&self, method: &str, params: Vec<JsonValue>) -> CallResult { | ||
let client_id = self.last_sent.fetch_add(1, Ordering::Relaxed) % self.clients.len(); | ||
|
||
self.clients[client_id] | ||
.request(method, params) | ||
.await | ||
.map_err(|e| match e { | ||
jsonrpsee::core::client::Error::Call(e) => e, | ||
e => ErrorObject::owned(INTERNAL_ERROR_CODE, e.to_string(), None::<String>), | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters