#![doc = include_str!("../README.md")]
use anyhow::Error;
use bitski_chain_models::networks::Network;
use bitski_provider::access_token_providers::{
AccessTokenProvider, ClientCredentialsAccessTokenProvider,
};
use bitski_provider::ethers_provider::BitskiEthersProvider;
use bitski_provider::web3_provider::BitskiWeb3Provider;
use std::sync::Arc;
use web3::Web3;
#[derive(Clone)]
pub struct Bitski {
pub client_id: String,
pub auth_token_provider: Arc<dyn AccessTokenProvider + Sync + Send>,
pub rpc_override: Option<String>,
}
impl Bitski {
pub fn new(
client_id: &dyn ToString,
credential_id: &dyn ToString,
client_secret: &dyn ToString,
scopes: Option<Vec<String>>,
) -> Self {
let auth_token_provider = Arc::new(ClientCredentialsAccessTokenProvider::new(
credential_id.to_string(),
client_secret.to_string(),
scopes,
));
Bitski {
client_id: client_id.to_string(),
auth_token_provider,
rpc_override: None,
}
}
pub fn set_rpc_override(&mut self, rpc_url: String) {
self.rpc_override = Some(rpc_url);
}
pub fn new_with_access_token(client_id: &dyn ToString, access_token: &dyn ToString) -> Self {
let auth_token_provider = Arc::new(access_token.to_string());
Bitski {
client_id: client_id.to_string(),
auth_token_provider,
rpc_override: None,
}
}
pub fn new_unauthenticated(client_id: &dyn ToString) -> Self {
let auth_token_provider = Arc::new(());
Bitski {
client_id: client_id.to_string(),
auth_token_provider,
rpc_override: None,
}
}
pub fn from_env() -> Result<Self, Error> {
let client_id = std::env::var("BITSKI_API_KEY")
.or_else(|_| std::env::var("BITSKI_CLIENT_ID"))
.or_else(|_| std::env::var("API_KEY"))
.or_else(|_| std::env::var("CLIENT_ID"))
.map_err(|err| {
eprintln!("BITSKI_API_KEY or BITSKI_CLIENT_ID is required.");
err
})?;
let credential_id =
std::env::var("BITSKI_CREDENTIAL_ID").or_else(|_| std::env::var("CREDENTIAL_ID"));
let credential_secret = std::env::var("BITSKI_CREDENTIAL_SECRET")
.or_else(|_| std::env::var("CREDENTIAL_SECRET"));
let scopes: Vec<String> = std::env::var("BITSKI_SCOPES")
.or_else(|_| std::env::var("SCOPES"))
.unwrap_or_default()
.split_terminator(',')
.map(|s| s.to_string())
.collect();
let scopes = match scopes.is_empty() {
true => None,
false => Some(scopes),
};
match (credential_id, credential_secret) {
(Ok(credential_id), Ok(credential_secret)) => Ok(Bitski::new(
&client_id,
&credential_id,
&credential_secret,
scopes,
)),
_ => Ok(Bitski::new_unauthenticated(&client_id)),
}
}
pub fn get_web3_provider<N: TryInto<Network>>(
&self,
network: N,
) -> Result<BitskiWeb3Provider, Error> {
let mut network: Network = network
.try_into()
.map_err(|_error| Error::msg("Invalid network"))?;
let network = if let Some(url) = &self.rpc_override {
network.rpc_url = url.to_owned();
network
} else {
network
};
let provider =
BitskiWeb3Provider::new(&network, &self.client_id, self.auth_token_provider.clone());
Ok(provider)
}
#[cfg(feature = "ethers")]
pub fn get_ethers_provider<N: TryInto<Network>>(
&self,
network: N,
) -> Result<BitskiEthersProvider, Error> {
let mut network: Network = network
.try_into()
.map_err(|_error| Error::msg("Invalid network"))?;
let network = if let Some(url) = &self.rpc_override {
network.rpc_url = url.to_owned();
network
} else {
network
};
let provider =
BitskiEthersProvider::new(&network, &self.client_id, self.auth_token_provider.clone());
Ok(provider)
}
pub async fn get_access_token(&self) -> Result<String, Error> {
self.auth_token_provider.get_access_token().await
}
pub fn get_web3<N: TryInto<Network>>(
&self,
network: N,
) -> Result<Web3<BitskiWeb3Provider>, Error> {
let provider = self.get_web3_provider(network)?;
Ok(Web3::new(provider))
}
}