//! 独立 std-only 协议对端;测试从固定 Rust 工具链构建,不调用宿主语言环境。 use std::io::{Read, Write}; fn read() -> Option { let mut prefix = [0; 4]; std::io::stdin().read_exact(&mut prefix).ok()?; let mut bytes = vec![0; u32::from_be_bytes(prefix) as usize]; std::io::stdin().read_exact(&mut bytes).unwrap(); Some(String::from_utf8(bytes).unwrap()) } fn send(value: &str) { let mut output = std::io::stdout().lock(); output .write_all(&(value.len() as u32).to_be_bytes()) .unwrap(); output.write_all(value.as_bytes()).unwrap(); output.flush().unwrap(); } fn main() { let args = std::env::args().skip(1).collect::>(); if let Some(mode) = args.first() { match mode.as_str() { "--echo" => { let mut bytes = Vec::new(); std::io::stdin().read_to_end(&mut bytes).unwrap(); std::io::stdout().write_all(&bytes).unwrap(); std::io::stderr() .write_all(args[1..].join("\n").as_bytes()) .unwrap(); std::process::exit(7); } "--hang" => { std::fs::write(&args[1], std::process::id().to_string()).unwrap(); std::thread::sleep(std::time::Duration::from_secs(10)); return; } "--flood" => { std::io::stdout().write_all(&[1; 4096]).unwrap(); std::io::stderr().write_all(&[2; 4096]).unwrap(); return; } _ => panic!("unknown test command"), } } let Some(hello) = read() else { return; }; assert!(hello.contains("\"kind\":\"hello\"")); let (fields, setting) = hello.rsplit_once(",\"setting\":").unwrap(); if setting.contains("sensitive") { assert!(setting.contains("sensitive\\\"\\\\雪")); } send(&format!("{fields}}}").replace("\"kind\":\"hello\"", "\"kind\":\"ready\"")); let health = read().unwrap(); assert!(health.contains("\"kind\":\"health\"")); send(&health); let mut bad_shutdown = false; while let Some(request) = read() { if request == "{\"kind\":\"shutdown\"}" { if bad_shutdown { send("{}"); std::process::exit(7); } send(&request); return; } let id = request .split("\"id\":") .nth(1) .unwrap() .split([',', '}']) .next() .unwrap(); if request.contains("\"kind\":\"cancel\"") { send(&format!( "{{\"kind\":\"error\",\"id\":{id},\"error\":\"dever.cancelled\",\"payload\":null}}" )); continue; } if request.contains("\"operation\":\"measure\"") { let payload = request .split_once(",\"payload\":") .unwrap() .1 .strip_suffix('}') .unwrap(); let length = payload.len(); let checksum: u64 = payload.bytes().map(u64::from).sum(); send(&format!( "{{\"kind\":\"result\",\"id\":{id},\"payload\":{{\"length\":{length},\"checksum\":{checksum}}}}}" )); continue; } if request.contains("\"operation\":\"crash\"") { std::process::exit(7); } if request.contains("\"operation\":\"hang\"") { continue; } if request.contains("\"operation\":\"ignore\"") { std::thread::sleep(std::time::Duration::from_secs(10)); continue; } if request.contains("\"operation\":\"shutdown_bad\"") { bad_shutdown = true; } if request.contains("\"operation\":\"native\"") { if request.contains("\"input\":-4") || request.contains("\"input\":-5") { bad_shutdown = true; } if request.contains("\"input\":-1") { send(&format!( "{{\"kind\":\"result\",\"id\":{id},\"payload\":{{\"value\":\"wrong-type\"}}}}" )); continue; } if request.contains("\"input\":-2") || request.contains("\"input\":-3") || request.contains("\"input\":-5") { let error = if request.contains("\"input\":-2") { "not.declared.Failed" } else { "dever.api.Error.Invalid" }; send(&format!( "{{\"kind\":\"error\",\"id\":{id},\"error\":\"{error}\",\"payload\":{{}}}}" )); continue; } let value = if request.contains("\"input\":99}") { std::process::id() } else { 42 }; send(&format!( "{{\"kind\":\"result\",\"id\":{id},\"payload\":{{\"value\":{value}}}}}" )); continue; } if request.contains("\"operation\":\"bad\"") { send("{\"kind\":\"result\",\"id\":900,\"payload\":{}}"); continue; } if request.contains("\"operation\":\"error\"") { send(&format!( "{{\"kind\":\"error\",\"id\":{id},\"error\":\"demo.test.Error.Failed\",\"payload\":{{\"message\":\"failed\"}}}}" )); continue; } if let Some((_, fields)) = [ ("null_error", "\"kind\":\"result\",\"error\":null"), ("missing_error", "\"kind\":\"error\""), ("extra_field", "\"kind\":\"result\",\"unexpected\":true"), ] .into_iter() .find(|(operation, _)| request.contains(&format!("\"operation\":\"{operation}\""))) { send(&format!("{{{fields},\"id\":{id},\"payload\":null}}")); continue; } let response = format!( "{{\"kind\":\"result\",\"id\":{id},\"payload\":{{\"value\":42,\"pid\":{}}}}}", std::process::id() ); if request.contains("\"operation\":\"fragment\"") { let prefix = (response.len() as u32).to_be_bytes(); std::io::stdout().write_all(&prefix[..2]).unwrap(); std::io::stdout().flush().unwrap(); assert!(read().unwrap().contains("\"kind\":\"cancel\"")); std::io::stdout().write_all(&prefix[2..]).unwrap(); std::io::stdout().write_all(response.as_bytes()).unwrap(); std::io::stdout().flush().unwrap(); } else { send(&response); } } }