use crate::{BuiltInConnectionString, ConnectionConfig, RpcClient};
use alloy_transport::{BoxTransport, IntoBoxTransport, TransportConnect, TransportResult};
use std::str::FromStr;
use tower::{
layer::util::{Identity, Stack},
Layer, ServiceBuilder,
};
#[derive(Debug)]
pub struct ClientBuilder<L> {
pub(crate) builder: ServiceBuilder<L>,
}
impl Default for ClientBuilder<Identity> {
fn default() -> Self {
Self { builder: ServiceBuilder::new() }
}
}
impl<L> ClientBuilder<L> {
pub fn layer<M>(self, layer: M) -> ClientBuilder<Stack<M, L>> {
ClientBuilder { builder: self.builder.layer(layer) }
}
pub fn transport<T>(self, transport: T, is_local: bool) -> RpcClient
where
L: Layer<T>,
T: IntoBoxTransport,
L::Service: IntoBoxTransport,
{
RpcClient::new_layered(is_local, transport, move |t| self.builder.service(t))
}
#[cfg(feature = "reqwest")]
pub fn http(self, url: url::Url) -> RpcClient
where
L: Layer<alloy_transport_http::Http<reqwest::Client>>,
L::Service: IntoBoxTransport,
{
let transport = alloy_transport_http::Http::new(url);
let is_local = transport.guess_local();
self.transport(transport, is_local)
}
#[cfg(feature = "reqwest")]
pub fn http_with_client(self, client: reqwest::Client, url: url::Url) -> RpcClient
where
L: Layer<alloy_transport_http::Http<reqwest::Client>>,
L::Service: IntoBoxTransport,
{
let transport = alloy_transport_http::Http::with_client(client, url);
let is_local = transport.guess_local();
self.transport(transport, is_local)
}
#[cfg(all(not(target_family = "wasm"), feature = "hyper"))]
pub fn hyper_http(self, url: url::Url) -> RpcClient
where
L: Layer<alloy_transport_http::HyperTransport>,
L::Service: IntoBoxTransport,
{
let transport = alloy_transport_http::HyperTransport::new_hyper(url);
let is_local = transport.guess_local();
self.transport(transport, is_local)
}
#[cfg(feature = "pubsub")]
pub async fn pubsub<C>(self, pubsub_connect: C) -> TransportResult<RpcClient>
where
C: alloy_pubsub::PubSubConnect,
L: Layer<alloy_pubsub::PubSubFrontend>,
L::Service: IntoBoxTransport,
{
let is_local = pubsub_connect.is_local();
let transport = pubsub_connect.into_service().await?;
Ok(self.transport(transport, is_local))
}
#[cfg(feature = "ws")]
pub async fn ws(self, ws_connect: alloy_transport_ws::WsConnect) -> TransportResult<RpcClient>
where
L: Layer<alloy_pubsub::PubSubFrontend>,
L::Service: IntoBoxTransport,
{
self.pubsub(ws_connect).await
}
#[cfg(feature = "ipc")]
pub async fn ipc<T>(
self,
ipc_connect: alloy_transport_ipc::IpcConnect<T>,
) -> TransportResult<RpcClient>
where
alloy_transport_ipc::IpcConnect<T>: alloy_pubsub::PubSubConnect,
L: Layer<alloy_pubsub::PubSubFrontend>,
L::Service: IntoBoxTransport,
{
self.pubsub(ipc_connect).await
}
pub async fn connect(self, s: &str) -> TransportResult<RpcClient>
where
L: Layer<BoxTransport>,
L::Service: IntoBoxTransport,
{
self.connect_with(s.parse::<BuiltInConnectionString>()?).await
}
pub async fn connect_with_config(
self,
s: &str,
config: ConnectionConfig,
) -> TransportResult<RpcClient>
where
L: Layer<BoxTransport>,
L::Service: IntoBoxTransport,
{
let connect = BuiltInConnectionString::from_str(s)?;
let is_local = connect.is_local();
let transport = connect.connect_boxed_with(config).await?;
let transport = self.builder.service(transport);
Ok(RpcClient::new(transport.into_box_transport(), is_local))
}
pub async fn connect_with<C>(self, connect: C) -> TransportResult<RpcClient>
where
C: TransportConnect,
L: Layer<BoxTransport>,
L::Service: IntoBoxTransport,
{
let transport = connect.get_transport().await?;
Ok(self.transport(transport, connect.is_local()))
}
}