use std::{path::PathBuf, str::FromStr, time::Duration};
use clap::{Parser, ValueEnum};
use solana_address::Address;
use solana_client::rpc_config::CommitmentConfig;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct Args {
#[arg(short, long, value_parser = parse_address)]
pub program: Address,
#[arg(short, long, value_parser = resolve_url)]
pub url: String,
#[arg(short, long, default_value = "soldump")]
pub dir: PathBuf,
#[arg(short, long)]
pub skip_size: Vec<usize>,
#[arg(short, long)]
pub only_size: Option<u64>,
#[arg(short, long, value_enum, default_value_t = Commitment::Confirmed)]
pub commitment: Commitment,
#[arg(short, long = "timeout", default_value_t = 30, value_name = "SECONDS")]
pub timeout_secs: u64,
}
impl Args {
pub fn timeout(&self) -> Duration {
Duration::from_secs(self.timeout_secs)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
pub enum Commitment {
Processed,
Confirmed,
Finalized,
}
impl Commitment {
pub fn as_str(self) -> &'static str {
match self {
Commitment::Processed => "processed",
Commitment::Confirmed => "confirmed",
Commitment::Finalized => "finalized",
}
}
pub fn config(self) -> CommitmentConfig {
match self {
Commitment::Processed => CommitmentConfig::processed(),
Commitment::Confirmed => CommitmentConfig::confirmed(),
Commitment::Finalized => CommitmentConfig::finalized(),
}
}
}
fn parse_address(s: &str) -> Result<Address, String> {
Address::from_str(s).map_err(|e| format!("invalid program address `{s}`: {e}"))
}
fn resolve_url(s: &str) -> Result<String, String> {
let url = match s {
"m" | "mainnet-beta" => "https://api.mainnet-beta.solana.com",
"d" | "devnet" => "https://api.devnet.solana.com",
"t" | "testnet" => "https://api.testnet.solana.com",
"l" | "localhost" => "http://localhost:8899",
other if other.starts_with("http://") || other.starts_with("https://") => other,
other => {
return Err(format!(
"`{other}` is neither a moniker (mainnet-beta, devnet, testnet, localhost) \
nor an http(s) URL"
))
}
};
Ok(url.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolve_url_rejects_anything_that_is_not_a_moniker_or_url() {
assert!(resolve_url("api.devnet.solana.com").is_err());
assert!(resolve_url("mainnet").is_err());
assert!(resolve_url("d").is_ok());
assert!(resolve_url("https://x.example/rpc").is_ok());
}
#[test]
fn verify_cli() {
use clap::CommandFactory;
Args::command().debug_assert();
}
}