diff --git a/cmd/wasirun/main.go b/cmd/wasirun/main.go index 58c9a46..2ac38f6 100644 --- a/cmd/wasirun/main.go +++ b/cmd/wasirun/main.go @@ -229,16 +229,17 @@ func run(wasmFile string, args []string) error { var wasiHTTP *wasi_http.WasiHTTP = nil switch wasiHttp { case "auto": - importWasi = wasi_http.DetectWasiHttp(wasmModule) + importWasi, wasiHttp = wasi_http.DetectWasiHttp(wasmModule) case "v1": + case "2023_10_18": importWasi = true case "none": importWasi = false default: - return fmt.Errorf("invalid value for -http '%v', expected 'auto', 'v1' or 'none'", wasiHttp) + return fmt.Errorf("invalid value for -http '%v', expected 'auto', 'v1', '2023_10_18' or 'none'", wasiHttp) } if importWasi { - wasiHTTP = wasi_http.MakeWasiHTTP() + wasiHTTP = wasi_http.MakeWasiHTTP(wasiHttp) if err := wasiHTTP.Instantiate(ctx, runtime); err != nil { return err } diff --git a/imports/wasi_http/common/util.go b/imports/wasi_http/common/util.go index 6fa0df3..ea69647 100644 --- a/imports/wasi_http/common/util.go +++ b/imports/wasi_http/common/util.go @@ -26,22 +26,44 @@ func ReadString(mod api.Module, ptr, len uint32) (string, bool) { return string(data), true } -func WriteString(ctx context.Context, module api.Module, ptr uint32, str string) error { +func writeStringToMemory(ctx context.Context, module api.Module, str string) (uint32, error) { data := []byte(str) strPtr, err := Malloc(ctx, module, uint32(len(data))) if err != nil { - return err + return 0, err } if !module.Memory().WriteString(strPtr, str) { - return fmt.Errorf("failed to write string") + return 0, fmt.Errorf("failed to write string") } - data = []byte{} + return strPtr, nil +} + +func WriteOptionalString(ctx context.Context, module api.Module, ptr uint32, str string) error { + strPtr, err := writeStringToMemory(ctx, module, str) + if err != nil { + return err + } + data := []byte{} + data = binary.LittleEndian.AppendUint32(data, 1) // is some data = binary.LittleEndian.AppendUint32(data, strPtr) data = binary.LittleEndian.AppendUint32(data, uint32(len(str))) if !module.Memory().Write(ptr, data) { return fmt.Errorf("failed to write struct") } + return nil +} +func WriteString(ctx context.Context, module api.Module, ptr uint32, str string) error { + strPtr, err := writeStringToMemory(ctx, module, str) + if err != nil { + return err + } + data := []byte{} + data = binary.LittleEndian.AppendUint32(data, strPtr) + data = binary.LittleEndian.AppendUint32(data, uint32(len(str))) + if !module.Memory().Write(ptr, data) { + return fmt.Errorf("failed to write struct") + } return nil } diff --git a/imports/wasi_http/default_http/http.go b/imports/wasi_http/default_http/http.go index ca7af44..945aec4 100644 --- a/imports/wasi_http/default_http/http.go +++ b/imports/wasi_http/default_http/http.go @@ -2,18 +2,36 @@ package default_http import ( "context" + "fmt" "github.com/stealthrocket/wasi-go/imports/wasi_http/types" "github.com/tetratelabs/wazero" ) -const ModuleName = "default-outgoing-HTTP" +const ( + ModuleName = "default-outgoing-HTTP" + ModuleName_2023_10_18 = "wasi:http/outgoing-handler@0.2.0-rc-2023-10-18" +) -func Instantiate(ctx context.Context, r wazero.Runtime, req *types.Requests, res *types.Responses, f *types.FieldsCollection) error { +func Instantiate(ctx context.Context, r wazero.Runtime, req *types.Requests, res *types.Responses, f *types.FieldsCollection, version string) error { handler := &Handler{req, res, f} - _, err := r.NewHostModuleBuilder(ModuleName). - NewFunctionBuilder().WithFunc(requestFn).Export("request"). - NewFunctionBuilder().WithFunc(handler.handleFn).Export("handle"). - Instantiate(ctx) + var name string + switch version { + case "v1": + name = ModuleName + case "2023_10_18": + name = ModuleName_2023_10_18 + default: + return fmt.Errorf("unknown version: %s", version) + } + builder := r.NewHostModuleBuilder(name). + NewFunctionBuilder().WithFunc(requestFn).Export("request") + switch version { + case "v1": + builder.NewFunctionBuilder().WithFunc(handler.handleFn).Export("handle") + case "2023_10_18": + builder.NewFunctionBuilder().WithFunc(handler.handleFn_2023_10_18).Export("handle") + } + _, err := builder.Instantiate(ctx) return err } diff --git a/imports/wasi_http/default_http/request.go b/imports/wasi_http/default_http/request.go index 4c7f4d8..82fe5cf 100644 --- a/imports/wasi_http/default_http/request.go +++ b/imports/wasi_http/default_http/request.go @@ -2,6 +2,8 @@ package default_http import ( "context" + "encoding/binary" + "fmt" "log" "github.com/stealthrocket/wasi-go/imports/wasi_http/types" @@ -19,6 +21,18 @@ func requestFn(_ context.Context, mod api.Module, a, b, c, d, e, f, g, h, j, k, return 0 } +func doError(mod api.Module, ptr uint32, msg string) { + data := []byte{} + data = binary.LittleEndian.AppendUint32(data, 1) // IsError == 1 + data = binary.LittleEndian.AppendUint32(data, 3) // Always "unexpected error" for now + data = binary.LittleEndian.AppendUint32(data, 0) // TODO: pass string here. + data = binary.LittleEndian.AppendUint32(data, 0) // as above + + if !mod.Memory().Write(ptr, data) { + panic("Failed to write response!") + } +} + // Handle handles HTTP client calls. // The remaining parameters (b..h) are for the HTTP Options, currently unimplemented. func (handler *Handler) handleFn(_ context.Context, mod api.Module, request, b, c, d, e, f, g, h uint32) uint32 { @@ -34,3 +48,32 @@ func (handler *Handler) handleFn(_ context.Context, mod api.Module, request, b, } return handler.res.MakeResponse(r) } + +// Handle handles HTTP client calls. +// The remaining parameters (b..h) are for the HTTP Options, currently unimplemented. +func (handler *Handler) handleFn_2023_10_18(_ context.Context, mod api.Module, request, b, c, d, e, f, g, h, ptr uint32) { + req, ok := handler.req.GetRequest(request) + if !ok { + msg := fmt.Sprintf("Failed to get request: %v\n", request) + log.Printf(msg) + doError(mod, ptr, msg) + return + } + r, err := req.MakeRequest(handler.f) + if err != nil { + log.Println(err.Error()) + doError(mod, ptr, err.Error()) + return + } + res := handler.res.MakeResponse(r) + data := []byte{} + + data = binary.LittleEndian.AppendUint32(data, 0) // IsOk == 0 + data = binary.LittleEndian.AppendUint32(data, res) + data = binary.LittleEndian.AppendUint32(data, 0) // Used for errors + data = binary.LittleEndian.AppendUint32(data, 0) // Used for errors + + if !mod.Memory().Write(ptr, data) { + panic("Failed to write response!") + } +} diff --git a/imports/wasi_http/http.go b/imports/wasi_http/http.go index 68e3cd7..f852ab7 100644 --- a/imports/wasi_http/http.go +++ b/imports/wasi_http/http.go @@ -2,6 +2,7 @@ package wasi_http import ( "context" + "fmt" "net/http" "github.com/stealthrocket/wasi-go/imports/wasi_http/default_http" @@ -18,9 +19,10 @@ type WasiHTTP struct { r *types.Requests rs *types.Responses o *types.OutResponses + v string } -func MakeWasiHTTP() *WasiHTTP { +func MakeWasiHTTP(version string) *WasiHTTP { s := streams.MakeStreams() f := types.MakeFields() r := types.MakeRequests(s, f) @@ -33,39 +35,80 @@ func MakeWasiHTTP() *WasiHTTP { r: r, rs: rs, o: o, + v: version, } } func (w *WasiHTTP) Instantiate(ctx context.Context, rt wazero.Runtime) error { - if err := types.Instantiate(ctx, rt, w.s, w.r, w.rs, w.f, w.o); err != nil { + switch w.v { + case "v1": + return w.instantiateV1(ctx, rt) + case "2023_10_18": + return w.instantiate_2023_10_18(ctx, rt) + default: + return fmt.Errorf("unknown version: %v", w.v) + } +} + +func (w *WasiHTTP) instantiateV1(ctx context.Context, rt wazero.Runtime) error { + if err := types.Instantiate_v1(ctx, rt, w.s, w.r, w.rs, w.f, w.o); err != nil { return err } - if err := streams.Instantiate(ctx, rt, w.s); err != nil { + if err := streams.Instantiate_v1(ctx, rt, w.s); err != nil { return err } - if err := default_http.Instantiate(ctx, rt, w.r, w.rs, w.f); err != nil { + if err := default_http.Instantiate(ctx, rt, w.r, w.rs, w.f, w.v); err != nil { return err } return nil } -func DetectWasiHttp(module wazero.CompiledModule) bool { +func (w *WasiHTTP) instantiate_2023_10_18(ctx context.Context, rt wazero.Runtime) error { + if err := types.Instantiate_2023_10_18(ctx, rt, w.s, w.r, w.rs, w.f, w.o); err != nil { + return err + } + if err := streams.Instantiate_2023_10_18(ctx, rt, w.s); err != nil { + return err + } + if err := default_http.Instantiate(ctx, rt, w.r, w.rs, w.f, w.v); err != nil { + return err + } + return nil +} + +func DetectWasiHttp(module wazero.CompiledModule) (bool, string) { functions := module.ImportedFunctions() hasWasiHttp := false + version := "" for _, f := range functions { moduleName, name, ok := f.Import() - if !ok || moduleName != default_http.ModuleName { + if !ok || (moduleName != default_http.ModuleName && moduleName != default_http.ModuleName_2023_10_18) { continue } switch name { case "handle": hasWasiHttp = true + switch moduleName { + case default_http.ModuleName: + version = "v1" + case default_http.ModuleName_2023_10_18: + version = "2023_10_18" + default: + version = "unknown" + } } } - return hasWasiHttp + return hasWasiHttp, version } func (w *WasiHTTP) MakeHandler(ctx context.Context, m api.Module) http.Handler { + fnName := "" + switch w.v { + case "v1": + fnName = "HTTP#handle" + case "2023_10_18": + fnName = "exports_wasi_http_0_2_0_rc_2023_10_18_incoming_handler_handle" + } return server.WasmServer{ Ctx: ctx, Module: m, @@ -73,5 +116,6 @@ func (w *WasiHTTP) MakeHandler(ctx context.Context, m api.Module) http.Handler { Responses: w.rs, Fields: w.f, OutParams: w.o, + HandleFn: fnName, } } diff --git a/imports/wasi_http/http_test.go b/imports/wasi_http/http_test.go index b47cace..478237a 100644 --- a/imports/wasi_http/http_test.go +++ b/imports/wasi_http/http_test.go @@ -102,7 +102,7 @@ func TestHttpClient(t *testing.T) { } defer system.Close(ctx) - w := MakeWasiHTTP() + w := MakeWasiHTTP("v1") w.Instantiate(ctx, runtime) instance, err := runtime.Instantiate(ctx, bytecode) @@ -170,7 +170,7 @@ func TestServer(t *testing.T) { } defer system.Close(ctx) - w := MakeWasiHTTP() + w := MakeWasiHTTP("v1") w.Instantiate(ctx, runtime) instance, err := runtime.Instantiate(ctx, bytecode) diff --git a/imports/wasi_http/server/server.go b/imports/wasi_http/server/server.go index 90cfba2..c884d87 100644 --- a/imports/wasi_http/server/server.go +++ b/imports/wasi_http/server/server.go @@ -15,10 +15,11 @@ type WasmServer struct { Requests *types.Requests Responses *types.Responses OutParams *types.OutResponses + HandleFn string } func (w WasmServer) ServeHTTP(res http.ResponseWriter, req *http.Request) { - fn := w.Module.ExportedFunction("HTTP#handle") + fn := w.Module.ExportedFunction(w.HandleFn) if fn == nil { res.WriteHeader(500) res.Write([]byte("Handler not found")) diff --git a/imports/wasi_http/streams/streams.go b/imports/wasi_http/streams/streams.go index f256cd6..bf0a9f3 100644 --- a/imports/wasi_http/streams/streams.go +++ b/imports/wasi_http/streams/streams.go @@ -10,7 +10,10 @@ import ( "github.com/tetratelabs/wazero" ) -const ModuleName = "streams" +const ( + ModuleName = "streams" + ModuleName_2023_10_18 = "wasi:io/streams@0.2.0-rc-2023-10-18" +) type Stream struct { reader io.Reader @@ -30,11 +33,21 @@ func MakeStreams() *Streams { } } -func Instantiate(ctx context.Context, r wazero.Runtime, s *Streams) error { +func Instantiate_v1(ctx context.Context, r wazero.Runtime, s *Streams) error { _, err := r.NewHostModuleBuilder(ModuleName). NewFunctionBuilder().WithFunc(s.streamReadFn).Export("read"). NewFunctionBuilder().WithFunc(s.dropInputStreamFn).Export("drop-input-stream"). - NewFunctionBuilder().WithFunc(s.writeStreamFn).Export("write"). + NewFunctionBuilder().WithFunc(s.blockingWriteAndFlush).Export("write"). + Instantiate(ctx) + return err +} + +func Instantiate_2023_10_18(ctx context.Context, r wazero.Runtime, s *Streams) error { + _, err := r.NewHostModuleBuilder(ModuleName_2023_10_18). + NewFunctionBuilder().WithFunc(s.streamReadFn).Export("[method]input-stream.read"). + NewFunctionBuilder().WithFunc(s.dropInputStreamFn).Export("[resource-drop]input-stream"). + NewFunctionBuilder().WithFunc(s.blockingWriteAndFlush).Export("[method]output-stream.blocking-write-and-flush"). + //NewFunctionBuilder().WithFunc(s.writeStreamFn).Export("write"). Instantiate(ctx) return err } diff --git a/imports/wasi_http/streams/write.go b/imports/wasi_http/streams/write.go index 441659e..db4a80f 100644 --- a/imports/wasi_http/streams/write.go +++ b/imports/wasi_http/streams/write.go @@ -8,7 +8,7 @@ import ( "github.com/tetratelabs/wazero/api" ) -func (s *Streams) writeStreamFn(_ context.Context, mod api.Module, stream, ptr, l, result_ptr uint32) { +func (s *Streams) blockingWriteAndFlush(_ context.Context, mod api.Module, stream, ptr, l, result_ptr uint32) { data, ok := mod.Memory().Read(ptr, l) if !ok { log.Printf("Body read failed!\n") diff --git a/imports/wasi_http/types/http.go b/imports/wasi_http/types/http.go index c8dde1f..f18bc95 100644 --- a/imports/wasi_http/types/http.go +++ b/imports/wasi_http/types/http.go @@ -10,14 +10,17 @@ import ( "github.com/tetratelabs/wazero/api" ) -const ModuleName = "types" +const ( + ModuleName = "types" + ModuleName_2023_10_18 = "wasi:http/types@0.2.0-rc-2023-10-18" +) func logFn(ctx context.Context, mod api.Module, ptr, len uint32) { str, _ := common.ReadString(mod, ptr, len) fmt.Print(str) } -func Instantiate(ctx context.Context, rt wazero.Runtime, s *streams.Streams, r *Requests, rs *Responses, f *FieldsCollection, o *OutResponses) error { +func Instantiate_v1(ctx context.Context, rt wazero.Runtime, s *streams.Streams, r *Requests, rs *Responses, f *FieldsCollection, o *OutResponses) error { _, err := rt.NewHostModuleBuilder(ModuleName). NewFunctionBuilder().WithFunc(r.newOutgoingRequestFn).Export("new-outgoing-request"). NewFunctionBuilder().WithFunc(f.newFieldsFn).Export("new-fields"). @@ -44,3 +47,34 @@ func Instantiate(ctx context.Context, rt wazero.Runtime, s *streams.Streams, r * Instantiate(ctx) return err } + +func Instantiate_2023_10_18(ctx context.Context, rt wazero.Runtime, s *streams.Streams, r *Requests, rs *Responses, f *FieldsCollection, o *OutResponses) error { + _, err := rt.NewHostModuleBuilder(ModuleName_2023_10_18). + NewFunctionBuilder().WithFunc(r.newOutgoingRequestFn_2023_10_18).Export("[constructor]outgoing-request"). + NewFunctionBuilder().WithFunc(f.newFieldsFn).Export("[constructor]fields"). + NewFunctionBuilder().WithFunc(f.dropFieldsFn).Export("[resource-drop]fields"). + NewFunctionBuilder().WithFunc(f.fieldsEntriesFn).Export("[method]fields.entries"). + NewFunctionBuilder().WithFunc(r.dropOutgoingRequestFn).Export("[resource-drop]outgoing-request"). + NewFunctionBuilder().WithFunc(r.outgoingRequestWriteFn).Export("[method]outgoing-request.write"). + NewFunctionBuilder().WithFunc(rs.dropIncomingResponseFn).Export("[resource-drop]incoming-response"). + NewFunctionBuilder().WithFunc(rs.incomingResponseStatusFn).Export("[method]incoming-response.status"). + NewFunctionBuilder().WithFunc(rs.incomingResponseHeadersFn).Export("[method]incoming-response.headers"). + NewFunctionBuilder().WithFunc(rs.incomingResponseConsumeFn).Export("[method]incoming-response.consume"). + NewFunctionBuilder().WithFunc(rs.incomingResponseConsumeFn).Export("[method]incoming-body.stream"). + NewFunctionBuilder().WithFunc(futureResponseGetFn_2023_10_18).Export("[method]future-incoming-response.get"). + NewFunctionBuilder().WithFunc(r.incomingRequestMethodFn).Export("[method]incoming-request.method"). + NewFunctionBuilder().WithFunc(r.incomingRequestPathFn_2023_10_18).Export("[method]incoming-request.path-with-query"). + NewFunctionBuilder().WithFunc(r.incomingRequestAuthorityFn_2023_10_18).Export("[method]incoming-request.authority"). + NewFunctionBuilder().WithFunc(r.incomingRequestHeadersFn).Export("[method]incoming-request.headers"). + NewFunctionBuilder().WithFunc(incomingRequestConsumeFn).Export("[method]incoming-request.consume"). + NewFunctionBuilder().WithFunc(r.dropIncomingRequestFn).Export("[resource-drop]incoming-request"). + NewFunctionBuilder().WithFunc(o.setResponseOutparamFn_2023_10_18).Export("[static]response-outparam.set"). + NewFunctionBuilder().WithFunc(rs.newOutgoingResponseFn).Export("[constructor]outgoing-response"). + NewFunctionBuilder().WithFunc(rs.outgoingResponseWriteFn_2023_10_18).Export("[method]outgoing-response.write"). + NewFunctionBuilder().WithFunc(rs.outgoingBodyWriteFn).Export("[method]outgoing-body.write"). + NewFunctionBuilder().WithFunc(rs.outgoingBodyFinishFn).Export("[static]outgoing-body.finish"). + NewFunctionBuilder().WithFunc(dropOutgoingResponseFn).Export("[resource-drop]outgoing-response"). + NewFunctionBuilder().WithFunc(logFn).Export("log-it"). + Instantiate(ctx) + return err +} diff --git a/imports/wasi_http/types/request.go b/imports/wasi_http/types/request.go index cf14216..a47ddd1 100644 --- a/imports/wasi_http/types/request.go +++ b/imports/wasi_http/types/request.go @@ -19,7 +19,7 @@ import ( type Request struct { Method string Path string - Query string + Query string // not used in newer versions Scheme string Authority string Headers uint32 @@ -120,6 +120,16 @@ func (r *Requests) incomingRequestPathFn(ctx context.Context, mod api.Module, re } } +func (r *Requests) incomingRequestPathFn_2023_10_18(ctx context.Context, mod api.Module, request, ptr uint32) { + req, ok := r.GetRequest(request) + if !ok { + return + } + if err := common.WriteOptionalString(ctx, mod, ptr, req.Path); err != nil { + panic(err.Error()) + } +} + func (r *Requests) incomingRequestAuthorityFn(ctx context.Context, mod api.Module, request, ptr uint32) { req, ok := r.GetRequest(request) if !ok { @@ -130,6 +140,16 @@ func (r *Requests) incomingRequestAuthorityFn(ctx context.Context, mod api.Modul } } +func (r *Requests) incomingRequestAuthorityFn_2023_10_18(ctx context.Context, mod api.Module, request, ptr uint32) { + req, ok := r.GetRequest(request) + if !ok { + return + } + if err := common.WriteOptionalString(ctx, mod, ptr, req.Authority); err != nil { + panic(err.Error()) + } +} + func (r *Requests) incomingRequestMethodFn(_ context.Context, mod api.Module, request, ptr uint32) { req, ok := r.GetRequest(request) if !ok { @@ -234,6 +254,68 @@ func (r *Requests) newOutgoingRequestFn(_ context.Context, mod api.Module, return id } +func (r *Requests) newOutgoingRequestFn_2023_10_18(_ context.Context, mod api.Module, + method, method_ptr, method_len, + path_is_some, path_ptr, path_len, + scheme_is_some, scheme, scheme_ptr, scheme_len, + authority_is_some, authority_ptr, authority_len, header_handle uint32) uint32 { + + request, id := r.newRequest() + + switch method { + case 0: + request.Method = "GET" + case 1: + request.Method = "HEAD" + case 2: + request.Method = "POST" + case 3: + request.Method = "PUT" + case 4: + request.Method = "DELETE" + case 5: + request.Method = "CONNECT" + case 6: + request.Method = "OPTIONS" + case 7: + request.Method = "TRACE" + case 8: + request.Method = "PATCH" + default: + log.Fatalf("Unknown method: %d", method) + } + + path, ok := mod.Memory().Read(uint32(path_ptr), uint32(path_len)) + if !ok { + return 0 + } + request.Path = string(path) + + request.Scheme = "https" + if scheme_is_some == 1 { + if scheme == 0 { + request.Scheme = "http" + } + if scheme == 2 { + d, ok := mod.Memory().Read(uint32(scheme_ptr), uint32(scheme_len)) + if !ok { + return 0 + } + request.Scheme = string(d) + } + } + + authority, ok := mod.Memory().Read(uint32(authority_ptr), uint32(authority_len)) + if !ok { + return 0 + } + request.Authority = string(authority) + + request.Headers = header_handle + + return id +} + func (r *Requests) dropOutgoingRequestFn(_ context.Context, mod api.Module, handle uint32) { r.deleteRequest(handle) } diff --git a/imports/wasi_http/types/response.go b/imports/wasi_http/types/response.go index aa72b44..2a6af1d 100644 --- a/imports/wasi_http/types/response.go +++ b/imports/wasi_http/types/response.go @@ -96,6 +96,44 @@ func (r *Responses) outgoingResponseWriteFn(ctx context.Context, mod api.Module, } } +func (r *Responses) outgoingResponseWriteFn_2023_10_18(ctx context.Context, mod api.Module, res, ptr uint32) { + data := []byte{} + + data = binary.LittleEndian.AppendUint32(data, 0) + data = binary.LittleEndian.AppendUint32(data, res) + + if !mod.Memory().Write(ptr, data) { + panic("Failed to write data!") + } +} + +func (r *Responses) outgoingBodyWriteFn(ctx context.Context, mod api.Module, res, ptr uint32) { + // For now the body is just the response. Eventually we may need an actual body struct. + response, found := r.GetResponse(res) + data := []byte{} + if !found { + // Error + data = binary.LittleEndian.AppendUint32(data, 1) + data = binary.LittleEndian.AppendUint32(data, 0) + } else { + writer := &bytes.Buffer{} + stream := r.streams.NewOutputStream(writer) + + response.streamHandle = stream + response.Buffer = writer + // 0 == no error + data = binary.LittleEndian.AppendUint32(data, 0) + data = binary.LittleEndian.AppendUint32(data, stream) + } + if !mod.Memory().Write(ptr, data) { + panic("Failed to write data!") + } +} + +func (r *Responses) outgoingBodyFinishFn(ctx context.Context, mod api.Module, body, res, ptr uint32) { + // TODO: lock buffer here. +} + func (r *Responses) newOutgoingResponseFn(_ context.Context, status, headers uint32) uint32 { res := &Response{&http.Response{}, headers, 0, nil} res.StatusCode = int(status) @@ -117,10 +155,20 @@ func (o *OutResponses) setResponseOutparamFn(_ context.Context, mod api.Module, return 0 } +func (o *OutResponses) setResponseOutparamFn_2023_10_18(_ context.Context, mod api.Module, res, err, resOut, _msg_ptr, _msg_str uint32) { + if err == 1 { + // TODO: details here. + return + } + o.lock.Lock() + defer o.lock.Unlock() + o.responses[res] = resOut +} + func (r *Responses) incomingResponseStatusFn(_ context.Context, mod api.Module, handle uint32) int32 { response, found := r.GetResponse(handle) if !found { - log.Printf("Unknown handle: %v", handle) + log.Printf("Unknown response handle: %v", handle) return 0 } return int32(response.StatusCode) @@ -178,3 +226,17 @@ func futureResponseGetFn(_ context.Context, mod api.Module, handle, ptr uint32) data = le.AppendUint32(data, handle) mod.Memory().Write(ptr, data) } + +func futureResponseGetFn_2023_10_18(_ context.Context, mod api.Module, handle, ptr uint32) { + le := binary.LittleEndian + data := []byte{} + // 1 == is_some, 0 == none + data = le.AppendUint32(data, 1) + // 0 == ok, 1 == is_err, consistency ftw! + data = le.AppendUint32(data, 0) + // There are two Results here, for some reason + data = le.AppendUint32(data, 0) + // Copy the future into the actual + data = le.AppendUint32(data, handle) + mod.Memory().Write(ptr, data) +}