Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,181 @@
|
||||
//! 独立 std-only 协议对端;测试从固定 Rust 工具链构建,不调用宿主语言环境。
|
||||
|
||||
use std::io::{Read, Write};
|
||||
|
||||
fn read() -> Option<String> {
|
||||
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::<Vec<_>>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user