File size: 4,061 Bytes
103262d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | // cli.rs — CLI commands for sovereign addressing
//
// Commands: encode, bytes, receipt, verify
use clap::{Parser, Subcommand};
use std::fs;
use std::io::{self, Read};
use crate::{sovereign_address, sovereign_address_bytes, worm_receipt, verify_address, verify_receipt};
#[derive(Parser)]
#[command(name = "snapaddr", about = "SnapKitty Sovereign Addressing")]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
/// Compute sovereign address of a JSON value
Encode {
/// JSON file path (reads stdin if not provided)
#[arg(value_name = "FILE")]
file: Option<String>,
},
/// Compute raw address bytes
Bytes {
/// JSON file path
#[arg(value_name = "FILE")]
file: Option<String>,
},
/// Generate WORM receipt
Receipt {
/// JSON file path
#[arg(value_name = "FILE")]
file: Option<String>,
},
/// Verify address or receipt
Verify {
/// JSON file path
#[arg(value_name = "FILE")]
file: String,
/// Expected address (for address verification)
#[arg(long)]
address: Option<String>,
},
/// Validate JSON admissibility
Validate {
/// JSON file path
#[arg(value_name = "FILE")]
file: Option<String>,
},
}
/// Read JSON from file or stdin.
fn read_json(file: Option<&str>) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let input = match file {
Some(path) => fs::read_to_string(path)?,
None => {
let mut buf = String::new();
io::stdin().read_to_string(&mut buf)?;
buf
}
};
Ok(serde_json::from_str(&input)?)
}
/// Run the CLI.
pub fn run() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
match cli.command {
Commands::Encode { file } => {
let value = read_json(file.as_deref())?;
let addr = sovereign_address(&value)?;
println!("{}", addr);
}
Commands::Bytes { file } => {
let value = read_json(file.as_deref())?;
let bytes = sovereign_address_bytes(&value)?;
for b in &bytes {
print!("{:02x}", b);
}
println!();
}
Commands::Receipt { file } => {
let value = read_json(file.as_deref())?;
let receipt = worm_receipt(&value)?;
println!("{}", serde_json::to_string_pretty(&receipt)?);
}
Commands::Verify { file, address } => {
let value = read_json(Some(&file))?;
if let Some(addr) = address {
let ok = verify_address(&value, &addr)?;
if ok {
println!("✓ Address verified");
} else {
println!("✗ Address mismatch");
std::process::exit(1);
}
} else {
// Verify receipt
let receipt = worm_receipt(&value)?;
let ok = verify_receipt(&receipt)?;
if ok {
println!("✓ Receipt verified");
println!("{}", serde_json::to_string_pretty(&receipt)?);
} else {
println!("✗ Receipt verification failed");
std::process::exit(1);
}
}
}
Commands::Validate { file } => {
let value = read_json(file.as_deref())?;
let result = crate::admissibility::validate_admissible(&value);
match result {
Ok(()) => println!("✓ JSON is admissible"),
Err(e) => {
println!("✗ Not admissible: {}", e);
std::process::exit(1);
}
}
}
}
Ok(())
}
|