use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use clap::Parser;
#[cfg(feature = "v2")]
use i0::v2;
#[cfg(feature = "v3")]
use i0::v3;
use i0::{Timestamp, display};
use rand::TryRng;
use rand::rngs::SysRng;
#[derive(Parser, Debug)]
#[command(about = "generates a new thei.rs/i0", long_about = None)]
struct Cli {
#[arg(short, long)]
designation: Option<String>,
#[arg(short, long)]
timestamp: Option<String>,
#[arg(short, long)]
seed: Option<String>,
#[arg(short, long, default_value_t = 3)]
version: u8,
}
fn main() {
let cli = Cli::parse();
let designation = cli.designation.unwrap_or_default();
let timestamp = cli
.timestamp
.map(|s| {
Timestamp::try_from_hex(s.as_ref())
.expect("timestamp in an invalid format; should be hex")
})
.unwrap_or_else(Timestamp::new);
let mut seed: [u8; 32] = [0u8; 32];
match cli.seed {
Some(s) => {
seed = URL_SAFE_NO_PAD
.decode(s)
.expect("seed is not valid base64 (make sure to use url-safe b64 without padding)")
.as_slice()
.try_into()
.expect("seed must be 32 bytes")
}
None => SysRng
.try_fill_bytes(&mut seed)
.expect("failed to get randomness"),
}
let version = cli.version;
let (short, long) = match version {
#[cfg(feature = "v2")]
2 => {
let metadata = v2::Metadata {
designation: &designation,
timestamp: ×tamp,
seed: &seed,
};
display::print_metadata(version, &metadata);
v2::generate(&metadata)
}
#[cfg(feature = "v3")]
3 => {
let metadata = v3::Metadata {
designation: &designation,
timestamp: ×tamp,
seed: &seed,
};
display::print_metadata(version, &metadata);
v3::generate(&metadata)
}
_ => panic!("version {version} hasn't been implemented"),
};
display::print(version, &long, &short);
}