Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name = "init4-bin-base"
description = "Internal utilities for binaries produced by the init4 team"
keywords = ["init4", "bin", "base"]

version = "0.9.0"
version = "0.9.1"
edition = "2021"
rust-version = "1.81"
authors = ["init4", "James Prestwich"]
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ pub mod utils {
/// OpenTelemetry utilities.
pub mod otlp;

#[cfg(feature = "alloy")]
/// Alloy Provider configuration and instantiation
pub mod provider;

#[cfg(feature = "alloy")]
/// Signer using a local private key or AWS KMS key.
pub mod signer;
Expand Down
139 changes: 139 additions & 0 deletions src/utils/provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use crate::utils::from_env::{FromEnvErr, FromEnvVar};
use alloy::{
providers::{IpcConnect, RootProvider, WsConnect},
pubsub::{ConnectionHandle, PubSubConnect},
rpc::client::BuiltInConnectionString,
transports::{
BoxTransport, TransportConnect, TransportError, TransportErrorKind, TransportResult,
},
};

impl FromEnvVar for BuiltInConnectionString {
type Error = TransportError;

fn from_env_var(env_var: &str) -> Result<Self, FromEnvErr<Self::Error>> {
let conn_str = String::from_env_var(env_var).map_err(FromEnvErr::infallible_into)?;
conn_str.parse().map_err(Into::into)
}
}

/// Configuration for an Alloy provider, sourced from an environment variable.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProviderConfig {
connection_string: BuiltInConnectionString,
}

impl ProviderConfig {
/// Creates a new `ProviderConfig` from a connection string.
pub const fn new(connection_string: BuiltInConnectionString) -> Self {
Self { connection_string }
}

/// Returns the connection string.
pub const fn connection_string(&self) -> &BuiltInConnectionString {
&self.connection_string
}

/// Connects to the provider using the connection string.
pub async fn connect(&self) -> TransportResult<RootProvider> {
RootProvider::connect_with(self.clone()).await
}
}

impl FromEnvVar for ProviderConfig {
type Error = TransportError;

fn from_env_var(env_var: &str) -> Result<Self, FromEnvErr<Self::Error>> {
let connection_string = BuiltInConnectionString::from_env_var(env_var)?;
Ok(Self { connection_string })
}
}

impl TransportConnect for ProviderConfig {
fn is_local(&self) -> bool {
self.connection_string.is_local()
}

fn get_transport(
&self,
) -> alloy::transports::impl_future!(<Output = Result<BoxTransport, TransportError>>) {
self.connection_string.get_transport()
}
}

/// Configuration for an Alloy provider, used to create a client, enforces
/// pubsub availability (WS or IPC connection).
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PubSubConfig {
connection_string: BuiltInConnectionString,
}

impl PubSubConfig {
/// Returns the connection string.
pub const fn connection_string(&self) -> &BuiltInConnectionString {
&self.connection_string
}

/// Connects to the provider using the connection string.
pub async fn connect(&self) -> TransportResult<RootProvider> {
RootProvider::connect_with(self.clone()).await
}
}

impl TryFrom<BuiltInConnectionString> for PubSubConfig {
type Error = TransportError;

fn try_from(connection_string: BuiltInConnectionString) -> Result<Self, Self::Error> {
if !matches!(
connection_string,
BuiltInConnectionString::Ws(_, _) | BuiltInConnectionString::Ipc(_)
) {
return Err(TransportErrorKind::pubsub_unavailable());
}
Ok(Self { connection_string })
}
}

impl FromEnvVar for PubSubConfig {
type Error = TransportError;

fn from_env_var(env_var: &str) -> Result<Self, FromEnvErr<Self::Error>> {
let cs = BuiltInConnectionString::from_env_var(env_var)?;
Self::try_from(cs).map_err(FromEnvErr::ParseError)
}
}

impl TransportConnect for PubSubConfig {
fn is_local(&self) -> bool {
self.connection_string.is_local()
}

fn get_transport(
&self,
) -> alloy::transports::impl_future!(<Output = Result<BoxTransport, TransportError>>) {
self.connection_string.get_transport()
}
}

impl PubSubConnect for PubSubConfig {
fn is_local(&self) -> bool {
self.connection_string.is_local()
}

fn connect(
&self,
) -> alloy::transports::impl_future!(<Output = TransportResult<ConnectionHandle>>) {
async move {
match &self.connection_string {
BuiltInConnectionString::Ws(ws, auth) => {
WsConnect::new(ws.as_str())
.with_auth_opt(auth.clone())
.connect()
.await
}
BuiltInConnectionString::Ipc(ipc) => IpcConnect::new(ipc.clone()).connect().await,
_ => unreachable!("can't instantiate http variant"),
}
}
}
}