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

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)
},
}