diff --git a/docs/hello-sse/api.go b/docs/hello-sse/api.go
new file mode 100644
index 0000000..6e94306
--- /dev/null
+++ b/docs/hello-sse/api.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "net/http"
+ "time"
+
+ "github.com/tmaxmax/go-sse"
+
+ wasmhttp "github.com/nlepage/go-wasm-http-server"
+)
+
+func main() {
+ s := &sse.Server{}
+ t, _ := sse.NewType("ping")
+
+ go func() {
+ m := &sse.Message{
+ Type: t,
+ }
+ m.AppendData("Hello world")
+
+ for range time.Tick(time.Second) {
+ _ = s.Publish(m)
+ }
+ }()
+
+ http.Handle("/events", s)
+
+ if _, err := wasmhttp.Serve(nil); err != nil {
+ panic(err)
+ }
+
+ select {}
+}
diff --git a/docs/hello-sse/api.wasm b/docs/hello-sse/api.wasm
new file mode 100755
index 0000000..dbd4ba5
Binary files /dev/null and b/docs/hello-sse/api.wasm differ
diff --git a/docs/hello-sse/index.html b/docs/hello-sse/index.html
new file mode 100644
index 0000000..c81fb1a
--- /dev/null
+++ b/docs/hello-sse/index.html
@@ -0,0 +1,32 @@
+
+
+
+ go-wasm-http-server hello demo
+
+
+
+
diff --git a/docs/hello-sse/sw.js b/docs/hello-sse/sw.js
new file mode 100644
index 0000000..df8ff57
--- /dev/null
+++ b/docs/hello-sse/sw.js
@@ -0,0 +1,12 @@
+importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.23.1/misc/wasm/wasm_exec.js')
+importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
+
+addEventListener('install', (event) => {
+ event.waitUntil(skipWaiting())
+})
+
+addEventListener('activate', event => {
+ event.waitUntil(clients.claim())
+})
+
+registerWasmHTTPListener('api.wasm', { base: 'api' })
diff --git a/docs/hello-state/api.wasm b/docs/hello-state/api.wasm
index 7863ef1..e1cbdc5 100755
Binary files a/docs/hello-state/api.wasm and b/docs/hello-state/api.wasm differ
diff --git a/docs/hello-state/sw.js b/docs/hello-state/sw.js
index 696e874..3371bbc 100644
--- a/docs/hello-state/sw.js
+++ b/docs/hello-state/sw.js
@@ -1,4 +1,4 @@
-importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js')
+importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.23.1/misc/wasm/wasm_exec.js')
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
addEventListener('install', (event) => {
diff --git a/docs/hello/api.wasm b/docs/hello/api.wasm
index 2b20a58..d21eaf1 100755
Binary files a/docs/hello/api.wasm and b/docs/hello/api.wasm differ
diff --git a/docs/hello/sw.js b/docs/hello/sw.js
index 026f6fe..df8ff57 100644
--- a/docs/hello/sw.js
+++ b/docs/hello/sw.js
@@ -1,4 +1,4 @@
-importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js')
+importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.23.1/misc/wasm/wasm_exec.js')
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
addEventListener('install', (event) => {
diff --git a/example_json_test.go b/example_json_test.go
index 7e7d5f9..15b9149 100644
--- a/example_json_test.go
+++ b/example_json_test.go
@@ -23,7 +23,11 @@ func Example_json() {
}
})
- defer wasmhttp.Serve(nil)()
+ release, err := wasmhttp.Serve(nil)
+ if err != nil {
+ panic(err)
+ }
+ defer release()
// Wait for webpage event or use empty select{}
}
diff --git a/go.mod b/go.mod
index 27a18c5..4309103 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,9 @@
module github.com/nlepage/go-wasm-http-server
-go 1.13
+go 1.18
-require github.com/nlepage/go-js-promise v1.0.0
+require (
+ github.com/hack-pad/safejs v0.1.1
+ github.com/nlepage/go-js-promise v1.0.0
+ github.com/tmaxmax/go-sse v0.8.0
+)
diff --git a/go.sum b/go.sum
index 291bfdb..b491b36 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,6 @@
+github.com/hack-pad/safejs v0.1.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
+github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
github.com/nlepage/go-js-promise v1.0.0 h1:K7OmJ3+0BgWJ2LfXchg2sI6RDr7AW/KWR8182epFwGQ=
github.com/nlepage/go-js-promise v1.0.0/go.mod h1:bdOP0wObXu34euibyK39K1hoBCtlgTKXGc56AGflaRo=
+github.com/tmaxmax/go-sse v0.8.0 h1:pPpTgyyi1r7vG2o6icebnpGEh3ebcnBXqDWkb7aTofs=
+github.com/tmaxmax/go-sse v0.8.0/go.mod h1:HLoxqxdH+7oSUItjtnpxjzJedfr/+Rrm/dNWBcTxJFM=
diff --git a/internal/jstype/types.go b/internal/jstype/types.go
new file mode 100644
index 0000000..5077176
--- /dev/null
+++ b/internal/jstype/types.go
@@ -0,0 +1,13 @@
+package jstype
+
+import (
+ "syscall/js"
+
+ "github.com/nlepage/go-wasm-http-server/internal/safejs"
+)
+
+var (
+ ReadableStream = safejs.Safe(js.Global().Get("ReadableStream"))
+ Response = safejs.Safe(js.Global().Get("Response"))
+ Uint8Array = safejs.Safe(js.Global().Get("Uint8Array"))
+)
diff --git a/internal/readablestream/readable_stream.go b/internal/readablestream/readable_stream.go
new file mode 100644
index 0000000..6b84fc5
--- /dev/null
+++ b/internal/readablestream/readable_stream.go
@@ -0,0 +1,87 @@
+package readablestream
+
+import (
+ "context"
+ "io"
+
+ "github.com/nlepage/go-wasm-http-server/internal/jstype"
+ "github.com/nlepage/go-wasm-http-server/internal/safejs"
+)
+
+type Writer struct {
+ Value safejs.Value
+ controller safejs.Value
+ ctx context.Context
+}
+
+var _ io.WriteCloser = (*Writer)(nil)
+
+func NewWriter() (*Writer, error) {
+ var start safejs.Func
+ var controller safejs.Value
+
+ start, err := safejs.FuncOf(func(_ safejs.Value, args []safejs.Value) any {
+ defer start.Release()
+ controller = args[0]
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ var cancel safejs.Func
+ ctx, cancelCtx := context.WithCancel(context.Background())
+
+ cancel, err = safejs.FuncOf(func(_ safejs.Value, _ []safejs.Value) any {
+ defer cancel.Release()
+ cancelCtx()
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ source, err := safejs.ValueOf(map[string]any{
+ "start": safejs.Unsafe(start.Value()),
+ "cancel": safejs.Unsafe(cancel.Value()),
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ value, err := jstype.ReadableStream.New(source)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Writer{
+ Value: value,
+ controller: controller,
+ ctx: ctx,
+ }, nil
+}
+
+func (rs *Writer) Write(b []byte) (int, error) {
+ chunk, err := jstype.Uint8Array.New(len(b)) // FIXME reuse same Uint8Array?
+ if err != nil {
+ return 0, err
+ }
+
+ n, err := safejs.CopyBytesToJS(chunk, b)
+ if err != nil {
+ return 0, err
+ }
+
+ _, err = rs.controller.Call("enqueue", chunk)
+
+ return n, err
+}
+
+func (rs *Writer) Close() error {
+ rs.controller.Call("close")
+ return nil
+}
+
+func (rs *Writer) Context() context.Context {
+ return rs.ctx
+}
diff --git a/internal/safejs/bytes.go b/internal/safejs/bytes.go
new file mode 100644
index 0000000..f6087d5
--- /dev/null
+++ b/internal/safejs/bytes.go
@@ -0,0 +1,11 @@
+package safejs
+
+import "github.com/hack-pad/safejs"
+
+func CopyBytesToGo(dst []byte, src Value) (int, error) {
+ return safejs.CopyBytesToGo(dst, safejs.Value(src))
+}
+
+func CopyBytesToJS(dst Value, src []byte) (int, error) {
+ return safejs.CopyBytesToJS(safejs.Value(dst), src)
+}
diff --git a/internal/safejs/func.go b/internal/safejs/func.go
new file mode 100644
index 0000000..dc0b141
--- /dev/null
+++ b/internal/safejs/func.go
@@ -0,0 +1,26 @@
+package safejs
+
+import (
+ "github.com/hack-pad/safejs"
+)
+
+type Func safejs.Func
+
+func FuncOf(fn func(this Value, args []Value) any) (Func, error) {
+ r, err := safejs.FuncOf(func(this safejs.Value, args []safejs.Value) any {
+ args2 := make([]Value, len(args))
+ for i, v := range args {
+ args2[i] = Value(v)
+ }
+ return fn(Value(this), []Value(args2))
+ })
+ return Func(r), err
+}
+
+func (f Func) Release() {
+ safejs.Func(f).Release()
+}
+
+func (f Func) Value() Value {
+ return Value(safejs.Func(f).Value())
+}
diff --git a/internal/safejs/value.go b/internal/safejs/value.go
new file mode 100644
index 0000000..26fd389
--- /dev/null
+++ b/internal/safejs/value.go
@@ -0,0 +1,103 @@
+package safejs
+
+import (
+ "syscall/js"
+
+ "github.com/hack-pad/safejs"
+)
+
+type Value safejs.Value
+
+func Safe(v js.Value) Value {
+ return Value(safejs.Safe(v))
+}
+
+func Unsafe(v Value) js.Value {
+ return safejs.Unsafe(safejs.Value(v))
+}
+
+func ValueOf(value any) (Value, error) {
+ v, err := safejs.ValueOf(value)
+ return Value(v), err
+}
+
+func (v Value) Call(m string, args ...any) (Value, error) {
+ args = toJSValue(args).([]any)
+ r, err := safejs.Value(v).Call(m, args...)
+ return Value(r), err
+}
+
+func (v Value) Get(p string) (Value, error) {
+ r, err := safejs.Value(v).Get(p)
+ return Value(r), err
+}
+
+func (v Value) GetBool(p string) (bool, error) {
+ bv, err := v.Get(p)
+ if err != nil {
+ return false, err
+ }
+
+ return safejs.Value(bv).Bool()
+}
+
+func (v Value) GetInt(p string) (int, error) {
+ iv, err := v.Get(p)
+ if err != nil {
+ return 0, err
+ }
+
+ return safejs.Value(iv).Int()
+}
+
+func (v Value) GetString(p string) (string, error) {
+ sv, err := v.Get(p)
+ if err != nil {
+ return "", err
+ }
+
+ return safejs.Value(sv).String()
+}
+
+func (v Value) Index(i int) (Value, error) {
+ r, err := safejs.Value(v).Index(i)
+ return Value(r), err
+}
+
+func (v Value) IndexString(i int) (string, error) {
+ sv, err := v.Index(i)
+ if err != nil {
+ return "", err
+ }
+
+ return safejs.Value(sv).String()
+}
+
+func (v Value) New(args ...any) (Value, error) {
+ args = toJSValue(args).([]any)
+ r, err := safejs.Value(v).New(args...)
+ return Value(r), err
+}
+
+func toJSValue(jsValue any) any {
+ switch value := jsValue.(type) {
+ case Value:
+ return safejs.Value(value)
+ case Func:
+ return safejs.Func(value)
+ case map[string]any:
+ newValue := make(map[string]any)
+ for mapKey, mapValue := range value {
+ newValue[mapKey] = toJSValue(mapValue)
+ }
+ return newValue
+ case []any:
+ newValue := make([]any, len(value))
+ for i, arg := range value {
+ newValue[i] = toJSValue(arg)
+ }
+ return newValue
+ default:
+ return jsValue
+ }
+}
diff --git a/package.go b/package.go
index 8c3c29a..aaf4c75 100644
--- a/package.go
+++ b/package.go
@@ -1,4 +1,2 @@
// Package wasmhttp (github.com/nlepage/go-wasm-http-server) allows to create a WebAssembly Go HTTP Server embedded in a ServiceWorker.
-//
-// It is a subset of the full solution, a full usage is available on the github repository: https://github.com/nlepage/go-wasm-http-server
package wasmhttp
diff --git a/request.go b/request.go
index b86a0df..b653bc3 100644
--- a/request.go
+++ b/request.go
@@ -7,29 +7,91 @@ import (
"syscall/js"
promise "github.com/nlepage/go-js-promise"
+
+ "github.com/nlepage/go-wasm-http-server/internal/jstype"
+ "github.com/nlepage/go-wasm-http-server/internal/safejs"
)
// Request builds and returns the equivalent http.Request
-func Request(r js.Value) *http.Request {
- jsBody := js.Global().Get("Uint8Array").New(promise.Await(r.Call("arrayBuffer")))
- body := make([]byte, jsBody.Get("length").Int())
- js.CopyBytesToGo(body, jsBody)
+func Request(ur js.Value) (*http.Request, error) {
+ r := safejs.Safe(ur)
- req := httptest.NewRequest(
- r.Get("method").String(),
- r.Get("url").String(),
- bytes.NewBuffer(body),
- )
-
- headersIt := r.Get("headers").Call("entries")
- for {
- e := headersIt.Call("next")
- if e.Get("done").Bool() {
- break
- }
- v := e.Get("value")
- req.Header.Set(v.Index(0).String(), v.Index(1).String())
+ ab, err := r.Call("arrayBuffer")
+ if err != nil {
+ return nil, err
}
- return req
+ u8a, err := jstype.Uint8Array.New(promise.Await(safejs.Unsafe(ab)))
+ if err != nil {
+ return nil, err
+ }
+
+ l, err := u8a.GetInt("length")
+ if err != nil {
+ return nil, err
+ }
+
+ b := make([]byte, l)
+
+ _, err = safejs.CopyBytesToGo(b, u8a)
+ if err != nil {
+ return nil, err
+ }
+
+ method, err := r.GetString("method")
+ if err != nil {
+ return nil, err
+ }
+
+ url, err := r.GetString("url")
+ if err != nil {
+ return nil, err
+ }
+
+ req := httptest.NewRequest(
+ method,
+ url,
+ bytes.NewReader(b),
+ )
+
+ headers, err := r.Get("headers")
+ if err != nil {
+ return nil, err
+ }
+
+ headersIt, err := headers.Call("entries")
+ for {
+ e, err := headersIt.Call("next")
+ if err != nil {
+ return nil, err
+ }
+
+ done, err := e.GetBool("done")
+ if err != nil {
+ return nil, err
+ }
+
+ if done {
+ break
+ }
+
+ v, err := e.Get("value")
+ if err != nil {
+ return nil, err
+ }
+
+ key, err := v.IndexString(0)
+ if err != nil {
+ return nil, err
+ }
+
+ value, err := v.IndexString(1)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set(key, value)
+ }
+
+ return req, nil
}
diff --git a/response.go b/response.go
new file mode 100644
index 0000000..70b538c
--- /dev/null
+++ b/response.go
@@ -0,0 +1,174 @@
+package wasmhttp
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "io"
+ "log/slog"
+ "net/http"
+ "syscall/js"
+
+ promise "github.com/nlepage/go-js-promise"
+
+ "github.com/nlepage/go-wasm-http-server/internal/jstype"
+ "github.com/nlepage/go-wasm-http-server/internal/readablestream"
+ "github.com/nlepage/go-wasm-http-server/internal/safejs"
+)
+
+type Response interface {
+ http.ResponseWriter
+ io.StringWriter
+ http.Flusher
+ io.Closer
+ Context() context.Context
+ WriteError(string)
+ JSValue() js.Value
+}
+
+type response struct {
+ header http.Header
+ wroteHeader bool
+
+ promise js.Value
+ resolve func(any)
+
+ rs *readablestream.Writer
+ body *bufio.Writer
+}
+
+func NewResponse() (Response, error) {
+ rs, err := readablestream.NewWriter()
+ if err != nil {
+ return nil, err
+ }
+
+ promise, resolve, _ := promise.New()
+
+ return &response{
+ promise: promise,
+ resolve: resolve,
+
+ rs: rs,
+ body: bufio.NewWriter(rs),
+ }, nil
+}
+
+var _ Response = (*response)(nil)
+
+// Header implements [http.ResponseWriter].
+func (r *response) Header() http.Header {
+ if r.header == nil {
+ r.header = make(http.Header)
+ }
+ return r.header
+}
+
+func (r *response) headerValue() map[string]any {
+ h := r.Header()
+ hh := make(map[string]any, len(h)+1)
+ for k := range h {
+ hh[k] = h.Get(k)
+ }
+ return hh
+}
+
+// Write implements http.ResponseWriter.
+func (r *response) Write(buf []byte) (int, error) {
+ r.writeHeader(buf, "")
+ return r.body.Write(buf)
+}
+
+// WriteHeader implements [http.ResponseWriter].
+func (r *response) WriteHeader(code int) {
+ if r.wroteHeader {
+ return
+ }
+
+ checkWriteHeaderCode(code)
+
+ init, err := safejs.ValueOf(map[string]any{
+ "code": code,
+ "headers": r.headerValue(),
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ res, err := jstype.Response.New(r.rs.Value, init)
+ if err != nil {
+ panic(err)
+ }
+
+ r.wroteHeader = true
+
+ r.resolve(safejs.Unsafe(res))
+}
+
+// WriteString implements [io.StringWriter].
+func (r *response) WriteString(str string) (int, error) {
+ r.writeHeader(nil, str)
+ return r.body.WriteString(str)
+}
+
+// Flush implements [http.Flusher]
+func (r *response) Flush() {
+ if !r.wroteHeader {
+ r.WriteHeader(200)
+ }
+ if err := r.body.Flush(); err != nil {
+ panic(err)
+ }
+}
+
+// Close implements [io.Closer]
+func (r *response) Close() error {
+ if err := r.body.Flush(); err != nil {
+ return err
+ }
+ return r.rs.Close()
+}
+
+func (r *response) Context() context.Context {
+ return r.rs.Context()
+}
+
+func (r *response) WriteError(str string) {
+ slog.Error(str)
+ if !r.wroteHeader {
+ r.WriteHeader(500)
+ _, _ = r.WriteString(str)
+ }
+}
+
+func (r *response) JSValue() js.Value {
+ return r.promise
+}
+
+func (r *response) writeHeader(b []byte, str string) {
+ if r.wroteHeader {
+ return
+ }
+
+ m := r.Header()
+
+ _, hasType := m["Content-Type"]
+ hasTE := m.Get("Transfer-Encoding") != ""
+ if !hasType && !hasTE {
+ if b == nil {
+ if len(str) > 512 {
+ str = str[:512]
+ }
+ b = []byte(str)
+ }
+ m.Set("Content-Type", http.DetectContentType(b))
+ }
+
+ r.WriteHeader(200)
+}
+
+func checkWriteHeaderCode(code int) {
+ if code < 100 || code > 999 {
+ panic(fmt.Sprintf("invalid WriteHeader code %v", code))
+ }
+}
diff --git a/response_recorder.go b/response_recorder.go
deleted file mode 100644
index 4f2fb40..0000000
--- a/response_recorder.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package wasmhttp
-
-import (
- "io/ioutil"
- "net/http/httptest"
- "syscall/js"
-)
-
-// ResponseRecorder uses httptest.ResponseRecorder to build a JS Response
-type ResponseRecorder struct {
- *httptest.ResponseRecorder
-}
-
-// NewResponseRecorder returns a new ResponseRecorder
-func NewResponseRecorder() ResponseRecorder {
- return ResponseRecorder{httptest.NewRecorder()}
-}
-
-// JSResponse builds and returns the equivalent JS Response
-func (rr ResponseRecorder) JSResponse() js.Value {
- var res = rr.Result()
-
- var body js.Value = js.Undefined()
- if res.ContentLength != 0 {
- var b, err = ioutil.ReadAll(res.Body)
- if err != nil {
- panic(err)
- }
- body = js.Global().Get("Uint8Array").New(len(b))
- js.CopyBytesToJS(body, b)
- }
-
- var init = make(map[string]interface{}, 2)
-
- if res.StatusCode != 0 {
- init["status"] = res.StatusCode
- }
-
- if len(res.Header) != 0 {
- var headers = make(map[string]interface{}, len(res.Header))
- for k := range res.Header {
- headers[k] = res.Header.Get(k)
- }
- init["headers"] = headers
- }
-
- return js.Global().Get("Response").New(body, init)
-}
diff --git a/serve.go b/serve.go
index 253588f..2c5488b 100644
--- a/serve.go
+++ b/serve.go
@@ -1,57 +1,92 @@
package wasmhttp
import (
+ "context"
"fmt"
"net/http"
"strings"
"syscall/js"
- promise "github.com/nlepage/go-js-promise"
+ "github.com/nlepage/go-wasm-http-server/internal/safejs"
+)
+
+var (
+ wasmhttp = safejs.Safe(js.Global().Get("wasmhttp"))
)
// Serve serves HTTP requests using handler or http.DefaultServeMux if handler is nil.
-func Serve(handler http.Handler) func() {
- var h = handler
+func Serve(handler http.Handler) (func(), error) {
+ h := handler
if h == nil {
h = http.DefaultServeMux
}
- var prefix = js.Global().Get("wasmhttp").Get("path").String()
+ prefix, err := wasmhttp.GetString("path")
+ if err != nil {
+ return nil, err
+ }
+
for strings.HasSuffix(prefix, "/") {
prefix = strings.TrimSuffix(prefix, "/")
}
if prefix != "" {
- var mux = http.NewServeMux()
+ mux := http.NewServeMux()
mux.Handle(prefix+"/", http.StripPrefix(prefix, h))
h = mux
}
- var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
- var resPromise, resolve, reject = promise.New()
+ handlerValue, err := safejs.FuncOf(func(_ safejs.Value, args []safejs.Value) interface{} {
+ res, err := NewResponse()
+ if err != nil {
+ panic(err)
+ }
go func() {
+ ctx, cancel := context.WithCancel(res.Context())
+
defer func() {
- if r := recover(); r != nil {
- if err, ok := r.(error); ok {
- reject(fmt.Sprintf("wasmhttp: panic: %+v\n", err))
- } else {
- reject(fmt.Sprintf("wasmhttp: panic: %v\n", r))
- }
+ cancel()
+ }()
+
+ defer func() {
+ if err := res.Close(); err != nil {
+ panic(err)
}
}()
- var res = NewResponseRecorder()
+ defer func() {
+ if r := recover(); r != nil {
+ var errStr string
+ if err, ok := r.(error); ok {
+ errStr = err.Error()
+ } else {
+ errStr = fmt.Sprintf("%s", r)
+ }
+ res.WriteError(errStr)
+ }
+ }()
- h.ServeHTTP(res, Request(args[0]))
+ req, err := Request(safejs.Unsafe(args[0]))
+ if err != nil {
+ res.WriteError(err.Error())
+ return
+ }
- resolve(res.JSResponse())
+ req = req.WithContext(ctx)
+
+ h.ServeHTTP(res, req)
}()
- return resPromise
+ return res.JSValue()
})
+ if err != nil {
+ return nil, err
+ }
- js.Global().Get("wasmhttp").Call("setHandler", cb)
+ if _, err = wasmhttp.Call("setHandler", handlerValue); err != nil {
+ return nil, err
+ }
- return cb.Release
+ return handlerValue.Release, nil
}