use std::sync::Arc;
use chrono::{DateTime, Utc};
use clap::{Args, Parser};
use itertools::Itertools;
use nitro_da_client::{BloberClient, BloberClientResult};
use nitro_da_indexer_api::{BlobsByBlober, BlobsByPayer, CompoundProof, TimeRange};
use serde::Serialize;
use solana_sdk::pubkey::Pubkey;
use tracing::instrument;
use crate::formatting::CommandOutput;
#[derive(Debug, Parser)]
pub enum IndexerSubCommand {
#[command(visible_alias = "b")]
Blobs(SlotArgs),
#[command(visible_alias = "p")]
Proofs(SlotArgs),
#[command(visible_alias = "bl")]
BlobsForBlober {
#[arg(short, long)]
blober: Pubkey,
#[clap(flatten)]
time_args: TimeArgs,
},
#[command(visible_alias = "bp")]
BlobsForPayer {
#[arg(short = 'y', long)]
payer: Pubkey,
#[arg(short = 'm', long)]
network_name: String,
#[clap(flatten)]
time_args: TimeArgs,
},
#[command(visible_alias = "pb")]
ProofForBlob {
#[arg(short, long)]
blob: Pubkey,
},
}
#[derive(Debug, Clone, Args)]
pub struct TimeArgs {
#[arg(long, value_parser=DateTime::parse_from_rfc3339)]
pub start: Option<DateTime<Utc>>,
#[arg(long, value_parser=DateTime::parse_from_rfc3339)]
pub end: Option<DateTime<Utc>>,
}
#[derive(Debug, Args)]
pub struct SlotArgs {
pub slot: u64,
}
#[derive(Debug, Serialize)]
pub enum IndexerCommandOutput {
Blobs(Vec<Vec<u8>>),
Proofs(Box<Option<CompoundProof>>),
}
impl std::fmt::Display for IndexerCommandOutput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndexerCommandOutput::Blobs(blobs) => {
write!(
f,
"Blobs: [{}]",
blobs.iter().map(hex::encode).collect_vec().join(", ")
)
}
IndexerCommandOutput::Proofs(proof) => {
write!(f, "Proofs: {proof:?}")
}
}
}
}
impl IndexerSubCommand {
#[instrument(skip(client), level = "debug")]
pub async fn run(
&self,
client: Arc<BloberClient>,
namespace: &str,
) -> BloberClientResult<CommandOutput> {
match self {
IndexerSubCommand::Blobs(SlotArgs { slot }) => {
let data = client.get_blobs(*slot, namespace, None).await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
IndexerSubCommand::Proofs(SlotArgs { slot }) => {
let proof = client.get_slot_proof(*slot, namespace, None).await?;
Ok(IndexerCommandOutput::Proofs(Box::new(Some(proof))).into())
}
IndexerSubCommand::BlobsForBlober {
blober,
time_args: TimeArgs { start, end },
} => {
let data = client
.get_blobs_by_blober(BlobsByBlober {
blober: blober.to_owned(),
time_range: TimeRange {
start: start.to_owned(),
end: end.to_owned(),
},
})
.await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
IndexerSubCommand::BlobsForPayer {
payer,
network_name,
time_args: TimeArgs { start, end },
} => {
let data = client
.get_blobs_by_payer(BlobsByPayer {
payer: payer.to_owned(),
network_name: network_name.to_owned(),
time_range: TimeRange {
start: start.to_owned(),
end: end.to_owned(),
},
})
.await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
IndexerSubCommand::ProofForBlob { blob } => {
let proof = client.get_blob_proof(blob.to_owned()).await?;
Ok(IndexerCommandOutput::Proofs(Box::new(proof)).into())
}
}
}
}