-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[water-api] new API design draft #2
Merged
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
dc13170
update: major revision
gaukas 424f2eb
update: add notes for SetReadDeadline
gaukas c3e5aba
refactor: move RuntimeConn definition
gaukas a74ad4b
update: refactor structs
gaukas 4586b79
update: revise Dialer and Listener procedures
gaukas 9dc2f53
fix: major crashing bugs
gaukas cf8b702
fix: abandon windows
gaukas 5e25397
new: adding benchmark
gaukas ba2c15a
new: dirty fix GO GC bug
gaukas c35ebd8
update: doc, ci check, cleanup
gaukas bed9bec
new: v0 final prototype
gaukas 385c51f
update: new v0 specs
gaukas 9813cf1
fix: minor bug and redundancy
gaukas 04037d3
fix: external caller can't set WASIConfigFactory
gaukas d8b9130
fix: typo
gaukas acea150
fix: broken interface
gaukas 9a09ce4
Merge branch 'master' into dev
gaukas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,21 @@ | ||
package water | ||
|
||
type Config struct { | ||
// WASI contains the compiled WASI binary in bytes. | ||
WASI []byte | ||
|
||
// Dialer is used to dial a network connection. | ||
Dialer Dialer | ||
Dialer Dialer // A dialer supporting multiple network types. | ||
Feature Feature // Bit-masked experimental features | ||
WABin []byte // WebAssembly module binary. | ||
WAConfig []byte // WebAssembly module config file, if any. | ||
} | ||
|
||
// init() checks if the Config is valid and initializes | ||
// the Config with default values if optional fields are not provided. | ||
// complete the config by filling in the missing optional fields | ||
// with fault values and panic if any of the required fields are not | ||
// provided. | ||
func (c *Config) init() { | ||
if len(c.WASI) == 0 { | ||
panic("water: WASI binary is not provided") | ||
} | ||
|
||
if c.Dialer == nil { | ||
c.Dialer = DefaultDialer() | ||
} | ||
|
||
if len(c.WABin) == 0 { | ||
panic("water: WASI binary is not provided") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package water | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
|
||
"github.com/bytecodealliance/wasmtime-go/v12" | ||
) | ||
|
||
// RuntimeConn defines an interface that all implementations of RuntimeConn | ||
// must implement no matter of which version it is. | ||
type RuntimeConn interface { | ||
net.Conn | ||
} | ||
|
||
// runtimeCore provides the WASM runtime base and is an internal struct | ||
// that every RuntimeXxx implementation will embed. | ||
type runtimeCore struct { | ||
// wasmtime | ||
engine *wasmtime.Engine | ||
module *wasmtime.Module | ||
store *wasmtime.Store | ||
linker *wasmtime.Linker | ||
instance *wasmtime.Instance | ||
|
||
// wasi imports | ||
deferFuncs []func() // defer functions to be called by WASM module on exit | ||
|
||
// wasi exports | ||
_init *wasmtime.Func | ||
_version *wasmtime.Func | ||
|
||
// other wasi related stuff | ||
wd *WasiDialer | ||
} | ||
|
||
func NewCore() *runtimeCore { | ||
return &runtimeCore{} | ||
} | ||
|
||
func (c *runtimeCore) Defer(f func()) { | ||
c.deferFuncs = append(c.deferFuncs, f) | ||
} | ||
|
||
func (c *runtimeCore) linkDefer() error { | ||
if c.linker == nil { | ||
return fmt.Errorf("linker not set") | ||
} | ||
|
||
if err := c.linker.DefineFunc(c.store, "env", "defer", c._defer); err != nil { | ||
return fmt.Errorf("(*wasmtime.Linker).DefineFunc: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *runtimeCore) linkDialer(dialer Dialer, address string) error { | ||
if c.linker == nil { | ||
return fmt.Errorf("linker not set") | ||
} | ||
|
||
if dialer == nil { | ||
return fmt.Errorf("dialer not set") | ||
} | ||
|
||
if c.wd == nil { | ||
c.wd = NewWasiDialer(address, dialer, c.store) | ||
} else { | ||
return fmt.Errorf("wasi dialer already set, double-linking?") | ||
} | ||
|
||
if err := c.linker.DefineFunc(c.store, "env", "dial", c.wd.WasiDialerFunc); err != nil { | ||
return fmt.Errorf("(*wasmtime.Linker).DefineFunc: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *runtimeCore) initializeConn() (RuntimeConn, error) { | ||
// get _init and _version functions | ||
c._init = c.instance.GetFunc(c.store, "_init") | ||
if c._init == nil { | ||
return nil, fmt.Errorf("instantiated WASM module does not export _init function") | ||
} | ||
c._version = c.instance.GetFunc(c.store, "_version") | ||
if c._version == nil { | ||
return nil, fmt.Errorf("instantiated WASM module does not export _version function") | ||
} | ||
|
||
// initialize WASM instance. | ||
// In a _init() call, the WASM module will setup all its internal states | ||
_, err := c._init.Call(c.store) | ||
if err != nil { | ||
return nil, fmt.Errorf("errored upon calling _init function: %w", err) | ||
} | ||
|
||
// get version | ||
// In a _version() call, the WASM module will return its version | ||
ret, err := c._version.Call(c.store) | ||
if err != nil { | ||
return nil, fmt.Errorf("errored upon calling _version function: %w", err) | ||
} | ||
if ver, ok := ret.(int32); !ok { | ||
return nil, fmt.Errorf("_version function returned non-int32 value") | ||
} else { | ||
return RuntimeConnWithVersion(c, ver) | ||
} | ||
} | ||
|
||
func (c *runtimeCore) _defer() { | ||
for _, f := range c.deferFuncs { | ||
f() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package main | ||
|
||
import ( | ||
"crypto/rand" | ||
"fmt" | ||
"net" | ||
"os" | ||
"sync" | ||
) | ||
|
||
func main() { | ||
// get temp dir | ||
tempDir := os.TempDir() | ||
// append OS-specific path separator | ||
tempDir += string(os.PathSeparator) | ||
// randomize a socket name | ||
randBytes := make([]byte, 16) | ||
if _, err := rand.Read(randBytes); err != nil { | ||
panic(fmt.Errorf("water: rand.Read returned error: %w", err)) | ||
} | ||
tempDir += fmt.Sprintf("%x", randBytes) | ||
|
||
// create a one-time use UnixListener | ||
ul, err := net.Listen("unix", tempDir) | ||
if err != nil { | ||
panic(fmt.Errorf("water: net.Listen returned error: %w", err)) | ||
} | ||
defer ul.Close() | ||
|
||
var waConn net.Conn | ||
var wg *sync.WaitGroup = new(sync.WaitGroup) | ||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
var err error | ||
waConn, err = ul.Accept() | ||
if err != nil { | ||
panic(fmt.Errorf("water: ul.Accept returned error: %w", err)) | ||
} | ||
}() | ||
|
||
// dial the one-time use UnixListener | ||
uc, err := net.Dial("unix", ul.Addr().String()) | ||
if err != nil { | ||
panic(fmt.Errorf("water: net.Dial returned error: %w", err)) | ||
} | ||
defer uc.Close() | ||
wg.Wait() | ||
|
||
// write to uc, read from waConn | ||
uc.Write([]byte("hello")) | ||
buf := make([]byte, 128) | ||
n, err := waConn.Read(buf) | ||
if err != nil { | ||
panic(fmt.Errorf("water: waConn.Read returned error: %w", err)) | ||
} | ||
fmt.Printf("read %d bytes from waConn: %s\n", n, string(buf[:n])) | ||
|
||
// write to waConn, read from uc | ||
waConn.Write([]byte("world")) | ||
n, err = uc.Read(buf) | ||
if err != nil { | ||
panic(fmt.Errorf("water: uc.Read returned error: %w", err)) | ||
} | ||
fmt.Printf("read %d bytes from uc: %s\n", n, string(buf[:n])) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package water | ||
|
||
type Feature uint64 | ||
|
||
// Feature is a bit mask of experimental features of WATER. | ||
const ( | ||
FEATURE_DUMMY Feature = 1 << iota // a dummy feature that does nothing. | ||
FEATURE_RESERVED // reserved for future use | ||
// ... | ||
FEATURE_CWAL Feature = 0xFFFFFFFFFFFFFFFF // CWAL = Can't Wait Any Longer | ||
FEATURE_NONE Feature = 0 // NONE = No Experimental Features | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
module github.com/gaukas/water | ||
|
||
go 1.21.0 | ||
go 1.18 | ||
|
||
require github.com/bytecodealliance/wasmtime-go/v11 v11.0.0 | ||
replace github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 => github.com/refraction-networking/wasmtime-go/v12 v12.0.0 | ||
|
||
require github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
github.com/bytecodealliance/wasmtime-go/v11 v11.0.0 h1:SwLgbjbFpQ1tf5vIbWexaZABezBSL8WmzP+foLyi0lE= | ||
github.com/bytecodealliance/wasmtime-go/v11 v11.0.0/go.mod h1:9btfEuCkOP7EDR9a7LqDXrfQ7dtWeGlDHt3buV5UyjY= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/refraction-networking/wasmtime-go/v12 v12.0.0 h1:crB/5HgsjL5OvfXwCT6YthaoL19tDYdK3R6NOKw42n8= | ||
github.com/refraction-networking/wasmtime-go/v12 v12.0.0/go.mod h1:xLry3QSj/6qi3uMlhbeCoJhf2gWtuXfNTS6TKhz9M+s= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not too sure how Go handles function with no return, but I forgot to add a check for it if there is no return value for the _version function in Rust previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From
func (*Func) Call()
's definition.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But let's forget about the multi-value for V0 (version in terms of of water API). It is not FFI-friendly and we don't take risks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's way neater in Go, not like Rust, you need to pass in a
&mut [Val]
with the exact length of the return values, otherwise it will fail the call.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the behavior then? Returning some bad values, an error (a
trap
), orpanic
the entire host program (that's the worst)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah,
it will panic the the entire host 🫠, it's returning aResult<Err(E)>
if I do.unwrap()
or?
then it will panic the host where it's actually avoidable by adding some handling code for that case. But currently I'm passing something like this to the call to avoid it.