Conversion between incomingHandler and request/response
Hello,
Since the wasi-http defines a server that accepts an incoming request and returns a response, and jco have the ability to serve a server, is it possible to provide a conversion between the WasiHttpIncomingHandler and a classic JS handlerfetch(request: Request): Promise<Response> (used by e.g. Cloudflare Worker and Deno)? Or should I develop a completely new shim based on the preview2-shim?
Hi, I've been working on exactly that. But requires JSPI or Asyncify to handle the asynchronous aspect. Let me know if you are interested in collaborating.
@calvinrp Hi, I wonder if it's possible to have a synchronous version MVP? I think the asynchronous might be better supported with WASI Preview 3?
@peter-jerry-ye I do have sync implementation working just for the incoming response handler, but limited to that.
If you want to do outbound requests or many things that rely upon wasi:io/poll or wasi:io/streams, then you will need async support.
The issue is the JS APIs that you need to use are async but the Wasm functions are sync (in WASI P2). There a few different ways to go about this. JSPI (JavaScript Promise Integration), which is a stack switching proposal, is the ideal implementation. It is behind a feature flag in V8 and expected to be released before the end of year. Asyncify requires a rewrite of the Wasm binary but could be used as a stop gap. Using Atomics and Web Workers is also helpful in some circumstances. Also, to a limited degree there is a path with synchronous XHR, Web Workers and Service Workers.
@calvinrp Thank you very much for your kind explanation. I see that jco server seems to be using Web Workers to solve this issue.
Happy to update on progress. It sounds like what I'm working on will be useful to you.
At this point we have JSPI based bindings and async host imports are possible -- I assume this issue doesn't still apply but if it does I'm happy to re-open (it's been a year)!
Sorry for posting in a closed thread, but I had a similar issue and couldn't find an answer.
I want to run a .NET application compiled for wasi-wasm inside a Cloudflare Worker and handle incoming/outgoing http requests.
<ItemGroup>
<PackageReference Include="BytecodeAlliance.Componentize.DotNet.Wasm.SDK" Version="0.2.0-preview00004" />
</ItemGroup>
<ItemGroup>
<Wit Include="wit/wit.wasm" World="proxy" Registry="ghcr.io/webassembly/wasi/http:0.2.0" />
</ItemGroup>
public class IncomingHandlerImpl : IIncomingHandler
{
public static void Handle(ITypes.IncomingRequest request, ITypes.ResponseOutparam responseOut)
{ }
}
After that I transpile the resulting WASM component:
jco transpile MyApp.wasm -o out-dir --no-namespaced-exports --no-typescript --tla-compat
After initializing the module, I encountered a problem: the handler method requires arguments of the IncomingRequest and IncomingRequest types, but they do not have a public constructor/builder, and as a result, I cannot simply wrap the request object from the fetch handler:
function handle(arg0, arg1) {
if (!_initialized) throwUninitialized();
if (!(arg0 instanceof IncomingRequest)) {
throw new TypeError('Resource error: Not a valid "IncomingRequest" resource.');
}
var handle0 = arg0[symbolRscHandle];
if (!handle0) {
const rep = arg0[symbolRscRep] || ++captureCnt16;
captureTable16.set(rep, arg0);
handle0 = rscTableCreateOwn(handleTable16, rep);
}
if (!(arg1 instanceof ResponseOutparam)) {
throw new TypeError('Resource error: Not a valid "ResponseOutparam" resource.');
}
var handle1 = arg1[symbolRscHandle];
if (!handle1) {
const rep = arg1[symbolRscRep] || ++captureCnt13;
captureTable13.set(rep, arg1);
handle1 = rscTableCreateOwn(handleTable13, rep);
}
_debugLog('[iface="wasi:http/[email protected]", function="handle"] [Instruction::CallWasm] (async? false, @ enter)');
const _wasm_call_currentTaskID = startCurrentTask(0, false, 'incomingHandler020Handle');
incomingHandler020Handle(handle0, handle1);
endCurrentTask(0);
_debugLog('[iface="wasi:http/[email protected]", function="handle"][Instruction::Return]', {
funcName: 'handle',
paramCount: 0,
postReturn: false
});
}
Any ideas on how to solve this?
Hey @0UserName sorry it was hard to use! I think what you want here is a custom instantiation that you can more easily control.
We have some documentation on this but it's clearly not fantastic -- it's in the Jco Book:
https://bytecodealliance.github.io/jco/manual-wasm-instantiation-with-wasi-overrides.html#manual-instantiation-of-a-transpiled-component-with-no-overrides
Also, there are two interfaces to HTTP -- the fetch handler and also wasi:http -- you may find wasi:http easier to manipulate.
This code isn't released yet (it will be soon!), but an upcoming jco-std project will make this easier for projects like Hono. You can preview that code (which does something similar) here:
https://github.com/vados-cosmonic/jco/blob/feat%3Djco-std/packages/jco-std/src/wasi/0.2.x/http/types/request.ts
Viewing the Hono adapter might give you some ideas on ways to convert/adapt.