gojs: refactors out gojs.Config type (#1240)
In order to support more configuration, we should stop using context as it is getting gnarly. Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io> Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -226,13 +226,6 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
|
||||
exit(1)
|
||||
}
|
||||
|
||||
if workdirInherit {
|
||||
if ctx, err = gojs.WithOSWorkDir(ctx); err != nil {
|
||||
fmt.Fprintf(stdErr, "cannot read current working directory: %v\n", err)
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
rt := wazero.NewRuntimeWithConfig(ctx, rtc)
|
||||
defer rt.Close(ctx)
|
||||
|
||||
@@ -274,7 +267,13 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
|
||||
}
|
||||
case modeGo:
|
||||
gojs.MustInstantiate(ctx, rt)
|
||||
err = gojs.Run(ctx, rt, code, conf)
|
||||
|
||||
config := gojs.NewConfig(conf)
|
||||
if workdirInherit {
|
||||
config = config.WithOSWorkdir()
|
||||
}
|
||||
|
||||
err = gojs.Run(ctx, rt, code, config)
|
||||
case modeDefault:
|
||||
_, err = rt.InstantiateModule(ctx, code, conf)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func main() {
|
||||
log.Printf("gojs.MustInstantiate took %dms", goJsInstantiate)
|
||||
|
||||
// Combine the above into our baseline config, overriding defaults.
|
||||
config := wazero.NewModuleConfig().
|
||||
moduleConfig := wazero.NewModuleConfig().
|
||||
// By default, I/O streams are discarded, so you won't see output.
|
||||
WithStdout(os.Stdout).WithStderr(os.Stderr)
|
||||
|
||||
@@ -63,7 +63,7 @@ func main() {
|
||||
log.Printf("CompileModule took %dms with %dKB cache", compilationTime, dirSize(compilationCacheDir)/1024)
|
||||
|
||||
// Instead of making real HTTP calls, return fake data.
|
||||
ctx = gojs.WithRoundTripper(ctx, &fakeGitHub{})
|
||||
config := gojs.NewConfig(moduleConfig).WithRoundTripper(&fakeGitHub{})
|
||||
|
||||
// Execute the "run" function, which corresponds to "main" in stars/main.go.
|
||||
start = time.Now()
|
||||
|
||||
@@ -80,8 +80,8 @@ func Benchmark_main(b *testing.B) {
|
||||
gojs.MustInstantiate(ctx, r)
|
||||
|
||||
// Instead of making real HTTP calls, return fake data.
|
||||
ctx = gojs.WithRoundTripper(ctx, &fakeGitHub{})
|
||||
cfg := wazero.NewModuleConfig()
|
||||
cfg := gojs.NewConfig(wazero.NewModuleConfig()).
|
||||
WithRoundTripper(&fakeGitHub{})
|
||||
|
||||
b.Run("gojs.Run", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
@@ -16,14 +16,12 @@ package gojs
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
. "github.com/tetratelabs/wazero/internal/gojs"
|
||||
internalconfig "github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
. "github.com/tetratelabs/wazero/internal/gojs/run"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
@@ -97,42 +95,60 @@ func (e *functionExporter) ExportFunctions(builder wazero.HostModuleBuilder) {
|
||||
hfExporter.ExportHostFunc(Debug)
|
||||
}
|
||||
|
||||
// WithRoundTripper sets the http.RoundTripper used to Run Wasm.
|
||||
//
|
||||
// For example, if the code compiled via `GOARCH=wasm GOOS=js` uses
|
||||
// http.RoundTripper, you can avoid failures by assigning an implementation
|
||||
// like so:
|
||||
//
|
||||
// ctx = gojs.WithRoundTripper(ctx, http.DefaultTransport)
|
||||
// err = gojs.Run(ctx, r, compiled, config)
|
||||
func WithRoundTripper(ctx context.Context, rt http.RoundTripper) context.Context {
|
||||
return context.WithValue(ctx, RoundTripperKey{}, rt)
|
||||
// Config extends wazero.ModuleConfig with GOOS=js specific extensions.
|
||||
// Use NewConfig to create an instance.
|
||||
type Config interface {
|
||||
// WithOSWorkdir sets the initial working directory used to Run Wasm to
|
||||
// the value of os.Getwd instead of the default of root "/".
|
||||
//
|
||||
// Here's an example that overrides this to the current directory:
|
||||
//
|
||||
// err = gojs.Run(ctx, r, compiled, gojs.NewConfig(moduleConfig).
|
||||
// WithOSWorkdir())
|
||||
//
|
||||
// Note: To use this feature requires mounting the real root directory via
|
||||
// wazero.FSConfig `WithDirMount`. On windows, this root must be the same drive
|
||||
// as the value of os.Getwd. For example, it would be an error to mount `C:\`
|
||||
// as the guest path "", while the current directory is inside `D:\`.
|
||||
WithOSWorkdir() Config
|
||||
|
||||
// WithRoundTripper sets the http.RoundTripper used to Run Wasm.
|
||||
//
|
||||
// For example, if the code compiled via `GOARCH=wasm GOOS=js` uses
|
||||
// http.RoundTripper, you can avoid failures by assigning an implementation
|
||||
// like so:
|
||||
//
|
||||
// err = gojs.Run(ctx, r, compiled, gojs.NewConfig(moduleConfig).
|
||||
// WithRoundTripper(ctx, http.DefaultTransport))
|
||||
WithRoundTripper(http.RoundTripper) Config
|
||||
}
|
||||
|
||||
// WithOSWorkDir sets the initial working directory used to Run Wasm to
|
||||
// the value of os.Getwd instead of the default of root "/".
|
||||
//
|
||||
// Here's an example that overrides this to "/usr/local/go/src/os".
|
||||
//
|
||||
// ctx = gojs.WithOSWorkDir(ctx)
|
||||
// err = gojs.Run(ctx, r, compiled, config)
|
||||
//
|
||||
// Note: To use this feature requires mounting the real root directory via
|
||||
// wazero.FSConfig `WithDirMount`. On windows, this root must be the same drive
|
||||
// as the value of os.Getwd. For example, it would be an error to mount `C:\`
|
||||
// as the guest path "", while the current directory is inside `D:\`.
|
||||
func WithOSWorkDir(ctx context.Context) (context.Context, error) {
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// NewConfig returns a Config that can be used for configuring module instantiation.
|
||||
func NewConfig(moduleConfig wazero.ModuleConfig) Config {
|
||||
return &cfg{moduleConfig: moduleConfig, internal: internalconfig.NewConfig()}
|
||||
}
|
||||
|
||||
// Ensure if used on windows, the input path is translated to a POSIX one.
|
||||
workdir = platform.ToPosixPath(workdir)
|
||||
// Strip the volume of the path, for example C:\
|
||||
workdir = workdir[len(filepath.VolumeName(workdir)):]
|
||||
type cfg struct {
|
||||
moduleConfig wazero.ModuleConfig
|
||||
internal *internalconfig.Config
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, WorkdirKey{}, workdir), nil
|
||||
func (c *cfg) clone() *cfg {
|
||||
return &cfg{moduleConfig: c.moduleConfig, internal: c.internal.Clone()}
|
||||
}
|
||||
|
||||
// WithOSWorkdir implements Config.WithOSWorkdir
|
||||
func (c *cfg) WithOSWorkdir() Config {
|
||||
ret := c.clone()
|
||||
ret.internal.OsWorkdir = true
|
||||
return ret
|
||||
}
|
||||
|
||||
// WithRoundTripper implements Config.WithRoundTripper
|
||||
func (c *cfg) WithRoundTripper(rt http.RoundTripper) Config {
|
||||
ret := c.clone()
|
||||
ret.internal.Rt = rt
|
||||
return ret
|
||||
}
|
||||
|
||||
// Run instantiates a new module and calls "run" with the given config.
|
||||
@@ -142,20 +158,21 @@ func WithOSWorkDir(ctx context.Context) (context.Context, error) {
|
||||
// - ctx: context to use when instantiating the module and calling "run".
|
||||
// - r: runtime to instantiate both the host and guest (compiled) module in.
|
||||
// - compiled: guest binary compiled with `GOARCH=wasm GOOS=js`
|
||||
// - config: the configuration such as args, env or filesystem to use.
|
||||
// - config: the Config to use including wazero.ModuleConfig or extensions of
|
||||
// it.
|
||||
//
|
||||
// # Example
|
||||
//
|
||||
// After compiling your Wasm binary with wazero.Runtime's `CompileModule`, run
|
||||
// it like below:
|
||||
//
|
||||
// // Use compilation cache to reduce performance penalty of multiple runs.
|
||||
// ctx = experimental.WithCompilationCacheDirName(ctx, ".build")
|
||||
// // Instantiate host functions needed by gojs
|
||||
// gojs.MustInstantiate(ctx, r)
|
||||
//
|
||||
// // Instantiate the host functions used for each call.
|
||||
// gojs.MustInstantiate(r)
|
||||
// // Assign any configuration relevant for your compiled wasm.
|
||||
// config := gojs.NewConfig(wazero.NewConfig())
|
||||
//
|
||||
// // Execute the "run" function, which corresponds to "main" in stars/main.go.
|
||||
// // Run your wasm, notably handing any ExitError
|
||||
// err = gojs.Run(ctx, r, compiled, config)
|
||||
// if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() != 0 {
|
||||
// log.Panicln(err)
|
||||
@@ -165,12 +182,12 @@ func WithOSWorkDir(ctx context.Context) (context.Context, error) {
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// - Use wazero.RuntimeConfig `WithWasmCore2` to avoid needing to pick >1.0
|
||||
// features set by `GOWASM` or used internally by Run.
|
||||
// - Wasm generated by `GOARCH=wasm GOOS=js` is very slow to compile.
|
||||
// Use experimental.WithCompilationCacheDirName to improve performance.
|
||||
// - Wasm generated by `GOARCH=wasm GOOS=js` is very slow to compile: Use
|
||||
// wazero.RuntimeConfig with wazero.CompilationCache when re-running the
|
||||
// same binary.
|
||||
// - The guest module is closed after being run.
|
||||
func Run(ctx context.Context, r wazero.Runtime, compiled wazero.CompiledModule, config wazero.ModuleConfig) error {
|
||||
_, err := RunAndReturnState(ctx, r, compiled, config)
|
||||
func Run(ctx context.Context, r wazero.Runtime, compiled wazero.CompiledModule, moduleConfig Config) error {
|
||||
c := moduleConfig.(*cfg)
|
||||
_, err := RunAndReturnState(ctx, r, compiled, c.moduleConfig, c.internal)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
func TestWithOSWorkdir(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, err := WithOSWorkDir(context.Background())
|
||||
require.NoError(t, err)
|
||||
actual := ctx.Value(gojs.WorkdirKey{}).(string)
|
||||
|
||||
// Check c:\ or d:\ aren't retained.
|
||||
require.Equal(t, -1, strings.IndexByte(actual, '\\'))
|
||||
require.Equal(t, -1, strings.IndexByte(actual, ':'))
|
||||
}
|
||||
@@ -4,14 +4,16 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
func Test_argsAndEnv(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
stdout, stderr, err := compileAndRun(testCtx, "argsenv", wazero.NewModuleConfig().
|
||||
WithEnv("c", "d").WithEnv("a", "b"))
|
||||
stdout, stderr, err := compileAndRun(testCtx, "argsenv", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return moduleConfig.WithEnv("c", "d").WithEnv("a", "b"), config.NewConfig()
|
||||
})
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Zero(t, stderr)
|
||||
|
||||
@@ -26,7 +26,7 @@ func newJsGlobal(rt http.RoundTripper) *jsVal {
|
||||
"fs": jsfs,
|
||||
"Date": jsDateConstructor,
|
||||
}).
|
||||
addFunction("fetch", httpFetch{})
|
||||
addFunction("fetch", &httpFetch{rt})
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -20,13 +20,20 @@ import (
|
||||
"github.com/tetratelabs/wazero/experimental/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
internalgojs "github.com/tetratelabs/wazero/internal/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/run"
|
||||
"github.com/tetratelabs/wazero/internal/testing/binaryencoding"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
binaryformat "github.com/tetratelabs/wazero/internal/wasm/binary"
|
||||
)
|
||||
|
||||
func compileAndRun(ctx context.Context, arg string, config wazero.ModuleConfig) (stdout, stderr string, err error) {
|
||||
type newConfig func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config)
|
||||
|
||||
func defaultConfig(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return moduleConfig, config.NewConfig()
|
||||
}
|
||||
|
||||
func compileAndRun(ctx context.Context, arg string, config newConfig) (stdout, stderr string, err error) {
|
||||
rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().
|
||||
// https://github.com/tetratelabs/wazero/issues/992
|
||||
WithMemoryCapacityFromMax(true).
|
||||
@@ -34,7 +41,7 @@ func compileAndRun(ctx context.Context, arg string, config wazero.ModuleConfig)
|
||||
return compileAndRunWithRuntime(ctx, rt, arg, config) // use global runtime
|
||||
}
|
||||
|
||||
func compileAndRunWithRuntime(ctx context.Context, r wazero.Runtime, arg string, config wazero.ModuleConfig) (stdout, stderr string, err error) {
|
||||
func compileAndRunWithRuntime(ctx context.Context, r wazero.Runtime, arg string, config newConfig) (stdout, stderr string, err error) {
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
|
||||
builder := r.NewHostModuleBuilder("go")
|
||||
@@ -49,13 +56,15 @@ func compileAndRunWithRuntime(ctx context.Context, r wazero.Runtime, arg string,
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
var s *internalgojs.State
|
||||
s, err = run.RunAndReturnState(ctx, r, compiled, config.
|
||||
mc, c := config(wazero.NewModuleConfig().
|
||||
WithStdout(&stdoutBuf).
|
||||
WithStderr(&stderrBuf).
|
||||
WithArgs("test", arg))
|
||||
|
||||
var s *internalgojs.State
|
||||
s, err = run.RunAndReturnState(ctx, r, compiled, mc, c)
|
||||
if err == nil {
|
||||
if !reflect.DeepEqual(s, internalgojs.NewState(ctx)) {
|
||||
if !reflect.DeepEqual(s, internalgojs.NewState(c)) {
|
||||
log.Panicf("unexpected state: %v\n", s)
|
||||
}
|
||||
}
|
||||
|
||||
42
internal/gojs/config/config.go
Normal file
42
internal/gojs/config/config.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// Package config exists to avoid dependency cycles when keeping most of gojs
|
||||
// code internal.
|
||||
package config
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
OsWorkdir bool
|
||||
Rt http.RoundTripper
|
||||
|
||||
// Workdir is the actual working directory value.
|
||||
Workdir string
|
||||
}
|
||||
|
||||
func NewConfig() *Config {
|
||||
return &Config{Workdir: "/"}
|
||||
}
|
||||
|
||||
func (c *Config) Clone() *Config {
|
||||
ret := *c // copy except maps which share a ref
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (c *Config) Init() error {
|
||||
if c.OsWorkdir {
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Ensure if used on windows, the input path is translated to a POSIX one.
|
||||
workdir = platform.ToPosixPath(workdir)
|
||||
// Strip the volume of the path, for example C:\
|
||||
c.Workdir = workdir[len(filepath.VolumeName(workdir)):]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
22
internal/gojs/config/config_test.go
Normal file
22
internal/gojs/config/config_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
func TestConfig_Init(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OsWorkdir", func(t *testing.T) {
|
||||
c := &Config{OsWorkdir: true}
|
||||
require.NoError(t, c.Init())
|
||||
actual := c.Workdir
|
||||
|
||||
// Check c:\ or d:\ aren't retained.
|
||||
require.Equal(t, -1, strings.IndexByte(actual, '\\'))
|
||||
require.Equal(t, -1, strings.IndexByte(actual, ':'))
|
||||
})
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/experimental/logging"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -18,7 +17,7 @@ func Test_crypto(t *testing.T) {
|
||||
loggingCtx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{},
|
||||
logging.NewHostLoggingListenerFactory(&log, logging.LogScopeRandom))
|
||||
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "crypto", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "crypto", defaultConfig)
|
||||
|
||||
require.Zero(t, stderr)
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
|
||||
@@ -539,8 +539,8 @@ type jsfsChown struct{}
|
||||
|
||||
func (jsfsChown) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
|
||||
path := resolvePath(ctx, args[0].(string))
|
||||
uid := goos.ValueToUint32(args[1])
|
||||
gid := goos.ValueToUint32(args[2])
|
||||
uid := goos.ValueToInt32(args[1])
|
||||
gid := goos.ValueToInt32(args[2])
|
||||
callback := args[3].(funcWrapper)
|
||||
|
||||
fsc := mod.(*wasm.CallContext).Sys.FS()
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
@@ -14,7 +15,9 @@ import (
|
||||
func Test_fs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
stdout, stderr, err := compileAndRun(testCtx, "fs", wazero.NewModuleConfig().WithFS(testFS))
|
||||
stdout, stderr, err := compileAndRun(testCtx, "fs", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return defaultConfig(moduleConfig.WithFS(testFS))
|
||||
})
|
||||
|
||||
require.Zero(t, stderr)
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
@@ -44,7 +47,9 @@ func Test_testfs(t *testing.T) {
|
||||
require.NoError(t, fstest.WriteTestFiles(testfsDir))
|
||||
|
||||
fsConfig := wazero.NewFSConfig().WithDirMount(tmpDir, "/")
|
||||
stdout, stderr, err := compileAndRun(testCtx, "testfs", wazero.NewModuleConfig().WithFSConfig(fsConfig))
|
||||
stdout, stderr, err := compileAndRun(testCtx, "testfs", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return defaultConfig(moduleConfig.WithFSConfig(fsConfig))
|
||||
})
|
||||
|
||||
require.Zero(t, stderr)
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
@@ -59,7 +64,9 @@ func Test_writefs(t *testing.T) {
|
||||
// test expects to write under /tmp
|
||||
require.NoError(t, os.Mkdir(path.Join(tmpDir, "tmp"), 0o700))
|
||||
|
||||
stdout, stderr, err := compileAndRun(testCtx, "writefs", wazero.NewModuleConfig().WithFSConfig(fsConfig))
|
||||
stdout, stderr, err := compileAndRun(testCtx, "writefs", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return defaultConfig(moduleConfig.WithFSConfig(fsConfig))
|
||||
})
|
||||
|
||||
require.Zero(t, stderr)
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
|
||||
@@ -265,6 +265,15 @@ func ValueToUint32(arg interface{}) uint32 {
|
||||
return uint32(arg.(float64))
|
||||
}
|
||||
|
||||
func ValueToInt32(arg interface{}) int32 {
|
||||
if arg == RefValueZero || arg == Undefined {
|
||||
return 0
|
||||
} else if u, ok := arg.(int); ok {
|
||||
return int32(u)
|
||||
}
|
||||
return int32(uint32(arg.(float64)))
|
||||
}
|
||||
|
||||
// GetFunction allows getting a JavaScript property by name.
|
||||
type GetFunction interface {
|
||||
Get(ctx context.Context, propertyKey string) interface{}
|
||||
|
||||
@@ -15,15 +15,6 @@ import (
|
||||
// headersConstructor = Get("Headers").New() // http.Roundtrip && "fetch"
|
||||
var headersConstructor = newJsVal(goos.RefHttpHeadersConstructor, "Headers")
|
||||
|
||||
type RoundTripperKey struct{}
|
||||
|
||||
func getRoundTripper(ctx context.Context) http.RoundTripper {
|
||||
if rt, ok := ctx.Value(RoundTripperKey{}).(http.RoundTripper); ok {
|
||||
return rt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// httpFetch implements jsFn for http.RoundTripper
|
||||
//
|
||||
// Reference in roundtrip_js.go init
|
||||
@@ -33,10 +24,10 @@ func getRoundTripper(ctx context.Context) http.RoundTripper {
|
||||
// In http.Transport RoundTrip, this returns a promise
|
||||
//
|
||||
// fetchPromise := js.Global().Call("fetch", req.URL.String(), opt)
|
||||
type httpFetch struct{}
|
||||
type httpFetch struct{ rt http.RoundTripper }
|
||||
|
||||
func (httpFetch) invoke(ctx context.Context, _ api.Module, args ...interface{}) (interface{}, error) {
|
||||
rt := getRoundTripper(ctx)
|
||||
func (h *httpFetch) invoke(ctx context.Context, _ api.Module, args ...interface{}) (interface{}, error) {
|
||||
rt := h.rt
|
||||
if rt == nil {
|
||||
panic("unexpected to reach here without roundtripper as property is nil checked")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/experimental/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
func Test_http(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := gojs.WithRoundTripper(testCtx, roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
rt := roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
if req.URL.Path == "/error" {
|
||||
return nil, errors.New("error")
|
||||
}
|
||||
@@ -38,10 +38,13 @@ func Test_http(t *testing.T) {
|
||||
Body: io.NopCloser(strings.NewReader("abcdef")),
|
||||
ContentLength: 6,
|
||||
}, nil
|
||||
}))
|
||||
})
|
||||
|
||||
stdout, stderr, err := compileAndRun(ctx, "http", wazero.NewModuleConfig().
|
||||
WithEnv("BASE_URL", "http://host"))
|
||||
stdout, stderr, err := compileAndRun(testCtx, "http", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return moduleConfig.WithEnv("BASE_URL", "http://host"), &config.Config{
|
||||
Rt: rt,
|
||||
}
|
||||
})
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Zero(t, stderr)
|
||||
|
||||
@@ -301,6 +301,11 @@ func writeVal(w logging.Writer, name string, val interface{}) {
|
||||
return
|
||||
}
|
||||
switch name {
|
||||
case "uid", "gid":
|
||||
w.WriteString(name) //nolint
|
||||
w.WriteByte('=') //nolint
|
||||
id := int(goos.ValueToInt32(val))
|
||||
w.WriteString(strconv.Itoa(id)) //nolint
|
||||
case "mask", "mode", "oldmask", "perm":
|
||||
w.WriteString(name) //nolint
|
||||
w.WriteByte('=') //nolint
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/experimental/logging"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
@@ -20,7 +21,7 @@ func Test_exit(t *testing.T) {
|
||||
loggingCtx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{},
|
||||
logging.NewHostLoggingListenerFactory(&log, logging.LogScopeProc))
|
||||
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "exit", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "exit", defaultConfig)
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(255)`)
|
||||
require.Zero(t, stderr)
|
||||
@@ -33,7 +34,7 @@ func Test_exit(t *testing.T) {
|
||||
func Test_goroutine(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
stdout, stderr, err := compileAndRun(testCtx, "goroutine", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(testCtx, "goroutine", defaultConfig)
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Zero(t, stderr)
|
||||
@@ -49,7 +50,7 @@ func Test_mem(t *testing.T) {
|
||||
loggingCtx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{},
|
||||
logging.NewHostLoggingListenerFactory(&log, logging.LogScopeMemory))
|
||||
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "mem", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "mem", defaultConfig)
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Zero(t, stderr)
|
||||
@@ -65,8 +66,9 @@ func Test_stdio(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := "stdin\n"
|
||||
stdout, stderr, err := compileAndRun(testCtx, "stdio", wazero.NewModuleConfig().
|
||||
WithStdin(strings.NewReader(input)))
|
||||
stdout, stderr, err := compileAndRun(testCtx, "stdio", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return defaultConfig(moduleConfig.WithStdin(strings.NewReader(input)))
|
||||
})
|
||||
|
||||
require.Equal(t, "stderr 6\n", stderr)
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
@@ -83,8 +85,9 @@ func Test_stdio_large(t *testing.T) {
|
||||
|
||||
size := 2 * 1024 * 1024 // 2MB
|
||||
input := make([]byte, size)
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "stdio", wazero.NewModuleConfig().
|
||||
WithStdin(bytes.NewReader(input)))
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "stdio", func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config) {
|
||||
return defaultConfig(moduleConfig.WithStdin(bytes.NewReader(input)))
|
||||
})
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Equal(t, fmt.Sprintf("stderr %d\n", size), stderr)
|
||||
@@ -102,7 +105,7 @@ func Test_stdio_large(t *testing.T) {
|
||||
func Test_gc(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
stdout, stderr, err := compileAndRun(testCtx, "gc", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(testCtx, "gc", defaultConfig)
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Equal(t, "", stderr)
|
||||
|
||||
@@ -7,25 +7,35 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/internal/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
)
|
||||
|
||||
func RunAndReturnState(ctx context.Context, r wazero.Runtime, compiled wazero.CompiledModule, config wazero.ModuleConfig) (*gojs.State, error) {
|
||||
// Instantiate the module compiled by go, noting it has no init function.
|
||||
func RunAndReturnState(
|
||||
ctx context.Context,
|
||||
r wazero.Runtime,
|
||||
compiled wazero.CompiledModule,
|
||||
moduleConfig wazero.ModuleConfig,
|
||||
config *config.Config,
|
||||
) (*gojs.State, error) {
|
||||
if err := config.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mod, err := r.InstantiateModule(ctx, compiled, config)
|
||||
// Instantiate the module compiled by go, noting it has no init function.
|
||||
mod, err := r.InstantiateModule(ctx, compiled, moduleConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
// Extract the args and env from the module config and write it to memory.
|
||||
// Extract the args and env from the module Config and write it to memory.
|
||||
argc, argv, err := gojs.WriteArgsAndEnviron(mod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create host-side state for JavaScript values and events.
|
||||
s := gojs.NewState(ctx)
|
||||
s := gojs.NewState(config)
|
||||
ctx = context.WithValue(ctx, gojs.StateKey{}, s)
|
||||
|
||||
// Invoke the run function.
|
||||
|
||||
@@ -6,24 +6,16 @@ import (
|
||||
"math"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/goos"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/values"
|
||||
)
|
||||
|
||||
type WorkdirKey struct{}
|
||||
|
||||
func getWorkdir(ctx context.Context) string {
|
||||
if wd, ok := ctx.Value(WorkdirKey{}).(string); ok {
|
||||
return wd
|
||||
}
|
||||
return "/"
|
||||
}
|
||||
|
||||
func NewState(ctx context.Context) *State {
|
||||
func NewState(config *config.Config) *State {
|
||||
return &State{
|
||||
values: values.NewValues(),
|
||||
valueGlobal: newJsGlobal(getRoundTripper(ctx)),
|
||||
cwd: getWorkdir(ctx),
|
||||
valueGlobal: newJsGlobal(config.Rt),
|
||||
cwd: config.Workdir,
|
||||
umask: 0o0022,
|
||||
_nextCallbackTimeoutID: 1,
|
||||
_scheduledTimeouts: map[uint32]chan bool{},
|
||||
|
||||
@@ -3,14 +3,13 @@ package gojs_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
)
|
||||
|
||||
func Test_syscall(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
stdout, stderr, err := compileAndRun(testCtx, "syscall", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(testCtx, "syscall", defaultConfig)
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Zero(t, stderr)
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/experimental/logging"
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
@@ -18,7 +17,7 @@ func Test_time(t *testing.T) {
|
||||
loggingCtx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{},
|
||||
logging.NewHostLoggingListenerFactory(&log, logging.LogScopeClock))
|
||||
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "time", wazero.NewModuleConfig())
|
||||
stdout, stderr, err := compileAndRun(loggingCtx, "time", defaultConfig)
|
||||
|
||||
require.EqualError(t, err, `module "" closed with exit_code(0)`)
|
||||
require.Zero(t, stderr)
|
||||
|
||||
Reference in New Issue
Block a user