9 Commits

Author SHA1 Message Date
Nicolas Lepage
163b49702b ⬆️ go 1.18 compatibility 2022-07-28 00:08:56 +02:00
Nicolas Lepage
624ed00220 ♻️ Use github.com/nlepage/go-js-promise 2021-08-16 23:40:53 +02:00
Nicolas Lepage
1f549a4bf0 📝 Create funding.yml 2021-03-02 12:07:53 +01:00
Nicolas Lepage
73a09847ca ✏️ 2021-02-18 22:01:34 +01:00
Nicolas Lepage
0bf86b9d79 📝 2021-02-10 12:44:50 +01:00
Nicolas Lepage
167237a124 📝 2021-02-09 23:20:40 +01:00
Nicolas Lepage
f602159c47 📝 2021-02-09 23:18:59 +01:00
Nicolas Lepage
a06a85731f 📝 New Random password generator web server example 2021-02-08 13:54:49 +01:00
Nicolas Lepage
17e34981b0 📝 2021-02-06 18:15:36 +01:00
15 changed files with 47 additions and 83 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: [nlepage]

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"go.toolsEnvVars": {
"GOOS": "js",
"GOARCH": "wasm"
}
}

View File

@@ -11,7 +11,7 @@
</a> </a>
</p> </p>
> Build your Go HTTP Server to [WebAssembly](https://mdn.io/WebAssembly/) and embed it in a ServiceWorker! > Embed your Go HTTP handlers in a ServiceWorker (using [WebAssembly](https://mdn.io/WebAssembly/)) and emulate an HTTP server!
## Examples ## Examples
@@ -19,6 +19,20 @@
- [Hello example with state](https://nlepage.github.io/go-wasm-http-server/hello-state) ([sources](https://github.com/nlepage/go-wasm-http-server/tree/master/docs/hello-state)) - [Hello example with state](https://nlepage.github.io/go-wasm-http-server/hello-state) ([sources](https://github.com/nlepage/go-wasm-http-server/tree/master/docs/hello-state))
- [Hello example with state and keepalive](https://nlepage.github.io/go-wasm-http-server/hello-state-keepalive) ([sources](https://github.com/nlepage/go-wasm-http-server/tree/master/docs/hello-state-keepalive)) - [Hello example with state and keepalive](https://nlepage.github.io/go-wasm-http-server/hello-state-keepalive) ([sources](https://github.com/nlepage/go-wasm-http-server/tree/master/docs/hello-state-keepalive))
- [😺 Catption generator example](https://nlepage.github.io/catption/wasm) ([sources](https://github.com/nlepage/catption/tree/wasm)) - [😺 Catption generator example](https://nlepage.github.io/catption/wasm) ([sources](https://github.com/nlepage/catption/tree/wasm))
- [Random password generator web server](https://nlepage.github.io/random-password-please/) ([sources](https://github.com/nlepage/random-password-please) forked from [jbarham/random-password-please](https://github.com/jbarham/random-password-please))
## How?
Talk given at the Go devroom of FOSDEM 2021 explaining how `go-wasm-http-server` works:
[![Deploy a Go HTTP server in your browser Youtube link](https://raw.githubusercontent.com/nlepage/go-wasm-http-talk/main/youtube.png)](https://youtu.be/O2RB_8ircdE)
The slides are available [here](https://nlepage.github.io/go-wasm-http-talk/).
## Why?
`go-wasm-http-server` can help you put up a demonstration for a project without actually running a Go HTTP server.
## Requirements ## Requirements
@@ -82,7 +96,8 @@ Create a ServiceWorker file with the following code:
📄 `sw.js` 📄 `sw.js`
```js ```js
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.0.0/sw.js') importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js')
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
registerWasmHTTPListener('path/to/server.wasm') registerWasmHTTPListener('path/to/server.wasm')
``` ```
@@ -125,9 +140,9 @@ fetch('server/path/to/resource').then(res => {
## API ## API
### Go API For Go API see [pkg.go.dev/github.com/nlepage/go-wasm-http-server](https://pkg.go.dev/github.com/nlepage/go-wasm-http-server#section-documentation)
See [pkg.go.dev/github.com/nlepage/go-wasm-http-server](https://pkg.go.dev/github.com/nlepage/go-wasm-http-server#section-documentation) ### JavaScript API
### [`registerWasmHTTPListener(wasmUrl, options)`](https://github.com/nlepage/go-wasm-http-server/blob/v1.0.0/sw.js#L3) ### [`registerWasmHTTPListener(wasmUrl, options)`](https://github.com/nlepage/go-wasm-http-server/blob/v1.0.0/sw.js#L3)
@@ -150,16 +165,6 @@ An optional object containing:
- `base` (`string`): Base path of the server, relative to the ServiceWorker's scope. - `base` (`string`): Base path of the server, relative to the ServiceWorker's scope.
- `args` (`string[]`): Arguments for the WebAssembly module. - `args` (`string[]`): Arguments for the WebAssembly module.
## Why?
`go-wasm-http-server` can help you put up a demonstration for a project without actually running a Go HTTP server.
## How?
If you want to know how `go-wasm-http-server` works, I will be presenting the project at [the FOSDEM 2021 Go devroom](https://fosdem.org/2021/schedule/room/dgo/).
The slides are available [here](https://nlepage.github.io/go-wasm-http-talk/).
## Author ## Author
👤 **Nicolas Lepage** 👤 **Nicolas Lepage**
@@ -182,4 +187,4 @@ Copyright © 2021 [Nicolas Lepage](https://github.com/nlepage).<br />
This project is [Apache 2.0](https://github.com/nlepage/go-wasm-http-server/blob/master/LICENSE) licensed. This project is [Apache 2.0](https://github.com/nlepage/go-wasm-http-server/blob/master/LICENSE) licensed.
*** ***
_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_ _This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_

View File

@@ -1,4 +1,5 @@
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@078ff3547ebe2abfbee1fd5af9ca5ad64be480c0/sw.js') importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js')
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
addEventListener('install', event => { addEventListener('install', event => {
event.waitUntil(skipWaiting()) event.waitUntil(skipWaiting())

Binary file not shown.

View File

@@ -1,4 +1,5 @@
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.0.0/sw.js') importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js')
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
addEventListener('install', (event) => { addEventListener('install', (event) => {
event.waitUntil(skipWaiting()) event.waitUntil(skipWaiting())

Binary file not shown.

View File

@@ -1,4 +1,5 @@
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.0.0/sw.js') importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js')
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js')
addEventListener('install', (event) => { addEventListener('install', (event) => {
event.waitUntil(skipWaiting()) event.waitUntil(skipWaiting())

2
go.mod
View File

@@ -1,3 +1,5 @@
module github.com/nlepage/go-wasm-http-server module github.com/nlepage/go-wasm-http-server
go 1.13 go 1.13
require github.com/nlepage/go-js-promise v1.0.0

2
go.sum Normal file
View File

@@ -0,0 +1,2 @@
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=

View File

@@ -1,55 +0,0 @@
package wasmhttp
import (
"syscall/js"
)
// NewPromise creates a new JavaScript Promise
func NewPromise() (p js.Value, resolve func(interface{}), reject func(interface{})) {
var cbFunc js.Func
cbFunc = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
cbFunc.Release()
resolve = func(value interface{}) {
args[0].Invoke(value)
}
reject = func(value interface{}) {
args[1].Invoke(value)
}
return js.Undefined()
})
p = js.Global().Get("Promise").New(cbFunc)
return
}
// Await waits for the Promise to be resolved and returns the value
func Await(p js.Value) (js.Value, error) {
resCh := make(chan js.Value)
var then js.Func
then = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
resCh <- args[0]
return nil
})
defer then.Release()
errCh := make(chan error)
var catch js.Func
catch = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
errCh <- js.Error{args[0]}
return nil
})
defer catch.Release()
p.Call("then", then).Call("catch", catch)
select {
case res := <-resCh:
return res, nil
case err := <-errCh:
return js.Undefined(), err
}
}

View File

@@ -5,11 +5,13 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"syscall/js" "syscall/js"
promise "github.com/nlepage/go-js-promise"
) )
// Request builds and returns the equivalent http.Request // Request builds and returns the equivalent http.Request
func Request(r js.Value) *http.Request { func Request(r js.Value) *http.Request {
jsBody := js.Global().Get("Uint8Array").New(Await(r.Call("arrayBuffer"))) jsBody := js.Global().Get("Uint8Array").New(promise.Await(r.Call("arrayBuffer")))
body := make([]byte, jsBody.Get("length").Int()) body := make([]byte, jsBody.Get("length").Int())
js.CopyBytesToGo(body, jsBody) js.CopyBytesToGo(body, jsBody)

View File

@@ -6,7 +6,7 @@ import (
"syscall/js" "syscall/js"
) )
// ResponseRecorder extends httptest.ResponseRecorder and implements js.Wrapper // ResponseRecorder uses httptest.ResponseRecorder to build a JS Response
type ResponseRecorder struct { type ResponseRecorder struct {
*httptest.ResponseRecorder *httptest.ResponseRecorder
} }
@@ -16,10 +16,8 @@ func NewResponseRecorder() ResponseRecorder {
return ResponseRecorder{httptest.NewRecorder()} return ResponseRecorder{httptest.NewRecorder()}
} }
var _ js.Wrapper = ResponseRecorder{} // JSResponse builds and returns the equivalent JS Response
func (rr ResponseRecorder) JSResponse() js.Value {
// JSValue builds and returns the equivalent JS Response (implementing js.Wrapper)
func (rr ResponseRecorder) JSValue() js.Value {
var res = rr.Result() var res = rr.Result()
var body js.Value = js.Undefined() var body js.Value = js.Undefined()

View File

@@ -5,6 +5,8 @@ import (
"net/http" "net/http"
"strings" "strings"
"syscall/js" "syscall/js"
promise "github.com/nlepage/go-js-promise"
) )
// Serve serves HTTP requests using handler or http.DefaultServeMux if handler is nil. // Serve serves HTTP requests using handler or http.DefaultServeMux if handler is nil.
@@ -26,7 +28,7 @@ func Serve(handler http.Handler) func() {
} }
var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} { var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
var resPromise, resolve, reject = NewPromise() var resPromise, resolve, reject = promise.New()
go func() { go func() {
defer func() { defer func() {
@@ -43,7 +45,7 @@ func Serve(handler http.Handler) func() {
h.ServeHTTP(res, Request(args[0])) h.ServeHTTP(res, Request(args[0]))
resolve(res) resolve(res.JSResponse())
}() }()
return resPromise return resPromise

2
sw.js
View File

@@ -1,5 +1,3 @@
importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.15.7/misc/wasm/wasm_exec.js')
function registerWasmHTTPListener(wasm, { base, args = [] } = {}) { function registerWasmHTTPListener(wasm, { base, args = [] } = {}) {
let path = new URL(registration.scope).pathname let path = new URL(registration.scope).pathname
if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}` if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}`