1
0
mirror of https://github.com/taigrr/wasm-experiments synced 2025-01-18 04:03:21 -08:00

Add jsgo.io example

This commit is contained in:
Johan Brandhorst
2018-08-15 17:00:38 +01:00
parent 50d7c00276
commit 31e31e865c
823 changed files with 404944 additions and 1 deletions

5
vendor/github.com/dave/wasmgo/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
*.iml
.DS_Store
.idea/
coverage.out
.coverage/

7
vendor/github.com/dave/wasmgo/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2018 David Brophy
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

56
vendor/github.com/dave/wasmgo/README.md generated vendored Normal file
View File

@@ -0,0 +1,56 @@
<a href="https://patreon.com/davebrophy" title="Help with my hosting bills using Patreon"><img src="https://img.shields.io/badge/patreon-donate-yellow.svg" style="max-width:100%;"></a>
# wasmgo
The `wasmgo` command compiles Go to WASM and deploys to the [jsgo.io](https://github.com/dave/jsgo)
CDN.
### Install
`go get -u github.com/dave/wasmgo`
### Usage
```
Compiles Go to WASM and deploys to the jsgo.io CDN.
Usage:
wasmgo deploy [package] [flags]
Flags:
-b, --build string Build tags to pass to the go build command.
-c, --command string Name of the go command. (default "go")
-f, --flags string Flags to pass to the go build command.
-h, --help help for deploy
-i, --index string Specify the index page. (default "index.wasmgo.html")
-j, --json Return all template variables as a json blob from the deploy command.
-o, --open Open the page in a browser.
-t, --template string Template defining the output returned by the deploy command. Variables: Page (string), Loader (string). (default "{{ .Page }}")
-v, --verbose Show detailed status messages.
```
### Example
Here's a simple hello world:
```
wasmgo deploy github.com/dave/wasmgo/helloworld
```
### Index
You may specify a custom index page by including `index.wasmgo.html` in your project or by using the `index`
command line flag.
Your index page should look something like this:
```html
<html>
<head><meta charset="utf-8"></head>
<body>
<script src="{{ .Script }}"></script>
<script src="{{ .Loader }}"></script>
</body>
</html>
```

14
vendor/github.com/dave/wasmgo/cmd/cmdconfig/config.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
package cmdconfig
type Config struct {
Port int
Index string
Template string
Json bool
Verbose bool
Open bool
Command string
Flags string
BuildTags string
Path string
}

37
vendor/github.com/dave/wasmgo/cmd/deploy.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package cmd
import (
"fmt"
"os"
"github.com/dave/wasmgo/cmd/deployer"
"github.com/spf13/cobra"
)
func init() {
deployCmd.PersistentFlags().StringVarP(&global.Index, "index", "i", "index.wasmgo.html", "Specify the index page.")
deployCmd.PersistentFlags().BoolVarP(&global.Verbose, "verbose", "v", false, "Show detailed status messages.")
deployCmd.PersistentFlags().BoolVarP(&global.Open, "open", "o", false, "Open the page in a browser.")
deployCmd.PersistentFlags().StringVarP(&global.Command, "command", "c", "go", "Name of the go command.")
deployCmd.PersistentFlags().StringVarP(&global.Flags, "flags", "f", "", "Flags to pass to the go build command.")
deployCmd.PersistentFlags().StringVarP(&global.BuildTags, "build", "b", "", "Build tags to pass to the go build command.")
deployCmd.PersistentFlags().StringVarP(&global.Template, "template", "t", "{{ .Page }}", "Template defining the output returned by the deploy command. Variables: Page (string), Loader (string).")
deployCmd.PersistentFlags().BoolVarP(&global.Json, "json", "j", false, "Return all template variables as a json blob from the deploy command.")
rootCmd.AddCommand(deployCmd)
}
var deployCmd = &cobra.Command{
Use: "deploy [package]",
Short: "Compile and deploy",
Long: "Compiles Go to WASM and deploys to the jsgo.io CDN.",
Args: cobra.RangeArgs(0, 1),
Run: func(cmd *cobra.Command, args []string) {
if len(args) > 0 {
global.Path = args[0]
}
if err := deployer.Start(global); err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
os.Exit(1)
}
},
}

342
vendor/github.com/dave/wasmgo/cmd/deployer/deployer.go generated vendored Normal file
View File

@@ -0,0 +1,342 @@
package deployer
import (
"bytes"
"crypto/sha1"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
"github.com/dave/jsgo/assets/std"
"github.com/dave/jsgo/server/servermsg"
"github.com/dave/jsgo/server/wasm/messages"
"github.com/dave/services/constor/constormsg"
"github.com/dave/wasmgo/cmd/cmdconfig"
"github.com/dave/wasmgo/config"
"github.com/gorilla/websocket"
"github.com/pkg/browser"
)
const CLIENT_VERSION = "1.0.0"
func Start(cfg *cmdconfig.Config) error {
var debug io.Writer
if cfg.Verbose {
debug = os.Stdout
} else {
debug = ioutil.Discard
}
// create a temp dir
tempDir, err := ioutil.TempDir("", "")
if err != nil {
return err
}
defer os.RemoveAll(tempDir)
fpath := filepath.Join(tempDir, "out.wasm")
sourceDir, err := runGoList(cfg)
if err != nil {
return err
}
if err := runGoBuild(cfg, fpath, debug); err != nil {
return err
}
binaryBytes, err := ioutil.ReadFile(fpath)
if err != nil {
return err
}
binarySha := sha1.New()
if _, err := io.Copy(binarySha, bytes.NewBuffer(binaryBytes)); err != nil {
return err
}
files := map[messages.DeployFileType]messages.DeployFile{}
files[messages.DeployFileTypeWasm] = messages.DeployFile{
DeployFileKey: messages.DeployFileKey{
Type: messages.DeployFileTypeWasm,
Hash: fmt.Sprintf("%x", binarySha.Sum(nil)),
},
Contents: binaryBytes,
}
loaderBuf := &bytes.Buffer{}
loaderSha := sha1.New()
wasmUrl := fmt.Sprintf("%s://%s/%x.wasm", config.Protocol[config.Pkg], config.Host[config.Pkg], binarySha.Sum(nil))
loaderVars := struct{ Binary string }{
Binary: wasmUrl,
}
if err := loaderTemplateMin.Execute(io.MultiWriter(loaderBuf, loaderSha), loaderVars); err != nil {
return err
}
files[messages.DeployFileTypeLoader] = messages.DeployFile{
DeployFileKey: messages.DeployFileKey{
Type: messages.DeployFileTypeLoader,
Hash: fmt.Sprintf("%x", loaderSha.Sum(nil)),
},
Contents: loaderBuf.Bytes(),
}
indexBuf := &bytes.Buffer{}
indexSha := sha1.New()
loaderUrl := fmt.Sprintf("%s://%s/%x.js", config.Protocol[config.Pkg], config.Host[config.Pkg], loaderSha.Sum(nil))
indexVars := struct{ Script, Loader string }{
Script: fmt.Sprintf("%s://%s/wasm_exec.%s.js", config.Protocol[config.Pkg], config.Host[config.Pkg], std.Wasm[true]),
Loader: loaderUrl,
}
indexTemplate := defaultIndexTemplate
if cfg.Index != "" {
indexFilename := cfg.Index
if cfg.Path != "" {
indexFilename = filepath.Join(sourceDir, cfg.Index)
}
indexTemplateBytes, err := ioutil.ReadFile(indexFilename)
if err != nil && !os.IsNotExist(err) {
return err
}
if err == nil {
indexTemplate, err = template.New("main").Parse(string(indexTemplateBytes))
if err != nil {
return err
}
}
}
if err := indexTemplate.Execute(io.MultiWriter(indexBuf, indexSha), indexVars); err != nil {
return err
}
files[messages.DeployFileTypeIndex] = messages.DeployFile{
DeployFileKey: messages.DeployFileKey{
Type: messages.DeployFileTypeIndex,
Hash: fmt.Sprintf("%x", indexSha.Sum(nil)),
},
Contents: indexBuf.Bytes(),
}
indexUrl := fmt.Sprintf("%s://%s/%x", config.Protocol[config.Index], config.Host[config.Index], indexSha.Sum(nil))
message := messages.DeployQuery{
Version: CLIENT_VERSION,
Files: []messages.DeployFileKey{
files[messages.DeployFileTypeWasm].DeployFileKey,
files[messages.DeployFileTypeIndex].DeployFileKey,
files[messages.DeployFileTypeLoader].DeployFileKey,
},
}
fmt.Fprintln(debug, "Querying server...")
protocol := "wss"
if config.Protocol[config.Wasm] == "http" {
protocol = "ws"
}
conn, _, err := websocket.DefaultDialer.Dial(
fmt.Sprintf("%s://%s/_wasm/", protocol, config.Host[config.Wasm]),
http.Header{"Origin": []string{fmt.Sprintf("%s://%s/", config.Protocol[config.Wasm], config.Host[config.Wasm])}},
)
if err != nil {
return err
}
messageBytes, messageType, err := messages.Marshal(message)
if err != nil {
return err
}
if err := conn.WriteMessage(messageType, messageBytes); err != nil {
return err
}
var response messages.DeployQueryResponse
var done bool
for !done {
_, replyBytes, err := conn.ReadMessage()
if err != nil {
return err
}
message, err := messages.Unmarshal(replyBytes)
if err != nil {
return err
}
switch message := message.(type) {
case messages.DeployQueryResponse:
response = message
done = true
case servermsg.Queueing:
// don't print
case servermsg.Error:
return errors.New(message.Message)
case messages.DeployClientVersionNotSupported:
return errors.New("this client version is not supported - try `go get -u github.com/dave/wasmgo`")
default:
// unexpected
fmt.Fprintf(debug, "Unexpected message from server: %#v\n", message)
}
}
if len(response.Required) > 0 {
fmt.Fprintf(debug, "Files required: %d.\n", len(response.Required))
fmt.Fprintln(debug, "Bundling required files...")
var required []messages.DeployFile
for _, k := range response.Required {
file := files[k.Type]
if file.Hash == "" {
return errors.New("server requested file not found")
}
required = append(required, file)
}
payload := messages.DeployPayload{Files: required}
payloadBytes, payloadType, err := messages.Marshal(payload)
if err != nil {
return err
}
if err := conn.WriteMessage(payloadType, payloadBytes); err != nil {
return err
}
fmt.Fprintf(debug, "Sending payload: %dKB.\n", len(payloadBytes)/1024)
done = false
for !done {
_, replyBytes, err := conn.ReadMessage()
if err != nil {
return err
}
message, err := messages.Unmarshal(replyBytes)
if err != nil {
return err
}
switch message := message.(type) {
case messages.DeployDone:
done = true
case servermsg.Queueing:
// don't print
case servermsg.Error:
return errors.New(message.Message)
case constormsg.Storing:
if message.Remain > 0 || message.Finished > 0 {
fmt.Fprintf(debug, "Storing, %d to go.\n", message.Remain)
}
default:
// unexpected
fmt.Fprintf(debug, "Unexpected message from server: %#v\n", message)
}
}
fmt.Fprintln(debug, "Sending done.")
} else {
fmt.Fprintln(debug, "No files required.")
}
outputVars := struct {
Page string
Loader string
}{
Page: indexUrl,
Loader: loaderUrl,
}
if cfg.Json {
out, err := json.Marshal(outputVars)
if err != nil {
return err
}
fmt.Println(string(out))
} else {
tpl, err := template.New("main").Parse(cfg.Template)
if err != nil {
return err
}
tpl.Execute(os.Stdout, outputVars)
fmt.Println("")
}
if cfg.Open {
browser.OpenURL(indexUrl)
}
return nil
}
func runGoBuild(cfg *cmdconfig.Config, fpath string, debug io.Writer) error {
args := []string{"build", "-o", fpath}
extraFlags := strings.Fields(cfg.Flags)
for _, f := range extraFlags {
args = append(args, f)
}
if cfg.BuildTags != "" {
args = append(args, "-tags", cfg.BuildTags)
}
path := "."
if cfg.Path != "" {
path = cfg.Path
}
args = append(args, path)
fmt.Fprintln(debug, "Compiling...")
cmd := exec.Command(cfg.Command, args...)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "GOARCH=wasm")
cmd.Env = append(cmd.Env, "GOOS=js")
output, err := cmd.CombinedOutput()
if err != nil {
if strings.Contains(string(output), "unsupported GOOS/GOARCH pair js/wasm") {
return errors.New("you need Go v1.11 to compile WASM. It looks like your default `go` command is not v1.11. Perhaps you need the -c flag to specify a custom command name - e.g. `-c=go1.11beta3`")
}
return fmt.Errorf("%v: %s", err, string(output))
}
if len(output) > 0 {
return fmt.Errorf("%s", string(output))
}
return nil
}
func runGoList(cfg *cmdconfig.Config) (string, error) {
args := []string{"list"}
if cfg.BuildTags != "" {
args = append(args, "-tags", cfg.BuildTags)
}
args = append(args, "-f", "{{.Dir}}")
path := "."
if cfg.Path != "" {
path = cfg.Path
}
args = append(args, path)
cmd := exec.Command(cfg.Command, args...)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "GOARCH=wasm")
cmd.Env = append(cmd.Env, "GOOS=js")
output, err := cmd.CombinedOutput()
if err != nil {
if strings.Contains(string(output), "unsupported GOOS/GOARCH pair js/wasm") {
return "", errors.New("you need Go v1.11 to compile WASM. It looks like your default `go` command is not v1.11. Perhaps you need the -c flag to specify a custom command name - e.g. `-c=go1.11beta3`")
}
return "", fmt.Errorf("%v: %s", err, string(output))
}
return string(output), nil
}

View File

@@ -0,0 +1,24 @@
package deployer
import "text/template"
var defaultIndexTemplate = template.Must(template.New("main").Parse(`<html>
<head><meta charset="utf-8"></head>
<body>
<script src="{{ .Script }}"></script>
<script src="{{ .Loader }}"></script>
</body>
</html>`))
var loaderTemplate = template.Must(template.New("main").Parse(`if (!WebAssembly.instantiateStreaming) {
WebAssembly.instantiateStreaming = async (resp, importObject) => {
const source = await (await resp).arrayBuffer();
return await WebAssembly.instantiate(source, importObject);
};
}
const go = new Go();
WebAssembly.instantiateStreaming(fetch("{{ .Binary }}"), go.importObject).then(result => {
go.run(result.instance);
});`))
var loaderTemplateMin = template.Must(template.New("main").Parse(`WebAssembly.instantiateStreaming||(WebAssembly.instantiateStreaming=(async(t,a)=>{const e=await(await t).arrayBuffer();return await WebAssembly.instantiate(e,a)}));const go=new Go;WebAssembly.instantiateStreaming(fetch("{{ .Binary }}"),go.importObject).then(t=>{go.run(t.instance)});`))

23
vendor/github.com/dave/wasmgo/cmd/root.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
package cmd
import (
"fmt"
"os"
"github.com/dave/wasmgo/cmd/cmdconfig"
"github.com/spf13/cobra"
)
var global = &cmdconfig.Config{}
var rootCmd = &cobra.Command{
Use: "wasmgo",
Short: "Compile Go to WASM, test locally or deploy to jsgo.io",
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

18
vendor/github.com/dave/wasmgo/cmd/serve.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
package cmd
/*
func init() {
serveCmd.PersistentFlags().IntVarP(&global.Port, "port", "p", 8080, "Server port. If this is in use, an unused port is chosen.")
rootCmd.AddCommand(serveCmd)
}
var serveCmd = &cobra.Command{
Use: "serve [package]",
Short: "Serve locally",
Long: "Starts a webserver locally, and recompiles the WASM on every page refresh, for testing and development.",
Args: cobra.RangeArgs(0, 1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Serve mode coming soon...")
},
}
*/

20
vendor/github.com/dave/wasmgo/cmd/version.go generated vendored Normal file
View File

@@ -0,0 +1,20 @@
package cmd
import (
"fmt"
"github.com/dave/wasmgo/cmd/deployer"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Show client version number",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(deployer.CLIENT_VERSION)
},
}

7
vendor/github.com/dave/wasmgo/config/config.dev.go generated vendored Normal file
View File

@@ -0,0 +1,7 @@
// +build dev
package config
const (
DEV = true
)

7
vendor/github.com/dave/wasmgo/config/config.prod.go generated vendored Normal file
View File

@@ -0,0 +1,7 @@
// +build !dev
package config
const (
DEV = false
)

7
vendor/github.com/dave/wasmgo/config/constants.go generated vendored Normal file
View File

@@ -0,0 +1,7 @@
package config
const (
Wasm = "wasm"
Index = "index"
Pkg = "pkg"
)

19
vendor/github.com/dave/wasmgo/config/hosts.dev.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
// +build dev,!local
package config
const (
LOCAL = false
)
var Host = map[string]string{
Wasm: "localhost:8083",
Pkg: "dev-pkg.jsgo.io",
Index: "dev-index.jsgo.io",
}
var Protocol = map[string]string{
Wasm: "http",
Pkg: "https",
Index: "https",
}

19
vendor/github.com/dave/wasmgo/config/hosts.local.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
// +build local
package config
const (
LOCAL = true
)
var Host = map[string]string{
Wasm: "localhost:8083",
Pkg: "localhost:8092",
Index: "localhost:8093",
}
var Protocol = map[string]string{
Wasm: "http",
Pkg: "http",
Index: "http",
}

19
vendor/github.com/dave/wasmgo/config/hosts.prod.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
// +build !dev,!local
package config
const (
LOCAL = false
)
var Host = map[string]string{
Wasm: "wasm.jsgo.io",
Pkg: "pkg.jsgo.io",
Index: "jsgo.io",
}
var Protocol = map[string]string{
Wasm: "https",
Pkg: "https",
Index: "https",
}

7
vendor/github.com/dave/wasmgo/main.go generated vendored Normal file
View File

@@ -0,0 +1,7 @@
package main
import "github.com/dave/wasmgo/cmd"
func main() {
cmd.Execute()
}