mirror of
https://github.com/nlepage/go-wasm-http-server.git
synced 2025-03-11 17:39:11 +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
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2019 Nicolas Lepage
|
Copyright 2021 Nicolas Lepage
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with 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"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
wasmhttp "github.com/nlepage/go-wasm-http-server"
|
wasmhttp "github.com/nlepage/go-wasm-http-server"
|
||||||
)
|
)
|
||||||
|
|
||||||
var no = 1
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
|
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)
|
params := make(map[string]string)
|
||||||
if err := json.NewDecoder(req.Body).Decode(¶ms); err != nil {
|
if err := json.NewDecoder(req.Body).Decode(¶ms); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.NewEncoder(res).Encode(map[string]string{
|
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 {
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
no++
|
|
||||||
})
|
})
|
||||||
|
|
||||||
wasmhttp.Serve(nil)
|
wasmhttp.ServeOnce(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 {}
|
|
||||||
}
|
}
|
||||||
|
BIN
docs/api.wasm
BIN
docs/api.wasm
Binary file not shown.
@ -2,8 +2,9 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>go-wasm-http-server demo</title>
|
<title>go-wasm-http-server demo</title>
|
||||||
<script src="https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@latest/index.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
|
navigator.serviceWorker.register('sw.js')
|
||||||
|
|
||||||
async function hello() {
|
async function hello() {
|
||||||
res = await fetch('api/hello', {
|
res = await fetch('api/hello', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -20,8 +21,5 @@
|
|||||||
<body>
|
<body>
|
||||||
<label for="name">Name : </label><input id="name" value="World">
|
<label for="name">Name : </label><input id="name" value="World">
|
||||||
<button onclick="hello()">Hello</button>
|
<button onclick="hello()">Hello</button>
|
||||||
<script>
|
|
||||||
wasmhttp.register('api.wasm', { base: 'api' })
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1 +1,3 @@
|
|||||||
importScripts('https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@latest/sw.js')
|
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
|
package wasmhttp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -12,35 +13,34 @@ import (
|
|||||||
|
|
||||||
// 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.
|
||||||
func Serve(handler http.Handler) func() {
|
func Serve(handler http.Handler) func() {
|
||||||
h := handler
|
var h = handler
|
||||||
if h == nil {
|
if h == nil {
|
||||||
h = http.DefaultServeMux
|
h = http.DefaultServeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
path := os.Getenv("WASMHTTP_PATH")
|
var path = os.Getenv("WASMHTTP_PATH")
|
||||||
if !strings.HasSuffix(path, "/") {
|
if !strings.HasSuffix(path, "/") {
|
||||||
path = path + "/"
|
path = path + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
if path != "" { // FIXME always true since / suffix is added to 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, "/") {
|
for strings.HasSuffix(prefix, "/") {
|
||||||
prefix = strings.TrimSuffix(prefix, "/")
|
prefix = strings.TrimSuffix(prefix, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
var mux = http.NewServeMux()
|
||||||
mux.Handle(path, http.StripPrefix(prefix, h))
|
mux.Handle(path, http.StripPrefix(prefix, h))
|
||||||
h = mux
|
h = mux
|
||||||
}
|
}
|
||||||
|
|
||||||
cb := js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
|
var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
|
||||||
jsReq := whutil.Request{args[0]}
|
var jsReq = whutil.Request{args[0]}
|
||||||
|
|
||||||
var resPromise = whutil.NewPromise(func(resolve whutil.PromiseResolve, reject whutil.PromiseReject) {
|
var resPromise = whutil.NewPromise(func(resolve whutil.PromiseResolve, reject whutil.PromiseReject) {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
r := recover()
|
if r := recover(); r != nil {
|
||||||
if r != nil {
|
|
||||||
if err, ok := r.(error); ok {
|
if err, ok := r.(error); ok {
|
||||||
reject(fmt.Sprintf("wasmhttp: panic: %+v\n", err))
|
reject(fmt.Sprintf("wasmhttp: panic: %+v\n", err))
|
||||||
} else {
|
} else {
|
||||||
@ -49,12 +49,12 @@ func Serve(handler http.Handler) func() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
req, err := jsReq.HTTPRequest()
|
var req, err = jsReq.HTTPRequest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := whutil.NewResponseWriter()
|
var res = whutil.NewResponseWriter()
|
||||||
|
|
||||||
h.ServeHTTP(res, req)
|
h.ServeHTTP(res, req)
|
||||||
|
|
||||||
@ -69,3 +69,65 @@ func Serve(handler http.Handler) func() {
|
|||||||
|
|
||||||
return cb.Release
|
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))
|
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