-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Move index.html to separate file with Go 1.16 embedded files * Add test coverage support Overrides three file system operations for the purposes of reading and writing the coverage profile file. The contents are copied out of the JS runtime and written again to the real file. * Extract FS wrappers to 'overrideFS' function Also guard use of global TextDecoder if not supported. * Wrap each FS operation, switch from writeSync() to write(), and bind "fs" as "this"
- Loading branch information
1 parent
8753b3a
commit bba38b6
Showing
4 changed files
with
139 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package main | ||
|
||
import ( | ||
_ "embed" | ||
"html/template" | ||
"io/ioutil" | ||
"log" | ||
|
@@ -14,22 +15,27 @@ import ( | |
"time" | ||
) | ||
|
||
//go:embed index.html | ||
var indexHTML string | ||
|
||
type wasmServer struct { | ||
indexTmpl *template.Template | ||
wasmFile string | ||
wasmExecJS []byte | ||
args []string | ||
envMap map[string]string | ||
logger *log.Logger | ||
indexTmpl *template.Template | ||
wasmFile string | ||
wasmExecJS []byte | ||
args []string | ||
coverageFile string | ||
envMap map[string]string | ||
logger *log.Logger | ||
} | ||
|
||
func NewWASMServer(wasmFile string, args []string, l *log.Logger) (http.Handler, error) { | ||
func NewWASMServer(wasmFile string, args []string, coverageFile string, l *log.Logger) (http.Handler, error) { | ||
var err error | ||
srv := &wasmServer{ | ||
wasmFile: wasmFile, | ||
args: args, | ||
logger: l, | ||
envMap: make(map[string]string), | ||
wasmFile: wasmFile, | ||
args: args, | ||
coverageFile: coverageFile, | ||
logger: l, | ||
envMap: make(map[string]string), | ||
} | ||
|
||
for _, env := range os.Environ() { | ||
|
@@ -56,13 +62,15 @@ func (ws *wasmServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
case "/", "/index.html": | ||
w.Header().Set("Content-Type", "text/html; charset=UTF-8") | ||
data := struct { | ||
WASMFile string | ||
Args []string | ||
EnvMap map[string]string | ||
WASMFile string | ||
Args []string | ||
CoverageFile string | ||
EnvMap map[string]string | ||
}{ | ||
WASMFile: filepath.Base(ws.wasmFile), | ||
Args: ws.args, | ||
EnvMap: ws.envMap, | ||
WASMFile: filepath.Base(ws.wasmFile), | ||
Args: ws.args, | ||
CoverageFile: ws.coverageFile, | ||
EnvMap: ws.envMap, | ||
} | ||
err := ws.indexTmpl.Execute(w, data) | ||
if err != nil { | ||
|
@@ -89,60 +97,3 @@ func (ws *wasmServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
} | ||
} | ||
} | ||
|
||
const indexHTML = `<!doctype html> | ||
<!-- | ||
Copyright 2018 The Go Authors. All rights reserved. | ||
Use of this source code is governed by a BSD-style | ||
license that can be found in the LICENSE file. | ||
--> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Go wasm</title> | ||
</head> | ||
<body> | ||
<!-- | ||
Add the following polyfill for Microsoft Edge 17/18 support: | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/encoding.min.js"></script> | ||
(see https://caniuse.com/#feat=textencoder) | ||
--> | ||
<script src="wasm_exec.js"></script> | ||
<script> | ||
if (!WebAssembly.instantiateStreaming) { // polyfill | ||
WebAssembly.instantiateStreaming = async (resp, importObject) => { | ||
const source = await (await resp).arrayBuffer(); | ||
return await WebAssembly.instantiate(source, importObject); | ||
}; | ||
} | ||
let exitCode = 0; | ||
function goExit(code) { | ||
exitCode = code; | ||
} | ||
(async() => { | ||
const go = new Go(); | ||
go.argv = [{{range $i, $item := .Args}} {{if $i}}, {{end}} "{{$item}}" {{end}}]; | ||
// The notFirst variable sets itself to true after first iteration. This is to put commas in between. | ||
go.env = { {{ $notFirst := false }} | ||
{{range $key, $val := .EnvMap}} {{if $notFirst}}, {{end}} {{$key}}: "{{$val}}" {{ $notFirst = true }} | ||
{{end}} }; | ||
go.exit = goExit; | ||
let mod, inst; | ||
await WebAssembly.instantiateStreaming(fetch("{{.WASMFile}}"), go.importObject).then((result) => { | ||
mod = result.module; | ||
inst = result.instance; | ||
}).catch((err) => { | ||
console.error(err); | ||
}); | ||
await go.run(inst); | ||
document.getElementById("doneButton").disabled = false; | ||
})(); | ||
</script> | ||
<button id="doneButton" style="display: none;" disabled>Done</button> | ||
</body> | ||
</html>` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<!doctype html> | ||
<!-- | ||
Copyright 2018 The Go Authors. All rights reserved. | ||
Use of this source code is governed by a BSD-style | ||
license that can be found in the LICENSE file. | ||
--> | ||
<html> | ||
|
||
<head> | ||
<meta charset="utf-8"> | ||
<title>Go wasm</title> | ||
</head> | ||
|
||
<body> | ||
<!-- | ||
Add the following polyfill for Microsoft Edge 17/18 support: | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/encoding.min.js"></script> | ||
(see https://caniuse.com/#feat=textencoder) | ||
--> | ||
<script src="wasm_exec.js"></script> | ||
<script> | ||
if (!WebAssembly.instantiateStreaming) { // polyfill | ||
WebAssembly.instantiateStreaming = async (resp, importObject) => { | ||
const source = await (await resp).arrayBuffer(); | ||
return await WebAssembly.instantiate(source, importObject); | ||
}; | ||
} | ||
|
||
let exitCode = 0; | ||
function goExit(code) { | ||
exitCode = code; | ||
} | ||
function enosys() { | ||
const err = new Error("not implemented"); | ||
err.code = "ENOSYS"; | ||
return err; | ||
} | ||
let coverageProfileContents = ""; | ||
function overrideFS(fs) { | ||
// A typical runtime opens fd's in sequence above the standard descriptors (0-2). | ||
// Choose an arbitrarily high fd for the custom coverage file to avoid conflict with the actual runtime fd's. | ||
const coverFileDescriptor = Number.MAX_SAFE_INTEGER; | ||
const coverFilePath = {{.CoverageFile}}; | ||
// Wraps the default operations with bind() to ensure internal usage of 'this' continues to work. | ||
const defaultOpen = fs.open.bind(fs); | ||
fs.open = (path, flags, mode, callback) => { | ||
if (path === coverFilePath) { | ||
callback(null, coverFileDescriptor); | ||
return; | ||
} | ||
defaultOpen(path, flags, mode, callback); | ||
}; | ||
const defaultClose = fs.close.bind(fs); | ||
fs.close = (fd, callback) => { | ||
if (fd === coverFileDescriptor) { | ||
callback(null); | ||
return; | ||
} | ||
defaultClose(fd, callback); | ||
}; | ||
if (!globalThis.TextDecoder) { | ||
throw new Error("globalThis.TextDecoder is not available, polyfill required"); | ||
} | ||
const decoder = new TextDecoder("utf-8"); | ||
const defaultWrite = fs.write.bind(fs); | ||
fs.write = (fd, buf, offset, length, position, callback) => { | ||
if (fd === coverFileDescriptor) { | ||
coverageProfileContents += decoder.decode(buf); | ||
callback(null, buf.length); | ||
return; | ||
} | ||
defaultWrite(fd, buf, offset, length, position, callback); | ||
}; | ||
} | ||
|
||
(async() => { | ||
const go = new Go(); | ||
overrideFS(globalThis.fs) | ||
go.argv = [{{range $i, $item := .Args}} {{if $i}}, {{end}} "{{$item}}" {{end}}]; | ||
// The notFirst variable sets itself to true after first iteration. This is to put commas in between. | ||
go.env = { {{ $notFirst := false }} | ||
{{range $key, $val := .EnvMap}} {{if $notFirst}}, {{end}} {{$key}}: "{{$val}}" {{ $notFirst = true }} | ||
{{end}} }; | ||
go.exit = goExit; | ||
let mod, inst; | ||
await WebAssembly.instantiateStreaming(fetch("{{.WASMFile}}"), go.importObject).then((result) => { | ||
mod = result.module; | ||
inst = result.instance; | ||
}).catch((err) => { | ||
console.error(err); | ||
}); | ||
await go.run(inst); | ||
document.getElementById("doneButton").disabled = false; | ||
})(); | ||
</script> | ||
|
||
<button id="doneButton" style="display: none;" disabled>Done</button> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters