This commit is contained in:
Nicolas Lepage
2019-11-27 07:22:07 +01:00
parent 40c75880da
commit 9c65a54a24
8 changed files with 25 additions and 6 deletions

View File

@@ -0,0 +1,3 @@
// Package whutil stands for WASM HTTP utilities.
// It contains internal utilities for github.com/nlepage/go-wasm-http-server.
package whutil

View File

@@ -0,0 +1,55 @@
package whutil
import (
"syscall/js"
)
// Promise is JS Promise
type Promise js.Value
// NewPromise creates a new JS Promise
func NewPromise(cb func(resolve, reject func(interface{}))) 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)
},
)
return js.Undefined()
})
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])
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)
}

View File

@@ -0,0 +1,39 @@
package whutil
import (
"bytes"
"net/http"
"syscall/js"
)
// Request is a JS Request
type Request 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())
body := make([]byte, jsBody.Get("length").Int())
js.CopyBytesToGo(body, jsBody)
req, err := http.NewRequest(
rValue.Get("method").String(),
rValue.Get("url").String(),
bytes.NewBuffer(body),
)
if err != nil {
return nil, err
}
headersIt := rValue.Get("headers").Call("entries")
for {
v := headersIt.Call("next")
if v.Get("done").Bool() {
break
}
req.Header.Set(v.Index(0).String(), v.Index(1).String())
}
return req, nil
}

View File

@@ -0,0 +1,58 @@
package whutil
import (
"bytes"
"net/http"
"syscall/js"
)
// ResponseWriter implements http.ResponseWriter
type ResponseWriter struct {
header http.Header
buf *bytes.Buffer
statusCode int
}
// NewResponseWriter creates a new ResponseWriter
func NewResponseWriter() *ResponseWriter {
return &ResponseWriter{
header: http.Header{},
buf: bytes.NewBuffer(nil),
statusCode: 0,
}
}
var _ http.ResponseWriter = (*ResponseWriter)(nil)
// Header implements http.ResponseWriter.Header
func (rw *ResponseWriter) Header() http.Header {
return rw.header
}
// Write implements http.ResponseWriter.Write
func (rw *ResponseWriter) Write(p []byte) (int, error) {
return rw.buf.Write(p)
}
// WriteHeader implements http.ResponseWriter.WriteHeader
func (rw *ResponseWriter) WriteHeader(statusCode int) {
rw.statusCode = statusCode
}
// JSResponse builds and returns the equivalent JS Response
func (rw *ResponseWriter) JSResponse() js.Value {
init := js.Global().Get("Object").New()
if rw.statusCode != 0 {
init.Set("status", rw.statusCode)
}
if len(rw.header) != 0 {
init.Set("headers", map[string][]string(rw.header))
}
jsBody := js.Global().Get("Uint8Array").New(rw.buf.Len())
js.CopyBytesToJS(jsBody, rw.buf.Bytes())
return js.Global().Get("Response").New(jsBody, init)
}