diff --git a/runtime/go/go.md b/runtime/go/go.md index c12ccbc..d7b66ed 100644 --- a/runtime/go/go.md +++ b/runtime/go/go.md @@ -13,78 +13,4 @@ permalink: /runtime/go.html `water` (a.k.a. `water-go` in contrast to `water-rs`) is a WATER Runtime Library build in Go. It uses the WebAssembly runtime with WASI support from [wazero](https://github.com/tetratelabs/wazero), and implements an abstracted network programming interface that roughly ressembles the standard `net` package in Go. ## Cross-platform Support -Project WATER is designed to be cross-platform and cross-architecture. See [Cross-platform Compatibility (Go)](./go/cross-platform.html) for more details. - -## Usage - -### Importing `water` -To use `water` in a Go project, simply import it as a module. - -By default, `water` does not recognize any transport modules as there can be many different -specifications of transport modules. To use a specific transport module, import its implementation -as well. - -```go -import ( - "github.com/refraction-networking/water" - _ "github.com/refraction-networking/water/transport/v0" // import the v0 transport module spec -) -``` - -### Working Mode: Dialer -Dialer acts like a client. It actively creates connections to a remote server (and usually is the one who sends the first message). - -```go -// ... - - // Load the WebAssembly binary into wasm as []byte. - // The rest of the code on this page assumes that wasm is already loaded. - wasm, _ := os.ReadFile("./examples/v0/plain/plain.wasm") - - config := &water.Config{ - TransportModuleBin: wasm, - } - - dialer, _ := water.NewDialerWithContext(context.Background(), config) - conn, _ := dialer.DialContext(context.Background(),"tcp", remoteAddr) - -// ... -``` - -### Working Mode: Listener -Listener acts like a server. It listens on a network address and wait for -incoming connections to accept. - -```go - lis, _ := config.ListenContext(context.Background(), "tcp", localAddr) - defer lis.Close() - log.Printf("Listening on %s", lis.Addr().String()) - - for { - conn, err := lis.Accept() - handleConn(conn) - } -``` - -### Working Mode: Relay -A relay combines the functionalities of both a dialer and a listener. It works -like a forward proxy, accepting connections from a client and forwarding them to a -remote server by dialing a connection to the remote server. - -```go - relay, _ := water.NewRelayWithContext(context.Background(), config) - - relay.ListenAndRelayTo("tcp", localAddr, "tcp", remoteAddr) // blocking -``` - -## Troubleshooting - -### Enable `wazero` debug logs - -`wazero` is the WebAssembly runtime with WASI support that `water` uses. To enable debug logs from `wazero`, pass the values below via the `context.Context` - -```go - // example of enabling FileSystem, Poll, and Sock logging scopes of wazero - ctx = context.WithValue(ctx, experimental.FunctionListenerFactoryKey{}, - logging.NewHostLoggingListenerFactory(os.Stderr, logging.LogScopeFilesystem|logging.LogScopePoll|logging.LogScopeSock)) -``` \ No newline at end of file +Project WATER is designed to be cross-platform and cross-architecture. See [Cross-platform Compatibility (Go)](./go/cross-platform.html) for more details. \ No newline at end of file diff --git a/runtime/go/troubleshoot.md b/runtime/go/troubleshoot.md new file mode 100644 index 0000000..14445d2 --- /dev/null +++ b/runtime/go/troubleshoot.md @@ -0,0 +1,18 @@ +--- +layout: default +title: Troubleshooting (Go) +grand_parent: Runtime Library +parent: Runtime Library in Go +nav_order: 2 +--- +# Troubleshooting + +## Enable `wazero` debug logs + +`wazero` is the WebAssembly runtime with WASI support that `water` uses. To enable debug logs from `wazero`, pass the values below via the `context.Context` + +```go +// example of enabling FileSystem, Poll, and Sock logging scopes of wazero +ctx = context.WithValue(ctx, experimental.FunctionListenerFactoryKey{}, + logging.NewHostLoggingListenerFactory(os.Stderr, logging.LogScopeFilesystem|logging.LogScopePoll|logging.LogScopeSock)) +``` \ No newline at end of file diff --git a/runtime/go/usage.md b/runtime/go/usage.md new file mode 100644 index 0000000..962a9f5 --- /dev/null +++ b/runtime/go/usage.md @@ -0,0 +1,65 @@ +--- +layout: default +title: Usage (Go) +grand_parent: Runtime Library +parent: Runtime Library in Go +nav_order: 3 +--- +# Usage + +## Importing `water` +To use `water` in a Go project, simply import it as a module. + +By default, `water` does not recognize any transport modules as there can be many different +specifications of transport modules. To use a specific transport module, import its implementation +as well. + +```go +import ( + "github.com/refraction-networking/water" + _ "github.com/refraction-networking/water/transport/v0" // import the v0 transport module spec +) +``` + +## Working Modes + +### Dialer +Dialer acts like a client. It actively creates connections to a remote server (and usually is the one who sends the first message). + +```go +// Load the WebAssembly binary into wasm as []byte. +// The rest of the code on this page assumes that wasm is already loaded. +wasm, _ := os.ReadFile("./examples/v0/plain/plain.wasm") + +config := &water.Config{ + TransportModuleBin: wasm, +} + +dialer, _ := water.NewDialerWithContext(context.Background(), config) +conn, _ := dialer.DialContext(context.Background(),"tcp", remoteAddr) +``` + +### Listener +Listener acts like a server. It listens on a network address and wait for +incoming connections to accept. + +```go +lis, _ := config.ListenContext(context.Background(), "tcp", localAddr) +defer lis.Close() +log.Printf("Listening on %s", lis.Addr().String()) + +for { + conn, err := lis.Accept() + handleConn(conn) +} +``` + +### Relay +A relay combines the functionalities of both a dialer and a listener. It works +like a forward proxy, accepting connections from a client and forwarding them to a +remote server by dialing a connection to the remote server. + +```go +relay, _ := water.NewRelayWithContext(context.Background(), config) +relay.ListenAndRelayTo("tcp", localAddr, "tcp", remoteAddr) // blocking +``` \ No newline at end of file diff --git a/transport-module/spec.md b/transport-module/spec.md index f207654..16db84f 100644 --- a/transport-module/spec.md +++ b/transport-module/spec.md @@ -19,8 +19,8 @@ WATM imports the following functions from the host environment: | --- | --- | --- | --- | |`host_dial` | - | `net_fd: s32` | Ask the host to connect to a remote server. | | `host_accept` | - | `net_fd: s32` | Ask the host to accept an incoming connection. | -| ~~`host_defer`~~ | - | - | ~~Ask the host to defer the execution of the current function.~~ Deprecated: this function is equal to `NOP`. | | `pull_config`* | - | `conf_fd: s32` | Ask the host to provide the configuration file. | +| ~~`host_defer`~~ | - | - | ~~Ask the host to defer the execution of the current function.~~ Deprecated: this function is equal to `NOP`. | ### Exports @@ -28,7 +28,9 @@ WATM exports the following functions to the host environment: | Function Signature | Parameters | Results | Description | | --- | --- | --- | --- | +| `_water_v0` | - | - | Version 0 identifier. | | `_water_init` | - | `errno: s32` | Initialize the transport module. | +| `_water_cancel_with` | `cancel_fd: s32` | `errno: s32` | Cancel the operation with the given file descriptor. | | `_water_dial` | `internal_fd: s32` | `net_fd: s32` | Connect to a remote server. | | `_water_accept` | `internal_fd: s32` | `net_fd: s32` | Accept an incoming connection. | | `_water_associate` | - | `errno: s32` | Associate the transport module with the host environment. | @@ -41,7 +43,55 @@ To help developers understand the API, we provide the following representations (planned feature) ### Go representation -(to be added) + +
+ Imports + +```go +//go:wasmimport env host_dial +//go:noescape +func _import_host_dial() (fd int32) + +//go:wasmimport env host_accept +//go:noescape +func _import_host_accept() (fd int32) + +//go:wasmimport env pull_config +//go:noescape +func _import_pull_config() (fd int32) + +//go:wasmimport env host_defer +//go:noescape +func _import_host_defer() +``` +
+ +
+ Exports + +```go +//export _water_v0 +func _water_v0() + +//export _water_init +func _water_init() + +//export _water_cancel_with +func _water_cancel_with(cancelFd int32) int32 + +//export _water_dial +func _water_dial(internalFd int32) (networkFd int32) + +//export _water_accept +func _water_accept(internalFd int32) (networkFd int32) + +//export _water_associate +func _water_associate() int32 + +//export _water_worker +func _water_worker() int32 +``` +
### Rust representation (to be added) @@ -51,7 +101,9 @@ Similarly, such API can be represented in WIT. _Note that the following is a simplified example and may not strictly follow the WIT syntax. In other words, we do not guarantee the following code to be compilable._ -#### Imported Functions +
+ Imports + ```wit // imports.wit package env; @@ -59,27 +111,33 @@ package env; interface host { host_dial: func() -> (net_fd: s32); host_accept: func() -> (net_fd: s32); - host_defer: func(); // deprecated pull_config: func() -> (conf_fd: s32); + host_defer: func(); // deprecated } world host-world { import host; } ``` +
+ +
+ Exports -#### Exported Functions ```wit // exports.wit interface wasm { - _water_init: func() -> (errno: s32) - _water_dial: func(internal_fd: s32) -> (net_fd: s32); - _water_accept: func(internal_fd: s32) -> (net_fd: s32); + _water_v0: func(); // version 0 identifier + _water_init: func() -> (errno: s32); + _water_cancel_with(cancel_fd: s32) -> (errno: s32); + _water_dial: func(internal_fd: s32) -> (net_fd: s32); + _water_accept: func(internal_fd: s32) -> (net_fd: s32); _water_associate: func() -> (errno: s32); - _water_worker: func() -> (errno: s32); + _water_worker: func() -> (errno: s32); } world wasm-world { export wasm; } -``` \ No newline at end of file +``` +
\ No newline at end of file