Skip to content

Commit

Permalink
⭐ new: pure Go implementation of water (#18)
Browse files Browse the repository at this point in the history
* update: recompile v0 WATM binaries

* update: canonical test cases

* update: conn wrap logic

* feat: WASIConfigFactory -> ModuleConfigFactory

* update: wasm runtime independent Core

* update: minor change to conn wraps

* update: remodel complete

Now encountering error. Debugging in progress.

* feat: better logging

Revisit slog-based logging and add logger-specific logging functions.

* update: robustness and QoL

Further optimize the implementation and fix bugs.

* update: all test passes

Update tests to reflect all changes, now all tests passing.

* fix: redundant bugfix build constraints

Old bugs are gone after switching to pure Go implementation based on wazero, we need no more these debugging flags.

* fix: remove redundant go.mod replace directive

* improvement: stop set nonblocking by default

This change should not break any existing behavior. If the WebAssembly did not explicitly call set_nonblocking or equivalent within, wazero is unaware of the fd is in nonblocking state and will not work in non-blocking mode when serving WASI API.
  • Loading branch information
gaukas authored Jan 3, 2024
1 parent 82e4e89 commit 3bebb48
Show file tree
Hide file tree
Showing 42 changed files with 2,186 additions and 1,256 deletions.
79 changes: 48 additions & 31 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ package water
import (
"net"

"github.com/gaukas/water/internal/log"
"github.com/gaukas/water/internal/wasm"
)

// Config defines the configuration for the WATER Dialer/Config interface.
type Config struct {
// TMBin contains the binary format of the WebAssembly Transport Module.
// In a typical use case, this mandatory field is populated by loading
// from a .wasm file, downloaded from a remote target, or generated from
// TransportModuleBin contains the binary format of the WebAssembly
// Transport Module.
// In practice, this mandatory field could be populated by loading
// a .wasm file, downloading from a remote host, or generating from
// a .wat (WebAssembly Text Format) file.
TMBin []byte
TransportModuleBin []byte

// TransportModuleConfig optionally provides a configuration file to be pushed into
// the WASM Transport Module.
TransportModuleConfig TransportModuleConfig

// NetworkDialerFunc specifies a func that dials the specified address on the
// named network. This optional field can be set to override the Go
Expand All @@ -23,22 +29,21 @@ type Config struct {
// NetworkListener specifies a net.listener implementation that listens
// on the specified address on the named network. This optional field
// will be used to provide (incoming) network connections from a
// presumably remote source to the WASM instance. Required by
// water.WrapListener().
// presumably remote source to the WASM instance.
//
// Calling (*Config).Listen will override this field.
NetworkListener net.Listener

// TMConfig optionally provides a configuration file to be pushed into
// the WASM Transport Module.
TMConfig TMConfig

// wasiConfigFactory is used to replicate the WASI config for each WASM
// instance created. This field is for advanced use cases and/or debugging
// purposes only.
// ModuleConfigFactory is used to configure the system resource of
// each WASM instance created. This field is for advanced use cases
// and/or debugging purposes only.
//
// Caller is supposed to call c.WASIConfig() to get the pointer to the
// WASIConfigFactory. If the pointer is nil, a new WASIConfigFactory will
// Caller is supposed to call c.ModuleConfig() to get the pointer to the
// ModuleConfigFactory. If the pointer is nil, a new ModuleConfigFactory will
// be created and returned.
wasiConfigFactory *wasm.WASIConfigFactory
ModuleConfigFactory *wasm.ModuleConfigFactory

OverrideLogger *log.Logger // essentially a *slog.Logger, currently using an alias to flatten the version discrepancy
}

// Clone creates a deep copy of the Config.
Expand All @@ -47,15 +52,15 @@ func (c *Config) Clone() *Config {
return nil
}

wasmClone := make([]byte, len(c.TMBin))
copy(wasmClone, c.TMBin)
wasmClone := make([]byte, len(c.TransportModuleBin))
copy(wasmClone, c.TransportModuleBin)

return &Config{
TMBin: c.TMBin,
NetworkDialerFunc: c.NetworkDialerFunc,
NetworkListener: c.NetworkListener,
TMConfig: c.TMConfig,
wasiConfigFactory: c.wasiConfigFactory.Clone(),
TransportModuleBin: c.TransportModuleBin,
NetworkDialerFunc: c.NetworkDialerFunc,
NetworkListener: c.NetworkListener,
TransportModuleConfig: c.TransportModuleConfig,
ModuleConfigFactory: c.ModuleConfigFactory.Clone(),
}
}

Expand All @@ -81,21 +86,25 @@ func (c *Config) NetworkListenerOrPanic() net.Listener {

// WATMBinOrDefault returns the WATMBin if it is not nil, otherwise it panics.
func (c *Config) WATMBinOrPanic() []byte {
if len(c.TMBin) == 0 {
if len(c.TransportModuleBin) == 0 {
panic("water: WebAssembly Transport Module binary is not provided in config")
}

return c.TMBin
return c.TransportModuleBin
}

// WASIConfig returns the WASIConfigFactory. If the pointer is
// nil, a new WASIConfigFactory will be created and returned.
func (c *Config) WASIConfig() *wasm.WASIConfigFactory {
if c.wasiConfigFactory == nil {
c.wasiConfigFactory = wasm.NewWasiConfigFactory()
// ModuleConfig returns the ModuleConfigFactory. If the pointer is
// nil, a new ModuleConfigFactory will be created and returned.
func (c *Config) ModuleConfig() *wasm.ModuleConfigFactory {
if c.ModuleConfigFactory == nil {
c.ModuleConfigFactory = wasm.NewModuleConfigFactory()

// by default, stdout and stderr are inherited
c.ModuleConfigFactory.InheritStdout()
c.ModuleConfigFactory.InheritStderr()
}

return c.wasiConfigFactory
return c.ModuleConfigFactory
}

func (c *Config) Listen(network, address string) (Listener, error) {
Expand All @@ -109,3 +118,11 @@ func (c *Config) Listen(network, address string) (Listener, error) {

return NewListener(config)
}

func (c *Config) Logger() *log.Logger {
if c.OverrideLogger != nil {
return c.OverrideLogger
}

return log.GetDefaultLogger()
}
12 changes: 5 additions & 7 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ import (

func TestConfigClone(t *testing.T) {
c := &water.Config{
TMBin: make([]byte, 256),
NetworkDialerFunc: nil, // functions aren't deeply equal unless nil
NetworkListener: &net.TCPListener{},
TMConfig: water.TMConfig{
FilePath: "/tmp/watm.toml",
},
TransportModuleBin: make([]byte, 256),
NetworkDialerFunc: nil, // functions aren't deeply equal unless nil
NetworkListener: &net.TCPListener{},
TransportModuleConfig: water.TransportModuleConfigFromBytes([]byte("foo")),
}

_, err := rand.Read(c.TMBin)
_, err := rand.Read(c.TransportModuleBin)
if err != nil {
t.Fatalf("rand.Read error: %v", err)
}
Expand Down
Loading

0 comments on commit 3bebb48

Please sign in to comment.