feat: publish Dever core with project scaffolding and versioned AI skills
This commit is contained in:
1 parent
70fa73cdc2
commit
ac458ffa7f
960 files changed
+221319
-1163
No files matched your search
@@ -0,0 +1,101 @@
|
||||
//! Ordinary argv/stdin/stdout fixture: deliberately has no Dever protocol.
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
match run() {
|
||||
Ok(code) => std::process::exit(code),
|
||||
Err(error) => {
|
||||
eprintln!("{error}");
|
||||
if matches!(
|
||||
std::env::args().nth(1).as_deref(),
|
||||
Some("tree" | "wait" | "heartbeat")
|
||||
) && let Some(directory) = std::env::args().nth(2)
|
||||
{
|
||||
let _ = std::fs::write(
|
||||
Path::new(&directory).join("fixture-error"),
|
||||
error.to_string(),
|
||||
);
|
||||
}
|
||||
std::process::exit(91);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> Result<i32, Box<dyn std::error::Error>> {
|
||||
let mut arguments = std::env::args().skip(1);
|
||||
match arguments.next().as_deref() {
|
||||
Some("echo") => {
|
||||
for argument in arguments {
|
||||
std::io::stdout().write_all(argument.as_bytes())?;
|
||||
std::io::stdout().write_all(&[0])?;
|
||||
}
|
||||
}
|
||||
Some("stdin") => {
|
||||
std::io::copy(&mut std::io::stdin(), &mut std::io::stdout())?;
|
||||
std::io::stderr().write_all(&[0, 255, 128, 10])?;
|
||||
}
|
||||
Some("exit") => return Ok(arguments.next().ok_or("missing exit code")?.parse()?),
|
||||
Some("fds") => {
|
||||
let descriptors = std::fs::read_dir("/proc/self/fd")?
|
||||
.map(|entry| entry.map(|entry| entry.path()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
for descriptor in descriptors {
|
||||
let Some(number) = descriptor
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.and_then(|name| name.parse::<u32>().ok())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if number > 2 && std::fs::read_link(&descriptor).is_ok() {
|
||||
writeln!(std::io::stdout(), "{number}")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some("duplex") => {
|
||||
let count: usize = arguments.next().ok_or("missing output length")?.parse()?;
|
||||
let stdout = std::thread::spawn(move || std::io::stdout().write_all(&vec![254; count]));
|
||||
let stderr = std::thread::spawn(move || std::io::stderr().write_all(&vec![253; count]));
|
||||
let mut input = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut input)?;
|
||||
stdout.join().map_err(|_| "stdout thread panicked")??;
|
||||
stderr.join().map_err(|_| "stderr thread panicked")??;
|
||||
}
|
||||
Some("wait") | Some("tree") => {
|
||||
let directory = arguments.next().ok_or("missing marker directory")?;
|
||||
let directory = Path::new(&directory);
|
||||
let mut starts = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(directory.join("starts"))?;
|
||||
starts.write_all(b"started\n")?;
|
||||
// Every lifecycle case gets a real descendant. PID namespace exit
|
||||
// must stop its heartbeat before the runtime returns cancellation.
|
||||
let mut child = std::process::Command::new(std::env::current_exe()?)
|
||||
.arg("heartbeat")
|
||||
.arg(directory)
|
||||
.spawn()?;
|
||||
std::fs::write(directory.join("ready"), b"ready")?;
|
||||
let status = child.wait()?;
|
||||
return Ok(status.code().unwrap_or(92));
|
||||
}
|
||||
Some("heartbeat") => {
|
||||
let directory = arguments.next().ok_or("missing marker directory")?;
|
||||
let lifetime = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.write(true)
|
||||
.open(Path::new(&directory).join("lifetime.lock"))?;
|
||||
lifetime.lock()?;
|
||||
let marker = Path::new(&directory).join("heartbeat");
|
||||
for count in 0..3000 {
|
||||
std::fs::write(&marker, count.to_string())?;
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
}
|
||||
_ => return Err("unknown ordinary command mode".into()),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
const MAX_BYTES: usize = 16 * 1024 * 1024;
|
||||
|
||||
fn main() {
|
||||
if std::env::args().skip(1).collect::<Vec<_>>() != ["--dever-component"] {
|
||||
std::process::exit(2);
|
||||
}
|
||||
if let Err(error) = serve() {
|
||||
eprintln!("component fixture: {error}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn serve() -> Result<(), String> {
|
||||
let hello = read_json()?;
|
||||
require_kind(&hello, "hello")?;
|
||||
let mode = hello
|
||||
.pointer("/setting/mode")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("normal");
|
||||
if mode == "delayed_start" {
|
||||
mark(&hello, "starting")?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
let ready = json!({
|
||||
"kind": "ready",
|
||||
"version": field(&hello, "version")?,
|
||||
"port": field(&hello, "port")?,
|
||||
"schema": field(&hello, "schema")?,
|
||||
"adapter": field(&hello, "adapter")?,
|
||||
"capabilities": field(&hello, "capabilities")?,
|
||||
"operations": field(&hello, "operations")?,
|
||||
});
|
||||
match mode {
|
||||
"duplicate_ready" => write_raw(r#"{"kind":"ready","kind":"ready"}"#)?,
|
||||
"capability_mismatch" => {
|
||||
let mut mismatched = ready;
|
||||
mismatched["capabilities"] = json!(["network", "process"]);
|
||||
write_json(&mismatched)?;
|
||||
}
|
||||
_ => write_json(&ready)?,
|
||||
}
|
||||
if matches!(mode, "duplicate_ready" | "capability_mismatch") {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let health = read_json()?;
|
||||
require_kind(&health, "health")?;
|
||||
write_json(&health)?;
|
||||
eprintln!("fixture ready");
|
||||
|
||||
loop {
|
||||
let message = read_json()?;
|
||||
match string_field(&message, "kind")? {
|
||||
"call" => handle_call(&message, mode, &hello)?,
|
||||
"shutdown" => {
|
||||
if mode == "delayed_shutdown" {
|
||||
mark(&hello, "stopping")?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
write_json(&json!({"kind": "shutdown"}))?;
|
||||
if mode != "embedded" {
|
||||
mark(&hello, "shutdown")?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
kind => return Err(format!("unexpected {kind} message")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mark(hello: &Value, extension: &str) -> Result<(), String> {
|
||||
let Some(marker) = hello.pointer("/setting/marker").and_then(Value::as_str) else {
|
||||
return Ok(());
|
||||
};
|
||||
let path = std::path::Path::new(marker).with_extension(extension);
|
||||
std::fs::write(path, b"ready").map_err(io_error)
|
||||
}
|
||||
|
||||
fn handle_call(call: &Value, mode: &str, hello: &Value) -> Result<(), String> {
|
||||
let id = field(call, "id")?;
|
||||
// Deliberately malformed business payloads exercise the caller's typed boundary.
|
||||
let payload = match mode {
|
||||
"missing_output" => Some(json!({})),
|
||||
"extra_output" => Some(json!({"value": 7, "unknown": true})),
|
||||
"wrong_output" => Some(json!({"value": "invalid number"})),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(payload) = payload {
|
||||
return write_json(&json!({"kind": "result", "id": id, "payload": payload}));
|
||||
}
|
||||
if matches!(mode, "declared_error" | "invalid_error" | "missing_error") {
|
||||
let identity = hello
|
||||
.pointer("/setting/identity")
|
||||
.ok_or("missing error identity")?;
|
||||
let payload = match mode {
|
||||
"invalid_error" => json!({"reason": 7}),
|
||||
"missing_error" => json!({}),
|
||||
_ => json!({"reason": "fixture"}),
|
||||
};
|
||||
return write_json(
|
||||
&json!({"kind": "error", "id": id, "error": identity, "payload": payload}),
|
||||
);
|
||||
}
|
||||
match string_field(call, "operation")? {
|
||||
"echo" => write_json(&json!({
|
||||
"kind": "result",
|
||||
"id": id,
|
||||
"payload": field(call, "payload")?,
|
||||
})),
|
||||
"read" => write_json(&json!({
|
||||
"kind": "result",
|
||||
"id": id,
|
||||
"payload": {"value": 7},
|
||||
})),
|
||||
"fail" => write_json(&json!({
|
||||
"kind": "error",
|
||||
"id": id,
|
||||
"error": "notification.delivery.Rejected",
|
||||
"payload": {"reason": "fixture"},
|
||||
})),
|
||||
"wait" => {
|
||||
let cancel = read_json()?;
|
||||
require_kind(&cancel, "cancel")?;
|
||||
if field(&cancel, "id")? != id {
|
||||
return Err("cancel id does not match call".into());
|
||||
}
|
||||
write_json(&json!({
|
||||
"kind": "error",
|
||||
"id": id,
|
||||
"error": "notification.delivery.Cancelled",
|
||||
"payload": {},
|
||||
}))
|
||||
}
|
||||
"timeout" => {
|
||||
let cancel = read_json()?;
|
||||
require_kind(&cancel, "cancel")?;
|
||||
if field(&cancel, "id")? != id {
|
||||
return Err("cancel id does not match timed out call".into());
|
||||
}
|
||||
write_json(&json!({"kind": "result", "id": id, "payload": {}}))
|
||||
}
|
||||
"crash" => std::process::exit(7),
|
||||
"duplicate" => write_raw(&format!(
|
||||
r#"{{"kind":"result","id":{id},"id":{id},"payload":{{}}}}"#,
|
||||
id = id
|
||||
)),
|
||||
"out_of_order" => {
|
||||
let id = id.as_u64().ok_or_else(|| "id is not u64".to_owned())?;
|
||||
write_json(&json!({"kind": "result", "id": id + 1, "payload": {}}))
|
||||
}
|
||||
"unknown" => write_json(&json!({"kind": "surprise", "id": id})),
|
||||
"oversize" => {
|
||||
let mut stdout = io::stdout().lock();
|
||||
stdout
|
||||
.write_all(&((MAX_BYTES as u32) + 1).to_be_bytes())
|
||||
.map_err(io_error)?;
|
||||
stdout.flush().map_err(io_error)?;
|
||||
std::process::exit(0);
|
||||
}
|
||||
"truncated" => {
|
||||
let mut stdout = io::stdout().lock();
|
||||
stdout.write_all(&32_u32.to_be_bytes()).map_err(io_error)?;
|
||||
stdout.write_all(b"{").map_err(io_error)?;
|
||||
stdout.flush().map_err(io_error)?;
|
||||
std::process::exit(0);
|
||||
}
|
||||
operation => Err(format!("unknown operation {operation}")),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_json() -> Result<Value, String> {
|
||||
let text = read_frame()?;
|
||||
serde_json::from_str(&text).map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
fn read_frame() -> Result<String, String> {
|
||||
let mut stdin = io::stdin().lock();
|
||||
let mut length = [0_u8; 4];
|
||||
stdin.read_exact(&mut length).map_err(io_error)?;
|
||||
let length = u32::from_be_bytes(length) as usize;
|
||||
if length == 0 || length > MAX_BYTES {
|
||||
return Err("invalid frame length".into());
|
||||
}
|
||||
let mut body = vec![0_u8; length];
|
||||
stdin.read_exact(&mut body).map_err(io_error)?;
|
||||
String::from_utf8(body).map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
fn write_json(value: &Value) -> Result<(), String> {
|
||||
write_raw(&serde_json::to_string(value).map_err(|error| error.to_string())?)
|
||||
}
|
||||
|
||||
fn write_raw(body: &str) -> Result<(), String> {
|
||||
let length = u32::try_from(body.len()).map_err(|_| "fixture frame is too large")?;
|
||||
let mut stdout = io::stdout().lock();
|
||||
stdout.write_all(&length.to_be_bytes()).map_err(io_error)?;
|
||||
stdout.write_all(body.as_bytes()).map_err(io_error)?;
|
||||
stdout.flush().map_err(io_error)
|
||||
}
|
||||
|
||||
fn require_kind(message: &Value, expected: &str) -> Result<(), String> {
|
||||
if string_field(message, "kind")? == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("expected {expected} message"))
|
||||
}
|
||||
}
|
||||
|
||||
fn string_field<'a>(message: &'a Value, name: &str) -> Result<&'a str, String> {
|
||||
field(message, name)?
|
||||
.as_str()
|
||||
.ok_or_else(|| format!("{name} is not a string"))
|
||||
}
|
||||
|
||||
fn field<'a>(message: &'a Value, name: &str) -> Result<&'a Value, String> {
|
||||
message.get(name).ok_or_else(|| format!("missing {name}"))
|
||||
}
|
||||
|
||||
fn io_error(error: io::Error) -> String {
|
||||
error.to_string()
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
type Buffer {
|
||||
text: Text
|
||||
count: Int
|
||||
}
|
||||
|
||||
type Index {
|
||||
values: Map<Int, Int>
|
||||
next: Int
|
||||
}
|
||||
|
||||
double(value: Int, text: Text) (next: Text) {
|
||||
next = text + text
|
||||
}
|
||||
|
||||
grow(value: Int, state: Buffer) (next: Buffer) {
|
||||
next = state
|
||||
next.text = state.text + "a"
|
||||
next.count = state.count + 1
|
||||
}
|
||||
|
||||
insert(value: Int, state: Index) (next: Index) {
|
||||
next = state
|
||||
next.values = put(state.values, state.next, value)
|
||||
next.next = state.next + 1
|
||||
}
|
||||
|
||||
word(value: Int) (result: Text) {
|
||||
result = "abcdefgh你好"
|
||||
}
|
||||
|
||||
copy(value: Text) (result: Text) {
|
||||
result = value
|
||||
}
|
||||
|
||||
clock(value: dever.time.ClockResult.Read(nanos)) (result: Int) recover("benchmark clock failures are reported") {
|
||||
result = nanos
|
||||
}
|
||||
|
||||
clock(value: dever.time.ClockResult.Failed(message)) (result: Int) recover("benchmark clock failures are reported") {
|
||||
dever.io.println("FAILED:" + message)
|
||||
result = 0
|
||||
}
|
||||
|
||||
json(value: dever.json.value.ParseResult.Parsed(document)) (result: Int) recover("benchmark parse failures are reported") {
|
||||
result = length(document.nodes)
|
||||
}
|
||||
|
||||
json(value: dever.json.value.ParseResult.Failed(position, message)) (result: Int) recover("benchmark parse failures are reported") {
|
||||
dever.io.println("FAILED:" + message)
|
||||
result = 0
|
||||
}
|
||||
|
||||
sample(index: Int, bytes: Bytes) () {
|
||||
start = clock(result(dever.time.monotonic_nanos()))
|
||||
buffer = reduce(
|
||||
grow,
|
||||
bytes,
|
||||
Buffer {
|
||||
text = ""
|
||||
count = 0
|
||||
}
|
||||
)
|
||||
text_end = clock(result(dever.time.monotonic_nanos()))
|
||||
mapped = each(copy, each(word, bytes))
|
||||
list_end = clock(result(dever.time.monotonic_nanos()))
|
||||
document = json(result(dever.json.parse("\"" + buffer.text + "\"")))
|
||||
json_end = clock(result(dever.time.monotonic_nanos()))
|
||||
dever.io.println(
|
||||
"text|" + int.to_text(buffer.count) + "|" + int.to_text(text_end - start)
|
||||
)
|
||||
dever.io.println(
|
||||
"list|" + int.to_text(length(mapped)) + "|" + int.to_text(list_end - text_end)
|
||||
)
|
||||
dever.io.println(
|
||||
"json|" + int.to_text(document) + "|" + int.to_text(json_end - list_end)
|
||||
)
|
||||
}
|
||||
|
||||
run() () {
|
||||
text = reduce(double, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "a")
|
||||
each(sample, [0, 1, 2, 3, 4, 5], dever.bytes.from_text(text))
|
||||
start = clock(result(dever.time.monotonic_nanos()))
|
||||
index = reduce(
|
||||
insert,
|
||||
dever.bytes.from_text(text),
|
||||
Index {
|
||||
values = {}
|
||||
next = 0
|
||||
}
|
||||
)
|
||||
end = clock(result(dever.time.monotonic_nanos()))
|
||||
dever.io.println(
|
||||
"map|" + int.to_text(length(index.values)) + "|" + int.to_text(end - start)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
main() () {
|
||||
benchmark.allocation.run()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cmd fixture_member = app.fixture_member
|
||||
@@ -0,0 +1,27 @@
|
||||
fixture_member(
|
||||
selected_tenant_id: platform.tenant.model.id,
|
||||
email: Text,
|
||||
display_name: Text,
|
||||
password: Secret
|
||||
) (result: BootstrapView) {
|
||||
input = domain.prepare(email, display_name)
|
||||
hash = blocking(dever.crypto.password_hash(password))
|
||||
principal = model.principal.create(
|
||||
{
|
||||
display_name = input.name
|
||||
}
|
||||
)
|
||||
stored = model.create(
|
||||
{
|
||||
principal_id = principal.id
|
||||
email = input.address
|
||||
password_hash = hash
|
||||
}
|
||||
)
|
||||
user.membership.fixture_join(principal.id, selected_tenant_id)
|
||||
result = BootstrapView {
|
||||
tenant_id = selected_tenant_id
|
||||
user_id = principal.id
|
||||
credential_id = stored.id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fixture_join(
|
||||
account_id: user.account.model.principal.id,
|
||||
selected_tenant_id: platform.tenant.model.id
|
||||
) () {
|
||||
stored = model.create(
|
||||
{
|
||||
user_id = account_id
|
||||
tenant_id = selected_tenant_id
|
||||
role = model.MembershipRole.Reader
|
||||
}
|
||||
)
|
||||
discarded = stored
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBmTCCAT+gAwIBAgIUYx/Ad4tJiQ4uakAPbpXu5Senv2YwCgYIKoZIzj0EAwIw
|
||||
GjEYMBYGA1UEAwwPRGV2ZXItVGVzdC1Sb290MB4XDTI2MDkxMjA4MTY1MFoXDTM2
|
||||
MDkwOTA4MTY1MFowGjEYMBYGA1UEAwwPRGV2ZXItVGVzdC1Sb290MFkwEwYHKoZI
|
||||
zj0CAQYIKoZIzj0DAQcDQgAECOux92VpsFwb2YOTRs6UATfp7HPm+JeCTMkJNXPo
|
||||
rqLZa4Vi/71dLQzNFxxsXxqFyf4oBYoCD0XMEicxYUgnO6NjMGEwHQYDVR0OBBYE
|
||||
FIo/Vdu7qm5dIikkwg6A0yRp1YzVMB8GA1UdIwQYMBaAFIo/Vdu7qm5dIikkwg6A
|
||||
0yRp1YzVMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49
|
||||
BAMCA0gAMEUCICmmB/eG055dU7F9OP7K9BUxOkFnYNtzIpYJfd0VwG6LAiEA4oiP
|
||||
pnep4mLGHAnvsucvvqDA5SVdHzYh22OYPdSgNeY=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYl2wcdhzZMZrQxSV
|
||||
ClBRv8AQqRyuJf5bSVXw5w6XLWmhRANCAAROwX6ZplJMfQicbaDXSZ7qoLPGDdr6
|
||||
EMtvQvlJdwVI44/NVX/lIS2dhF0h1GxKAippeSiLj9+Srh2mmg7+zEvK
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBdjCCARugAwIBAgIBATAKBggqhkjOPQQDAjAaMRgwFgYDVQQDDA9EZXZlci1U
|
||||
ZXN0LVJvb3QwHhcNMjYwOTEyMDgxNjUwWhcNMzYwOTA5MDgxNjUwWjAUMRIwEAYD
|
||||
VQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAROwX6ZplJM
|
||||
fQicbaDXSZ7qoLPGDdr6EMtvQvlJdwVI44/NVX/lIS2dhF0h1GxKAippeSiLj9+S
|
||||
rh2mmg7+zEvKo1gwVjAUBgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFEc4
|
||||
R7JUtHLl16fHXxBvGDz0qwnKMB8GA1UdIwQYMBaAFIo/Vdu7qm5dIikkwg6A0yRp
|
||||
1YzVMAoGCCqGSM49BAMCA0kAMEYCIQCzl7jB3XrkRoQXTXMoi9j1OzmCPO3UXLr5
|
||||
eDq/F8G/twIhALgVU/5C4hx6hpVtlHUmd49EibizuPlNeaCjRPB1WqDM
|
||||
-----END CERTIFICATE-----
|
||||
Reference in new issue
Block a user