mirror of
https://github.com/nlepage/go-wasm-http-server.git
synced 2025-03-10 17:29:10 +00:00
⚗️
This commit is contained in:
parent
3b1987e60b
commit
51d77eecb2
2
LICENSE
2
LICENSE
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 Nicolas Lepage
|
||||
Copyright 2021 Nicolas Lepage
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
20
docs/api.go
20
docs/api.go
@ -4,39 +4,23 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
wasmhttp "github.com/nlepage/go-wasm-http-server"
|
||||
)
|
||||
|
||||
var no = 1
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
|
||||
h, m, s := time.Now().Clock()
|
||||
fmt.Printf("hello at %02d:%02d:%02d\n", h, m, s)
|
||||
|
||||
params := make(map[string]string)
|
||||
if err := json.NewDecoder(req.Body).Decode(¶ms); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(res).Encode(map[string]string{
|
||||
"message": fmt.Sprintf("Hello %s! (%d)", params["name"], no),
|
||||
"message": fmt.Sprintf("Hello %s!", params["name"]),
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
no++
|
||||
})
|
||||
|
||||
wasmhttp.Serve(nil)
|
||||
|
||||
go func() {
|
||||
for range time.Tick(time.Second) {
|
||||
h, m, s := time.Now().Clock()
|
||||
fmt.Printf("tick at %02d:%02d:%02d\n", h, m, s)
|
||||
}
|
||||
}()
|
||||
|
||||
select {}
|
||||
wasmhttp.ServeOnce(nil)
|
||||
}
|
||||
|
BIN
docs/api.wasm
BIN
docs/api.wasm
Binary file not shown.
@ -2,8 +2,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>go-wasm-http-server demo</title>
|
||||
<script src="https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@latest/index.js"></script>
|
||||
<script>
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
|
||||
async function hello() {
|
||||
res = await fetch('api/hello', {
|
||||
method: 'POST',
|
||||
@ -20,8 +21,5 @@
|
||||
<body>
|
||||
<label for="name">Name : </label><input id="name" value="World">
|
||||
<button onclick="hello()">Hello</button>
|
||||
<script>
|
||||
wasmhttp.register('api.wasm', { base: 'api' })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1 +1,3 @@
|
||||
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@latest/sw.js')
|
||||
|
||||
registerWasmHTTPListener('api.wasm')
|
||||
|
82
serve.go
82
serve.go
@ -1,6 +1,7 @@
|
||||
package wasmhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -12,35 +13,34 @@ import (
|
||||
|
||||
// Serve serves HTTP requests using handler or http.DefaultServeMux if handler is nil.
|
||||
func Serve(handler http.Handler) func() {
|
||||
h := handler
|
||||
var h = handler
|
||||
if h == nil {
|
||||
h = http.DefaultServeMux
|
||||
}
|
||||
|
||||
path := os.Getenv("WASMHTTP_PATH")
|
||||
var path = os.Getenv("WASMHTTP_PATH")
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
path = path + "/"
|
||||
}
|
||||
|
||||
if path != "" { // FIXME always true since / suffix is added to path
|
||||
prefix := os.Getenv("WASMHTTP_PATH")
|
||||
var prefix = os.Getenv("WASMHTTP_PATH")
|
||||
for strings.HasSuffix(prefix, "/") {
|
||||
prefix = strings.TrimSuffix(prefix, "/")
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
var mux = http.NewServeMux()
|
||||
mux.Handle(path, http.StripPrefix(prefix, h))
|
||||
h = mux
|
||||
}
|
||||
|
||||
cb := js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
|
||||
jsReq := whutil.Request{args[0]}
|
||||
var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
|
||||
var jsReq = whutil.Request{args[0]}
|
||||
|
||||
var resPromise = whutil.NewPromise(func(resolve whutil.PromiseResolve, reject whutil.PromiseReject) {
|
||||
go func() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
if r := recover(); r != nil {
|
||||
if err, ok := r.(error); ok {
|
||||
reject(fmt.Sprintf("wasmhttp: panic: %+v\n", err))
|
||||
} else {
|
||||
@ -49,12 +49,12 @@ func Serve(handler http.Handler) func() {
|
||||
}
|
||||
}()
|
||||
|
||||
req, err := jsReq.HTTPRequest()
|
||||
var req, err = jsReq.HTTPRequest()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
res := whutil.NewResponseWriter()
|
||||
var res = whutil.NewResponseWriter()
|
||||
|
||||
h.ServeHTTP(res, req)
|
||||
|
||||
@ -69,3 +69,65 @@ func Serve(handler http.Handler) func() {
|
||||
|
||||
return cb.Release
|
||||
}
|
||||
|
||||
func ServeOnce(handler http.Handler) {
|
||||
var ctx, cancel = context.WithCancel(context.Background())
|
||||
|
||||
var h = handler
|
||||
if h == nil {
|
||||
h = http.DefaultServeMux
|
||||
}
|
||||
|
||||
var path = os.Getenv("WASMHTTP_PATH")
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
path = path + "/"
|
||||
}
|
||||
|
||||
if path != "" { // FIXME always true since / suffix is added to path
|
||||
var prefix = os.Getenv("WASMHTTP_PATH")
|
||||
for strings.HasSuffix(prefix, "/") {
|
||||
prefix = strings.TrimSuffix(prefix, "/")
|
||||
}
|
||||
|
||||
var mux = http.NewServeMux()
|
||||
mux.Handle(path, http.StripPrefix(prefix, h))
|
||||
h = mux
|
||||
}
|
||||
|
||||
var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
|
||||
var jsReq = whutil.Request{args[0]}
|
||||
|
||||
var resPromise = whutil.NewPromise(func(resolve whutil.PromiseResolve, reject whutil.PromiseReject) {
|
||||
go func() {
|
||||
defer cancel()
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var req, err = jsReq.HTTPRequest()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var res = whutil.NewResponseWriter()
|
||||
|
||||
h.ServeHTTP(res, req)
|
||||
|
||||
resolve(res)
|
||||
}()
|
||||
})
|
||||
|
||||
return resPromise
|
||||
})
|
||||
|
||||
js.Global().Get("wasmhttp").Call("registerHandler", os.Getenv("WASMHTTP_HANDLER_ID"), cb)
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
20
sw.js
20
sw.js
@ -76,3 +76,23 @@ addEventListener('fetch', e => {
|
||||
|
||||
e.respondWith(handler(e.request))
|
||||
})
|
||||
|
||||
function registerWasmHTTPListener(wasm, base, args) {
|
||||
let path = new URL(registration.scope).pathname
|
||||
if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}`
|
||||
|
||||
addEventListener('fetch', async e => {
|
||||
const { pathname } = new URL(e.request.url)
|
||||
if (!pathname.startsWith(path)) return
|
||||
|
||||
const handlerId = `${nextHandlerId++}`
|
||||
const handlerPromise = new Promise(resolve => handlerResolvers[handlerId] = resolve)
|
||||
|
||||
// FIXME await ? catch ?
|
||||
startWasm(wasm, { env: { WASMHTTP_HANDLER_ID: handlerId, WASMHTTP_PATH: path }, args })
|
||||
|
||||
const handler = await handlerPromise
|
||||
|
||||
e.respondWith(handler(e.request))
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user