feat: extend wasm backend entrypoints
This commit is contained in:
+42
-12
@@ -84,6 +84,7 @@ struct WasmWorkerConfig
|
||||
struct WasmResponse
|
||||
{
|
||||
bool ok = false;
|
||||
bool handler_present = true; // false → unit has no handler for the requested kind (404)
|
||||
String body;
|
||||
DValue meta; // status / headers / cookies / session
|
||||
String error; // collapsed trace or loader error when !ok
|
||||
@@ -387,7 +388,8 @@ public:
|
||||
|
||||
// resolve-kind values shared with the guest core (src/wasm/core.cpp)
|
||||
// must match WasmResolveKind in src/wasm/core.cpp
|
||||
enum ResolveKind { RESOLVE_COMPONENT = 0, RESOLVE_RENDER = 1, RESOLVE_EXISTS = 2, RESOLVE_ONCE = 3 };
|
||||
enum ResolveKind { RESOLVE_COMPONENT = 0, RESOLVE_RENDER = 1, RESOLVE_EXISTS = 2, RESOLVE_ONCE = 3,
|
||||
RESOLVE_CLI = 4, RESOLVE_WEBSOCKET = 5, RESOLVE_SERVE_HTTP = 6 };
|
||||
|
||||
String birth()
|
||||
{
|
||||
@@ -480,35 +482,59 @@ public:
|
||||
return("");
|
||||
}
|
||||
|
||||
String render_entry(const String& entry_source_path)
|
||||
// Invoke the entry unit through one of its directive handlers
|
||||
// (render/cli/websocket/serve_http, selected by kind). handler_present, when
|
||||
// provided, reports whether the unit actually exports that handler — the
|
||||
// caller maps a missing render to an empty body (native parity) and a
|
||||
// missing cli/serve handler to a 404.
|
||||
String invoke_entry(const String& entry_source_path, int32_t kind, bool* handler_present = 0,
|
||||
const String& handler_name = "")
|
||||
{
|
||||
entry_dir = dir_of(entry_source_path);
|
||||
size_t unit_index = 0;
|
||||
String error = load_unit(entry_source_path, unit_index);
|
||||
if(error != "")
|
||||
return(error);
|
||||
// a page with no RENDER block renders empty (native parity), not an error
|
||||
if(!unit_func(unit_index, "__uce_render"))
|
||||
// Base handler export for the kind, plus the named suffix (serve_http /
|
||||
// render / component can route to a named entry, e.g. __uce_serve_http_x).
|
||||
String symbol = kind == RESOLVE_CLI ? "__uce_cli"
|
||||
: kind == RESOLVE_WEBSOCKET ? "__uce_websocket"
|
||||
: kind == RESOLVE_SERVE_HTTP ? "__uce_serve_http"
|
||||
: "__uce_render";
|
||||
if(handler_name != "")
|
||||
symbol += "_" + sanitize_symbol_suffix(handler_name);
|
||||
bool present = (bool)unit_func(unit_index, symbol);
|
||||
if(handler_present)
|
||||
*handler_present = present;
|
||||
if(!present)
|
||||
return("");
|
||||
// Render through the core so the entry gets the same ONCE() + dispatch
|
||||
// The core parses a "path:name" target into the named suffix; the bare
|
||||
// path above loaded the module, this drives the handler resolution.
|
||||
String target = handler_name == "" ? entry_source_path : entry_source_path + ":" + handler_name;
|
||||
// Invoke through the core so the entry gets the same ONCE() + dispatch
|
||||
// path as components (unit is pre-loaded above; resolution is cached).
|
||||
auto entry = core_func("uce_wasm_render_entry");
|
||||
auto entry = core_func("uce_wasm_invoke_entry");
|
||||
if(!entry)
|
||||
return("core does not export uce_wasm_render_entry");
|
||||
return("core does not export uce_wasm_invoke_entry");
|
||||
int32_t guest_ptr = 0;
|
||||
error = call_core("uce_alloc", { (int32_t)entry_source_path.size() }, &guest_ptr);
|
||||
error = call_core("uce_alloc", { (int32_t)target.size() }, &guest_ptr);
|
||||
if(error != "" || guest_ptr == 0)
|
||||
return(error == "" ? String("guest uce_alloc failed for entry path") : error);
|
||||
error = guest_write((u32)guest_ptr, entry_source_path);
|
||||
error = guest_write((u32)guest_ptr, target);
|
||||
if(error != "")
|
||||
return(error);
|
||||
auto result = entry->call(ctx(), { wasmtime::Val(guest_ptr), wasmtime::Val((int32_t)entry_source_path.size()) });
|
||||
auto result = entry->call(ctx(), { wasmtime::Val(guest_ptr), wasmtime::Val((int32_t)target.size()), wasmtime::Val(kind) });
|
||||
call_core("uce_free", { guest_ptr }, 0);
|
||||
if(!result)
|
||||
return(trap_text(result.err()));
|
||||
return("");
|
||||
}
|
||||
|
||||
String render_entry(const String& entry_source_path)
|
||||
{
|
||||
return(invoke_entry(entry_source_path, RESOLVE_RENDER));
|
||||
}
|
||||
|
||||
String collect(WasmResponse& response)
|
||||
{
|
||||
String error = call_core("uce_wasm_finish_output", {}, 0);
|
||||
@@ -1055,6 +1081,9 @@ private:
|
||||
}
|
||||
String symbol = kind == RESOLVE_RENDER ? "__uce_render"
|
||||
: kind == RESOLVE_ONCE ? "__uce_once"
|
||||
: kind == RESOLVE_CLI ? "__uce_cli"
|
||||
: kind == RESOLVE_WEBSOCKET ? "__uce_websocket"
|
||||
: kind == RESOLVE_SERVE_HTTP ? "__uce_serve_http"
|
||||
: "__uce_component";
|
||||
if(render_name != "")
|
||||
symbol += "_" + sanitize_symbol_suffix(render_name);
|
||||
@@ -1735,7 +1764,8 @@ private:
|
||||
|
||||
// ---- public entry: one request through one workspace -----------------------
|
||||
|
||||
inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_tree, const String& entry_source_path)
|
||||
inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_tree, const String& entry_source_path,
|
||||
int32_t kind = WasmWorkspace::RESOLVE_RENDER, const String& handler_name = "")
|
||||
{
|
||||
WasmResponse response;
|
||||
WasmWorkspace workspace(worker);
|
||||
@@ -1746,7 +1776,7 @@ inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_
|
||||
if(error == "")
|
||||
error = workspace.apply_context(context_tree);
|
||||
if(error == "")
|
||||
error = workspace.render_entry(entry_source_path);
|
||||
error = workspace.invoke_entry(entry_source_path, kind, &response.handler_present, handler_name);
|
||||
if(error == "")
|
||||
error = workspace.collect(response);
|
||||
response.workspace_birth_us = workspace.workspace_birth_us;
|
||||
|
||||
Reference in New Issue
Block a user