mirror of
https://github.com/nlepage/go-wasm-http-server.git
synced 2026-01-12 01:59:14 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
163b49702b | ||
|
|
624ed00220 | ||
|
|
1f549a4bf0 | ||
|
|
73a09847ca | ||
|
|
0bf86b9d79 | ||
|
|
167237a124 | ||
|
|
f602159c47 | ||
|
|
a06a85731f | ||
|
|
17e34981b0 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: [nlepage]
|
||||
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"go.toolsEnvVars": {
|
||||
"GOOS": "js",
|
||||
"GOARCH": "wasm"
|
||||
}
|
||||
}
|
||||
35
README.md
35
README.md
@@ -11,7 +11,7 @@
|
||||
</a>
|
||||
</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
|
||||
|
||||
@@ -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 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))
|
||||
- [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:
|
||||
|
||||
[](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
|
||||
|
||||
@@ -82,7 +96,8 @@ Create a ServiceWorker file with the following code:
|
||||
|
||||
📄 `sw.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')
|
||||
```
|
||||
@@ -125,9 +140,9 @@ fetch('server/path/to/resource').then(res => {
|
||||
|
||||
## 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)
|
||||
|
||||
@@ -150,16 +165,6 @@ An optional object containing:
|
||||
- `base` (`string`): Base path of the server, relative to the ServiceWorker's scope.
|
||||
- `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
|
||||
|
||||
👤 **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 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)_
|
||||
|
||||
@@ -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 => {
|
||||
event.waitUntil(skipWaiting())
|
||||
|
||||
Binary file not shown.
@@ -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) => {
|
||||
event.waitUntil(skipWaiting())
|
||||
|
||||
Binary file not shown.
@@ -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) => {
|
||||
event.waitUntil(skipWaiting())
|
||||
|
||||
2
go.mod
2
go.mod
@@ -1,3 +1,5 @@
|
||||
module github.com/nlepage/go-wasm-http-server
|
||||
|
||||
go 1.13
|
||||
|
||||
require github.com/nlepage/go-js-promise v1.0.0
|
||||
|
||||
2
go.sum
Normal file
2
go.sum
Normal 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=
|
||||
55
promise.go
55
promise.go
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,13 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"syscall/js"
|
||||
|
||||
promise "github.com/nlepage/go-js-promise"
|
||||
)
|
||||
|
||||
// Request builds and returns the equivalent 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())
|
||||
js.CopyBytesToGo(body, jsBody)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
// ResponseRecorder extends httptest.ResponseRecorder and implements js.Wrapper
|
||||
// ResponseRecorder uses httptest.ResponseRecorder to build a JS Response
|
||||
type ResponseRecorder struct {
|
||||
*httptest.ResponseRecorder
|
||||
}
|
||||
@@ -16,10 +16,8 @@ func NewResponseRecorder() ResponseRecorder {
|
||||
return ResponseRecorder{httptest.NewRecorder()}
|
||||
}
|
||||
|
||||
var _ js.Wrapper = ResponseRecorder{}
|
||||
|
||||
// JSValue builds and returns the equivalent JS Response (implementing js.Wrapper)
|
||||
func (rr ResponseRecorder) JSValue() js.Value {
|
||||
// JSResponse builds and returns the equivalent JS Response
|
||||
func (rr ResponseRecorder) JSResponse() js.Value {
|
||||
var res = rr.Result()
|
||||
|
||||
var body js.Value = js.Undefined()
|
||||
|
||||
6
serve.go
6
serve.go
@@ -5,6 +5,8 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"syscall/js"
|
||||
|
||||
promise "github.com/nlepage/go-js-promise"
|
||||
)
|
||||
|
||||
// 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 resPromise, resolve, reject = NewPromise()
|
||||
var resPromise, resolve, reject = promise.New()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
@@ -43,7 +45,7 @@ func Serve(handler http.Handler) func() {
|
||||
|
||||
h.ServeHTTP(res, Request(args[0]))
|
||||
|
||||
resolve(res)
|
||||
resolve(res.JSResponse())
|
||||
}()
|
||||
|
||||
return resPromise
|
||||
|
||||
2
sw.js
2
sw.js
@@ -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 = [] } = {}) {
|
||||
let path = new URL(registration.scope).pathname
|
||||
if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}`
|
||||
|
||||
Reference in New Issue
Block a user