use std::{str::FromStr, sync::Arc};
use jsonrpsee::{http_client::HttpClientBuilder, ws_client::HeaderMap};
use nitro_sender::NitroSender;
use solana_cli_config::Config;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use tokio_util::sync::CancellationToken;
use crate::{
DataAnchorClient, DataAnchorClientError, DataAnchorClientResult,
client::{
DataAnchorClientBuilder,
data_anchor_client_builder::{self, IsSet, IsUnset, SetIndexerClient, SetProofClient},
},
constants::IndexerUrl,
};
impl<State> DataAnchorClientBuilder<State>
where
State: data_anchor_client_builder::State,
{
async fn indexer_from_url(
self,
indexer_url: &str,
indexer_api_token: Option<String>,
) -> DataAnchorClientResult<DataAnchorClientBuilder<SetProofClient<SetIndexerClient<State>>>>
where
State::IndexerClient: IsUnset,
State::ProofClient: IsUnset,
{
let mut headers = HeaderMap::new();
if let Some(token) = indexer_api_token {
headers.insert(
"x-api-key",
token.parse().map_err(|_| {
DataAnchorClientError::InvalidIndexerApiToken(
"Failed to parse API token".to_owned(),
)
})?,
);
}
headers.insert(
"user-agent",
format!("data-anchor-client/{}", env!("CARGO_PKG_VERSION"))
.parse()
.map_err(|_| {
DataAnchorClientError::InvalidIndexerApiToken(
"Failed to set user-agent".to_owned(),
)
})?,
);
let indexer_client = HttpClientBuilder::new()
.set_headers(headers.clone())
.build(indexer_url)?;
let proof_client = HttpClientBuilder::new()
.set_headers(headers)
.build(format!("{indexer_url}/proof"))?;
Ok(self
.indexer_client(Arc::new(indexer_client))
.proof_client(Arc::new(proof_client)))
}
pub async fn build_with_config(
self,
solana_config: Config,
cancellation_token: CancellationToken,
indexer_api_token: Option<String>,
) -> DataAnchorClientResult<DataAnchorClient>
where
State::Payer: IsSet,
State::Indexer: IsSet,
State::RpcClient: IsUnset,
State::NitroSender: IsUnset,
State::IndexerClient: IsUnset,
State::ProofClient: IsUnset,
{
let rpc_client = Arc::new(RpcClient::new_with_commitment(
solana_config.json_rpc_url.clone(),
CommitmentConfig::from_str(&solana_config.commitment)?,
));
let payer = self.get_payer().clone();
let indexer_url = if let Some(indexer) = self.get_indexer() {
indexer.url()
} else {
let genesis_hash = rpc_client.get_genesis_hash().await?;
IndexerUrl::from_genesis_hash(&genesis_hash.to_string())?.url()
};
Ok(self
.rpc_client(rpc_client.clone())
.nitro_sender(
NitroSender::new(rpc_client.clone(), cancellation_token, vec![payer.clone()])
.await?,
)
.indexer_from_url(&indexer_url, indexer_api_token)
.await?
.build())
}
}