feat: release Dever 0.1.5 with direct workers and long transactions

This commit is contained in:
Codex committed 2026-10-11 11:17:33 +00:00
1 parent 89629c2197
commit a900d7e8db
153 files changed
+3676 -3708

No files matched your search

+310
View File
@@ -0,0 +1,310 @@
#include "dever_ffi.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BYTES (16U * 1024U * 1024U)
#define MAX_TOKENS 65536U
#define MAX_DEPTH 64U
typedef struct {
size_t start, end, after, count;
char kind;
} token;
typedef struct {
const char *data;
size_t length, cursor, used;
token *tokens;
} document;
static void whitespace(document *doc) {
while (doc->cursor < doc->length && strchr(" \t\r\n", doc->data[doc->cursor]) != NULL)
doc->cursor++;
}
static int string_end(document *doc) {
if (doc->data[doc->cursor++] != '"') return 0;
while (doc->cursor < doc->length) {
unsigned char byte = (unsigned char)doc->data[doc->cursor++];
if (byte == '"') return 1;
if (byte < 32) return 0;
if (byte == '\\') {
if (doc->cursor == doc->length) return 0;
byte = (unsigned char)doc->data[doc->cursor++];
if (byte == 'u') {
for (unsigned digit = 0; digit < 4; digit++)
if (doc->cursor == doc->length || !isxdigit((unsigned char)doc->data[doc->cursor++])) return 0;
} else if (strchr("\"\\/bfnrt", byte) == NULL) return 0;
}
}
return 0;
}
static int number_end(document *doc) {
if (doc->data[doc->cursor] == '-') doc->cursor++;
if (doc->cursor == doc->length) return 0;
if (doc->data[doc->cursor] == '0') doc->cursor++;
else {
if (doc->data[doc->cursor] < '1' || doc->data[doc->cursor] > '9') return 0;
while (doc->cursor < doc->length && isdigit((unsigned char)doc->data[doc->cursor])) doc->cursor++;
}
if (doc->cursor < doc->length && doc->data[doc->cursor] == '.') {
size_t start = ++doc->cursor;
while (doc->cursor < doc->length && isdigit((unsigned char)doc->data[doc->cursor])) doc->cursor++;
if (doc->cursor == start) return 0;
}
if (doc->cursor < doc->length && strchr("eE", doc->data[doc->cursor]) != NULL) {
doc->cursor++;
if (doc->cursor < doc->length && strchr("+-", doc->data[doc->cursor]) != NULL) doc->cursor++;
size_t start = doc->cursor;
while (doc->cursor < doc->length && isdigit((unsigned char)doc->data[doc->cursor])) doc->cursor++;
if (doc->cursor == start) return 0;
}
return 1;
}
static int value(document *doc, unsigned depth) {
whitespace(doc);
if (depth > MAX_DEPTH || doc->used == MAX_TOKENS || doc->cursor == doc->length) return 0;
token *item = &doc->tokens[doc->used++];
item->start = doc->cursor;
item->kind = doc->data[doc->cursor];
if (item->kind == '"') {
if (!string_end(doc)) return 0;
} else if (item->kind == '{' || item->kind == '[') {
char end = item->kind == '{' ? '}' : ']';
doc->cursor++;
whitespace(doc);
if (doc->cursor == doc->length) return 0;
if (doc->data[doc->cursor] != end) {
for (;;) {
whitespace(doc);
if (item->kind == '{') {
if (doc->cursor == doc->length || doc->data[doc->cursor] != '"' || !value(doc, depth + 1)) return 0;
whitespace(doc);
if (doc->cursor == doc->length || doc->data[doc->cursor++] != ':') return 0;
}
if (!value(doc, depth + 1)) return 0;
item->count++;
whitespace(doc);
if (doc->cursor == doc->length) return 0;
if (doc->data[doc->cursor] == end) break;
if (doc->data[doc->cursor++] != ',') return 0;
}
}
doc->cursor++;
} else {
const char *literal = item->kind == 't' ? "true" : item->kind == 'f' ? "false" : item->kind == 'n' ? "null" : NULL;
if (literal != NULL) {
size_t size = strlen(literal);
if (size > doc->length - doc->cursor || memcmp(doc->data + doc->cursor, literal, size) != 0) return 0;
doc->cursor += size;
} else if (!number_end(doc)) return 0;
}
item->end = doc->cursor;
item->after = doc->used;
return 1;
}
static int parse(document *doc, const char *data, size_t size) {
*doc = (document){.data = data, .length = size};
if (size == 0 || size > MAX_BYTES || memchr(data, 0, size) != NULL) return 0;
doc->tokens = calloc(MAX_TOKENS, sizeof(token));
if (doc->tokens == NULL) return 0;
if (value(doc, 0)) {
whitespace(doc);
if (doc->cursor == size) return 1;
}
free(doc->tokens);
doc->tokens = NULL;
return 0;
}
static dever_ffi_slice slice(const document *doc, size_t index) {
const token *item = &doc->tokens[index];
return (dever_ffi_slice){doc->data + item->start, item->end - item->start};
}
static int text_is(const document *doc, size_t index, const char *text) {
if (index >= doc->used || doc->tokens[index].kind != '"') return 0;
dever_ffi_slice part = slice(doc, index);
return part.size == strlen(text) + 2 && memcmp(part.data + 1, text, (size_t)part.size - 2) == 0;
}
static size_t field(const document *doc, const char *name) {
size_t found = MAX_TOKENS;
if (doc->tokens[0].kind != '{') return found;
for (size_t index = 1; index < doc->tokens[0].after;) {
size_t entry = doc->tokens[index].after;
if (text_is(doc, index, name)) {
if (found != MAX_TOKENS) return MAX_TOKENS;
found = entry;
}
index = doc->tokens[entry].after;
}
return found;
}
static int same(const document *left, size_t left_index, const document *right, size_t right_index) {
if (left_index >= left->used || right_index >= right->used) return 0;
const token *left_item = &left->tokens[left_index], *right_item = &right->tokens[right_index];
if (left_item->kind != right_item->kind || left_item->count != right_item->count) return 0;
if (left_item->kind == '[') {
for (size_t offset = 1; offset <= left_item->count; offset++)
if (!same(left, left_index + offset, right, right_index + offset)) return 0;
return 1;
}
dever_ffi_slice left_slice = slice(left, left_index), right_slice = slice(right, right_index);
return left_slice.size == right_slice.size && memcmp(left_slice.data, right_slice.data, (size_t)left_slice.size) == 0;
}
static int append(dever_ffi_output *output, dever_ffi_slice input) {
if (input.size > output->capacity - output->size) return 0;
memcpy(output->data + output->size, input.data, (size_t)input.size);
output->size += input.size;
return 1;
}
static int literal(dever_ffi_output *output, const char *text) {
return append(output, (dever_ffi_slice){text, strlen(text)});
}
static int send(dever_ffi_slice data) {
if (data.size == 0 || data.size > MAX_BYTES) return 0;
unsigned char size[4] = {(unsigned char)(data.size >> 24), (unsigned char)(data.size >> 16), (unsigned char)(data.size >> 8), (unsigned char)data.size};
return fwrite(size, 1, 4, stdout) == 4 && fwrite(data.data, 1, (size_t)data.size, stdout) == data.size && fflush(stdout) == 0;
}
static char *receive(size_t *length) {
unsigned char size[4];
if (fread(size, 1, 4, stdin) != 4) return NULL;
*length = ((uint32_t)size[0] << 24) | ((uint32_t)size[1] << 16) | ((uint32_t)size[2] << 8) | size[3];
if (*length == 0 || *length > MAX_BYTES) return NULL;
char *data = malloc(*length);
if (data == NULL) return NULL;
if (fread(data, 1, *length, stdin) != *length) { free(data); return NULL; }
return data;
}
static int identifier(const document *doc, size_t index, uint64_t *result) {
if (index >= doc->used) return 0;
dever_ffi_slice input = slice(doc, index);
uint64_t number = 0;
for (uint64_t offset = 0; offset < input.size; offset++) {
unsigned digit = (unsigned char)input.data[offset] - '0';
if (digit > 9 || number > ((uint64_t)INT64_MAX - digit) / 10) return 0;
number = number * 10 + digit;
}
*result = number;
return 1;
}
static int serve(const dever_ffi_handler *handler, const document *manifest, int *opened) {
size_t length = 0;
char *input = receive(&length);
document hello = {0};
char *buffer = malloc(MAX_BYTES), *returned = malloc(MAX_BYTES);
int okay = input != NULL && buffer != NULL && returned != NULL && parse(&hello, input, length);
const char *fields[] = {"port", "schema", "adapter", "capabilities", "operations"};
if (okay) okay = hello.tokens[0].count == 8 && text_is(&hello, field(&hello, "kind"), "hello") && text_is(&hello, field(&hello, "version"), "dever-component-1");
for (size_t index = 0; okay && index < 5; index++) okay = same(&hello, field(&hello, fields[index]), manifest, field(manifest, fields[index]));
size_t setting = okay ? field(&hello, "setting") : MAX_TOKENS;
if (okay) okay = setting < hello.used;
if (okay && handler->open != NULL) okay = handler->open(handler->context, slice(&hello, setting)) == DEVER_FFI_OK;
dever_ffi_output output = {buffer, MAX_BYTES, 0};
if (okay) {
*opened = 1;
okay = literal(&output, "{\"kind\":\"ready\",\"version\":\"dever-component-1\"");
for (size_t index = 0; okay && index < 5; index++)
okay = literal(&output, ",\"") && literal(&output, fields[index]) && literal(&output, "\":") && append(&output, slice(manifest, field(manifest, fields[index])));
okay = okay && literal(&output, "}") && send((dever_ffi_slice){output.data, output.size});
}
free(hello.tokens);
free(input);
uint64_t next_id = 1;
int cancelled = 0, stopped = 0;
while (okay && !stopped) {
input = receive(&length);
document message = {0};
okay = input != NULL && parse(&message, input, length);
if (!okay) { free(input); break; }
size_t kind = field(&message, "kind"), id_index = field(&message, "id");
uint64_t request_id = 0;
output.size = 0;
if (text_is(&message, kind, "shutdown")) {
okay = message.tokens[0].count == 1 && send((dever_ffi_slice){"{\"kind\":\"shutdown\"}", 19});
stopped = 1;
} else if (text_is(&message, kind, "health")) {
okay = message.tokens[0].count == 2 && identifier(&message, id_index, &request_id) && request_id == 0 && send((dever_ffi_slice){input, length});
} else if (text_is(&message, kind, "cancel")) {
okay = message.tokens[0].count == 2 && identifier(&message, id_index, &request_id) && request_id > 0 && request_id == next_id - 1 && !cancelled;
cancelled = 1;
} else if (text_is(&message, kind, "call")) {
size_t operation = field(&message, "operation"), payload = field(&message, "payload");
okay = message.tokens[0].count == 4 && identifier(&message, id_index, &request_id) && request_id == next_id && payload < message.used && operation < message.used && message.tokens[operation].kind == '"';
size_t operations = field(manifest, "operations");
int found = 0;
for (size_t index = operations + 1; okay && index < manifest->tokens[operations].after; index = manifest->tokens[index].after)
if (same(&message, operation, manifest, index)) found = 1;
okay = okay && found;
if (okay) {
next_id++;
cancelled = 0;
dever_ffi_slice operation_name = slice(&message, operation);
operation_name.data++;
operation_name.size -= 2;
dever_ffi_output result = {returned, MAX_BYTES - 256, 0};
int status = handler->invoke(handler->context, operation_name, slice(&message, payload), &result);
document result_doc = {0};
okay = result.data == returned && result.capacity == MAX_BYTES - 256 && result.size <= result.capacity && parse(&result_doc, returned, (size_t)result.size);
if (okay && status == DEVER_FFI_OK) {
okay = literal(&output, "{\"kind\":\"result\",\"id\":") && append(&output, slice(&message, id_index)) && literal(&output, ",\"payload\":") && append(&output, (dever_ffi_slice){returned, result.size});
} else if (okay && status == DEVER_FFI_ERROR) {
size_t error = field(&result_doc, "error"), error_payload = field(&result_doc, "payload");
okay = result_doc.tokens[0].count == 2 && error < result_doc.used && result_doc.tokens[error].kind == '"' && error_payload < result_doc.used;
okay = okay && literal(&output, "{\"kind\":\"error\",\"id\":") && append(&output, slice(&message, id_index)) && literal(&output, ",\"error\":") && append(&output, slice(&result_doc, error)) && literal(&output, ",\"payload\":") && append(&output, slice(&result_doc, error_payload));
} else okay = 0;
okay = okay && literal(&output, "}") && send((dever_ffi_slice){output.data, output.size});
free(result_doc.tokens);
}
} else okay = 0;
free(message.tokens);
free(input);
}
free(buffer);
free(returned);
return okay && stopped;
}
int dever_ffi_serve(const dever_ffi_handler *handler) {
if (handler == NULL || handler->abi != DEVER_FFI_ABI_V1 || handler->invoke == NULL) return 1;
FILE *file = fopen("contract.json", "rb");
if (file == NULL) return 1;
char *data = malloc(MAX_BYTES + 1);
if (data == NULL) { fclose(file); return 1; }
size_t size = fread(data, 1, MAX_BYTES + 1, file);
int okay = !ferror(file) && size <= MAX_BYTES;
fclose(file);
document manifest = {0};
okay = okay && parse(&manifest, data, size);
if (okay) {
size_t operations = field(&manifest, "operations");
okay = operations < manifest.used && manifest.tokens[operations].kind == '[' && manifest.tokens[operations].count > 0;
const char *names[] = {"port", "schema", "adapter"};
for (size_t index = 0; okay && index < 3; index++) {
size_t entry = field(&manifest, names[index]);
okay = entry < manifest.used && manifest.tokens[entry].kind == '"';
}
size_t capabilities = field(&manifest, "capabilities");
okay = okay && capabilities < manifest.used && manifest.tokens[capabilities].kind == '[';
}
int opened = 0;
okay = okay && serve(handler, &manifest, &opened);
if (opened && handler->close != NULL) handler->close(handler->context);
free(manifest.tokens);
free(data);
if (!okay) fputs("native FFI Worker failed\n", stderr);
return okay ? 0 : 1;
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef DEVER_FFI_H
#define DEVER_FFI_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DEVER_FFI_ABI_V1 1
#define DEVER_FFI_OK 0
#define DEVER_FFI_ERROR 1
#define DEVER_FFI_FAULT 2
typedef struct {
const char *data;
uint64_t size;
} dever_ffi_slice;
typedef struct {
char *data;
uint64_t capacity;
uint64_t size;
} dever_ffi_output;
typedef struct {
uint32_t abi;
void *context;
int (*open)(void *context, dever_ffi_slice setting);
int (*invoke)(void *context, dever_ffi_slice operation, dever_ffi_slice payload, dever_ffi_output *output);
void (*close)(void *context);
} dever_ffi_handler;
int dever_ffi_serve(const dever_ffi_handler *handler);
#ifdef __cplusplus
}
#endif
#endif