package main import ( "bytes" "context" "flag" "fmt" "io/ioutil" "log" "os" "path/filepath" "strings" "time" "github.com/google/subcommands" "github.com/perlin-network/life/exec" "github.com/rogpeppe/go-internal/txtar" "tulpa.dev/within/wasmcloud/executor" ) type runCmd struct { funcName, abi string gasLimit uint64 ramLimit int } func (runCmd) Name() string { return "run" } func (runCmd) Synopsis() string { return "run a webassembly file with the same environment as production servers" } func (runCmd) Usage() string { return `wasmcloud run [options] $ wasmcloud run olinfetch.wasm $ wasmcloud run -abi dagger -func-name dagger_main hello_dagger.wasm Run a given webassembly binary and return the output. Flags: ` } func (r *runCmd) SetFlags(fs *flag.FlagSet) { fs.StringVar(&r.funcName, "func-name", "cwa_main", "entrypoint function to call") fs.StringVar(&r.abi, "abi", "cwa", "ABI to use") fs.Uint64Var(&r.gasLimit, "gas-limit", 1048576, "number of wasm instructions per execution") fs.IntVar(&r.ramLimit, "ram-limit", 128, "number of wasm pages that can be used") } func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { if fs.NArg() != 1 { fmt.Println(r.Usage()) return subcommands.ExitUsageError } fname := fs.Arg(0) stdout := bytes.NewBuffer(nil) stderr := bytes.NewBuffer(nil) logBuf := bytes.NewBuffer(nil) wasmBin, err := ioutil.ReadFile(fname) if err != nil { log.Fatal(err) } getenvironment := func(data []string, getkeyval func(item string) (key, val string)) map[string]string { items := make(map[string]string) for _, item := range data { key, val := getkeyval(item) items[key] = val } return items } environment := getenvironment(os.Environ(), func(item string) (key, val string) { splits := strings.Split(item, "=") key = splits[0] val = splits[1] return }) c := executor.Config{ VMConfig: exec.VMConfig{ GasLimit: r.gasLimit, ReturnOnGasLimitExceeded: true, MaxMemoryPages: r.ramLimit, }, Name: filepath.Base(fname), FuncName: r.funcName, Env: environment, Binary: wasmBin, Stdin: os.Stdin, Stdout: stdout, Stderr: stderr, LogSink: logBuf, } result, err := executor.Run(c) if err != nil { log.Printf("can't run binary: %v", err) return subcommands.ExitFailure } arc := txtar.Archive{ Comment: []byte(fmt.Sprintf("execution of %s at %s", filepath.Base(fname), result.StartTime.Format(time.RFC3339))), Files: []txtar.File{ { Name: "logs.txt", Data: logBuf.Bytes(), }, { Name: "stdout.txt", Data: stdout.Bytes(), }, { Name: "stderr.txt", Data: stderr.Bytes(), }, result.StatsFile(), }, } fmt.Println(string(txtar.Format(&arc))) return subcommands.ExitSuccess }