use std::io::{Read, Write}; use std::net::TcpStream; // Minimal RESP helpers fn arr(parts: &[&str]) -> String { let mut out = format!("*{}\r\n", parts.len()); for p in parts { out.push_str(&format!("${}\r\n{}\r\n", p.len(), p)); } out } fn read_reply(s: &mut TcpStream) -> String { let mut buf = [0u8; 65536]; let n = s.read(&mut buf).unwrap(); String::from_utf8_lossy(&buf[..n]).to_string() } fn parse_two_bulk(reply: &str) -> Option<(String,String)> { let mut lines = reply.split("\r\n"); if lines.next()? != "*2" { return None; } let _n = lines.next()?; let a = lines.next()?.to_string(); let _m = lines.next()?; let b = lines.next()?.to_string(); Some((a,b)) } fn parse_bulk(reply: &str) -> Option { let mut lines = reply.split("\r\n"); let hdr = lines.next()?; if !hdr.starts_with('$') { return None; } Some(lines.next()?.to_string()) } fn parse_simple(reply: &str) -> Option { let mut lines = reply.split("\r\n"); let hdr = lines.next()?; if !hdr.starts_with('+') { return None; } Some(hdr[1..].to_string()) } fn main() { let mut args = std::env::args().skip(1); let host = args.next().unwrap_or_else(|| "127.0.0.1".into()); let port = args.next().unwrap_or_else(|| "6379".into()); let addr = format!("{host}:{port}"); println!("Connecting to {addr}..."); let mut s = TcpStream::connect(addr).expect("connect"); // Generate & persist X25519 enc keys under name "alice" s.write_all(arr(&["age","keygen","alice"]).as_bytes()).unwrap(); let (_alice_recip, _alice_ident) = parse_two_bulk(&read_reply(&mut s)).expect("gen enc"); // Generate & persist Ed25519 signing key under name "signer" s.write_all(arr(&["age","signkeygen","signer"]).as_bytes()).unwrap(); let (_verify, _secret) = parse_two_bulk(&read_reply(&mut s)).expect("gen sign"); // Encrypt by name let msg = "hello from persistent keys"; s.write_all(arr(&["age","encryptname","alice", msg]).as_bytes()).unwrap(); let ct_b64 = parse_bulk(&read_reply(&mut s)).expect("ct b64"); println!("ciphertext b64: {}", ct_b64); // Decrypt by name s.write_all(arr(&["age","decryptname","alice", &ct_b64]).as_bytes()).unwrap(); let pt = parse_bulk(&read_reply(&mut s)).expect("pt"); assert_eq!(pt, msg); println!("decrypted ok"); // Sign by name s.write_all(arr(&["age","signname","signer", msg]).as_bytes()).unwrap(); let sig_b64 = parse_bulk(&read_reply(&mut s)).expect("sig b64"); // Verify by name s.write_all(arr(&["age","verifyname","signer", msg, &sig_b64]).as_bytes()).unwrap(); let ok = parse_simple(&read_reply(&mut s)).expect("verify"); assert_eq!(ok, "1"); println!("signature verified"); // List names s.write_all(arr(&["age","list"]).as_bytes()).unwrap(); let list = read_reply(&mut s); println!("LIST -> {list}"); println!("✔ persistent AGE workflow complete."); }