2026-06-12 19:55:35 +00:00

143 lines
2.7 KiB
C++

// WASM-PROPOSAL Phase 2 — native UCE core subset compiled to WASM.
//
// This scaffold validates the Phase 2 membrane without the Phase 3 dynamic
// loader: the core owns memory/libc++/DValue/UCEB1, imports a tiny hostcall
// surface, decodes a host-provided UCEB1 request context, and invokes one
// statically linked real .uce page.
#include <cstdlib>
#include <cstring>
#include "../../src/lib/types.h"
#include "../../src/lib/dvalue.cpp"
extern "C" {
size_t uce_host_ctx_read(char* buf, size_t cap);
void uce_host_log(int level, const char* buf, size_t len);
}
#define RENDER(X) extern "C" void __uce_render(X)
#include "page.uce"
static Request g_request;
static ByteStream g_ob;
static String g_output;
SharedUnit::~SharedUnit() {}
String nibble(String div, String& haystack)
{
auto pos = haystack.find(div);
if(pos == String::npos)
{
auto result = haystack;
haystack.clear();
return(result);
}
auto result = haystack.substr(0, pos);
haystack.erase(0, pos + div.length());
return(result);
}
void Request::ob_start()
{
ob_stack.push_back(new ByteStream());
ob = ob_stack.back();
}
void Request::set_status(s32 code, String reason)
{
if(reason == "")
reason = code == 200 ? "OK" : "Status";
response_code = "HTTP/1.1 " + std::to_string(code) + " " + reason;
}
Request::~Request()
{
for(auto* stream : ob_stack)
delete stream;
ob_stack.clear();
}
static void phase2_clear_ob_stack()
{
for(auto* stream : g_request.ob_stack)
delete stream;
g_request.ob_stack.clear();
}
static void phase2_apply_context(DValue& root)
{
g_request.call = root;
g_request.params.clear();
DValue* params = root.key("params");
if(params)
{
params->each([&](const DValue& item, String key) {
g_request.params[key] = item.to_string();
});
}
}
extern "C" {
void* uce_alloc(size_t len)
{
return(malloc(len));
}
void uce_free(void* ptr)
{
free(ptr);
}
int uce_phase2_render()
{
context = &g_request;
phase2_clear_ob_stack();
g_ob.str("");
g_ob.clear();
g_request.ob = &g_ob;
g_request.out = "";
g_output = "";
size_t ctx_required = uce_host_ctx_read(0, 0);
if(ctx_required == 0)
return(10);
char* ctx_buf = (char*)malloc(ctx_required);
if(ctx_buf == 0)
return(11);
size_t ctx_len = uce_host_ctx_read(ctx_buf, ctx_required);
if(ctx_len != ctx_required)
{
free(ctx_buf);
return(12);
}
DValue decoded;
String error;
bool ok = ucb_decode(String(ctx_buf, ctx_len), decoded, &error);
free(ctx_buf);
if(!ok)
{
uce_host_log(3, error.data(), error.size());
return(20);
}
phase2_apply_context(decoded);
__uce_render(g_request);
g_output = g_ob.str();
return(0);
}
const char* uce_phase2_output_data()
{
return(g_output.data());
}
size_t uce_phase2_output_size()
{
return(g_output.size());
}
}