diff --git a/docs/api.wasm b/docs/api.wasm index 880a2a1..93decd0 100755 Binary files a/docs/api.wasm and b/docs/api.wasm differ diff --git a/example_json_test.go b/example_json_test.go index c7c1f40..7e7d5f9 100644 --- a/example_json_test.go +++ b/example_json_test.go @@ -8,7 +8,7 @@ import ( wasmhttp "github.com/nlepage/go-wasm-http-server" ) -// Demostrates a simple hello JSON service. +// Demonstrates a simple hello JSON service. func Example_json() { http.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) { params := make(map[string]string) diff --git a/internal/whutil/promise.go b/internal/whutil/promise.go index 8fdb9e5..e3c0f7a 100644 --- a/internal/whutil/promise.go +++ b/internal/whutil/promise.go @@ -5,51 +5,34 @@ import ( ) // Promise is JS Promise -type Promise js.Value +type Promise struct { + js.Value +} + +type PromiseResolve func(...interface{}) js.Value + +type PromiseReject func(...interface{}) js.Value // NewPromise creates a new JS Promise -func NewPromise(cb func(resolve, reject func(interface{}))) Promise { +func NewPromise(cb func(resolve PromiseResolve, reject PromiseReject)) Promise { var cbFunc js.Func - cbFunc = js.FuncOf(func(_ js.Value, args []js.Value) interface{} { defer cbFunc.Release() - - cb( - func(v interface{}) { - args[0].Invoke(v) - }, - func(v interface{}) { - args[1].Invoke(v) - }, - ) - + cb(args[0].Invoke, args[1].Invoke) return js.Undefined() }) - - return Promise(js.Global().Get("Promise").New(cbFunc)) + return Promise{js.Global().Get("Promise").New(cbFunc)} } // Await waits for the Promise to be resolved and returns the value func (p Promise) Await() js.Value { ch := make(chan js.Value) - p.Then(func(v js.Value) { - ch <- v - }) - return <-ch -} - -// Then calls cb with the value when the Promise is resolved -func (p Promise) Then(cb func(js.Value)) { var then js.Func then = js.FuncOf(func(_ js.Value, args []js.Value) interface{} { defer then.Release() - cb(args[0]) + ch <- args[0] return nil }) - js.Value(p).Call("then", then) -} - -// Value returns the Promise as a js.Value -func (p Promise) Value() js.Value { - return js.Value(p) + p.Call("then", then) + return <-ch } diff --git a/internal/whutil/request.go b/internal/whutil/request.go index 82eda77..177c68c 100644 --- a/internal/whutil/request.go +++ b/internal/whutil/request.go @@ -7,26 +7,26 @@ import ( ) // Request is a JS Request -type Request js.Value +type Request struct { + js.Value +} -// HTTPRequest builds and returns this equivalent http.Request -func (r *Request) HTTPRequest() (*http.Request, error) { - rValue := js.Value(*r) - - jsBody := js.Global().Get("Uint8Array").New(Promise(rValue.Call("arrayBuffer")).Await()) +// HTTPRequest builds and returns the equivalent http.Request +func (r Request) HTTPRequest() (*http.Request, error) { + jsBody := js.Global().Get("Uint8Array").New(Promise{r.Call("arrayBuffer")}.Await()) body := make([]byte, jsBody.Get("length").Int()) js.CopyBytesToGo(body, jsBody) req, err := http.NewRequest( - rValue.Get("method").String(), - rValue.Get("url").String(), + r.Get("method").String(), + r.Get("url").String(), bytes.NewBuffer(body), ) if err != nil { return nil, err } - headersIt := rValue.Get("headers").Call("entries") + headersIt := r.Get("headers").Call("entries") for { v := headersIt.Call("next") if v.Get("done").Bool() { diff --git a/internal/whutil/response_writer.go b/internal/whutil/response_writer.go index 36ba5ac..848277a 100644 --- a/internal/whutil/response_writer.go +++ b/internal/whutil/response_writer.go @@ -14,33 +14,35 @@ type ResponseWriter struct { } // NewResponseWriter creates a new ResponseWriter -func NewResponseWriter() *ResponseWriter { - return &ResponseWriter{ +func NewResponseWriter() ResponseWriter { + return ResponseWriter{ header: http.Header{}, buf: bytes.NewBuffer(nil), statusCode: 0, } } -var _ http.ResponseWriter = (*ResponseWriter)(nil) +var _ http.ResponseWriter = ResponseWriter{} // Header implements http.ResponseWriter.Header -func (rw *ResponseWriter) Header() http.Header { +func (rw ResponseWriter) Header() http.Header { return rw.header } // Write implements http.ResponseWriter.Write -func (rw *ResponseWriter) Write(p []byte) (int, error) { +func (rw ResponseWriter) Write(p []byte) (int, error) { return rw.buf.Write(p) } // WriteHeader implements http.ResponseWriter.WriteHeader -func (rw *ResponseWriter) WriteHeader(statusCode int) { +func (rw ResponseWriter) WriteHeader(statusCode int) { rw.statusCode = statusCode } -// JSResponse builds and returns the equivalent JS Response -func (rw *ResponseWriter) JSResponse() js.Value { +var _ js.Wrapper = ResponseWriter{} + +// JSValue builds and returns the equivalent JS Response (implementing js.Wrapper) +func (rw ResponseWriter) JSValue() js.Value { init := js.Global().Get("Object").New() if rw.statusCode != 0 { diff --git a/serve.go b/serve.go index f768b51..96f157c 100644 --- a/serve.go +++ b/serve.go @@ -34,42 +34,35 @@ func Serve(handler http.Handler) func() { } cb := js.FuncOf(func(_ js.Value, args []js.Value) interface{} { - jsReq := whutil.Request(args[0]) + jsReq := whutil.Request{args[0]} - var resolveRes func(interface{}) - var res = whutil.NewPromise(func(resolve, _ func(interface{})) { - resolveRes = resolve + var res = whutil.NewPromise(func(resolve whutil.PromiseResolve, reject whutil.PromiseReject) { + go func() { + defer func() { + r := recover() + if 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)) + } + } + }() + + req, err := jsReq.HTTPRequest() + if err != nil { + panic(err) + } + + res := whutil.NewResponseWriter() + + h.ServeHTTP(res, req) + + resolve(res) + }() }) - go func() { - defer func() { - r := recover() - if r != nil { - if err, ok := r.(error); ok { - fmt.Printf("wasmhttp: panic: %+v\n", err) - } else { - fmt.Printf("wasmhttp: panic: %v\n", r) - } - - res := whutil.NewResponseWriter() - res.WriteHeader(500) - resolveRes(res.JSResponse()) - } - }() - - req, err := jsReq.HTTPRequest() - if err != nil { - panic(err) - } - - res := whutil.NewResponseWriter() - - h.ServeHTTP(res, req) - - resolveRes(res.JSResponse()) - }() - - return res.Value() + return res }) js.Global().Get("wasmhttp").Call("registerHandler", os.Getenv("WASMHTTP_HANDLER_ID"), cb)