Skip to content

Commit 638eb8b

Browse files
README: update documentation
Signed-off-by: Achille Roussel <[email protected]>
1 parent 84893e0 commit 638eb8b

File tree

3 files changed

+83
-70
lines changed

3 files changed

+83
-70
lines changed

README.md

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,102 @@
11
# net
22

3-
This library provides `net.Dial` and `net.Listen` functions
4-
for `GOOS=wasip1`
3+
This library provides `net.Dial` and `net.Listen` functions for
4+
[`GOOS=wasip1`][wasip1].
55

6-
Applications built with this library are compatible with WasmEdge
7-
and [stealthrocket/wasi-go](https://github.com/stealthrocket/wasi-go).
6+
Applications built with this library are compatible with [WasmEdge][wasmedge]
7+
and [stealthrocket/wasi-go][wasi-go].
88

9-
## Dialing
9+
[wasi-go]: https://github.com/stealthrocket/wasi-go
10+
[wasip1]: https://tip.golang.org/doc/go1.21#wasip1
11+
[wasmedge]: https://github.com/WasmEdge/WasmEdge
1012

11-
The library will automatically configure the default HTTP transport
12-
to use the `Dial` function from this library.
13+
## Motivation
1314

14-
To make outbound HTTP connections you just need the following import somewhere:
15+
The WASI preview 1 specification has partial support for socket networking,
16+
preventing a large class of Go applications from running when compiled to
17+
WebAssembly with `GOOS=wasip1`. Extensions to the base specifications have been
18+
implemented by runtimes to enable a wider range of programs to be run as
19+
WebAssembly modules.
1520

16-
```go
17-
import _ "github.com/stealthrocket/net"
18-
```
21+
This package aims to offset Go applications built with `GOOS=wasip1` the
22+
opportunity to leverage those WASI extensions, by providing high level functions
23+
similar to those found in the standard `net` package to create network clients
24+
and servers.
1925

20-
To connect to databases, there's usually a way to pass in a custom `Dial`
21-
function.
26+
## Configuration
2227

23-
For example, to connect to MySQL:
28+
Where possible, the package offers the ability to automatically configure the
29+
network stack via `init` functions called on package imports. This model is
30+
currently supported for `http` and `mysql` with those imports:
2431

2532
```go
26-
import (
27-
"context"
33+
import _ "github.com/stealthrocket/net/http"
34+
```
35+
```go
36+
import _ "github.com/stealthrocket/net/mysql"
37+
```
2838

29-
"github.com/go-sql-driver/mysql"
30-
"github.com/stealthrocket/net"
31-
)
39+
When imported, those packages alter the default configuration to install a
40+
dialer function implemented on top of the WASI socket extensions. When compiled
41+
to other targets, the import of those packages does nothing.
3242

33-
func init() {
34-
for _, network := range []string{"tcp", "tcp4", "tcp6"} {
35-
mysql.RegisterDialContext(network, func(ctx context.Context, addr string) (net.Conn, error) {
36-
return net.Dial(network, addr)
37-
})
38-
}
39-
}
43+
## Dialing
4044

41-
func main() {
42-
db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/database")
43-
}
44-
```
45+
Packages implementing network clients for various protocols usually support
46+
configuration through the installation of an alternative dial function allowing
47+
the application to customize how network connections are established.
4548

46-
and to connect to Redis:
49+
The `wasip1` sub-package provides dial functions matching the signature of those
50+
implemented in the standard `net` package to integrate with those configuration
51+
mechanisms.
4752

48-
```go
49-
import (
50-
"github.com/redis/go-redis/v9"
51-
"github.com/stealthrocket/net"
52-
)
53+
The sub-modules contain examples of how to configure popular Go libraries to
54+
leverage the dial functions of `wasip1`. Here is an example for a Redis client:
5355

54-
func main() {
55-
db := redis.NewClient(&redis.Options{
56-
Addr: "127.0.0.1:6379",
57-
Dialer: net.DialContext,
58-
})
59-
}
56+
```go
57+
client := redis.NewClient(&redis.Options{
58+
Addr: "localhost:6379",
59+
Dialer: wasip1.DialContext, // change the dial function to use socket extensions
60+
})
6061
```
6162

6263
## Listening
6364

64-
HTTP servers can be created like so:
65+
Network servers can be created using the `wasip1.Listen` function, which mimics
66+
the signature of `net.Listen` but uses WASI socket extensiosn to create the
67+
`net.Listener`.
68+
69+
For example, a program compiled to `GOOS=wasip1` can create a http server by
70+
first constructing a listener and passing it to the server's `Serve` method:
6571

6672
```go
6773
import (
6874
"net/http"
6975

70-
"github.com/stealthrocket/net"
76+
"github.com/stealthrocket/net/wasip1"
7177
)
7278

7379
func main() {
74-
listener, err := net.Listen("tcp", "127.0.0.1:8080")
80+
listener, err := wasip1.Listen("tcp", "127.0.0.1:3000")
7581
if err != nil {
76-
// TODO: handle listen error
82+
...
7783
}
7884
server := &http.Server{
79-
// TODO: setup HTTP server
85+
...
86+
}
87+
if err := server.Serve(listener); err != nil {
88+
...
8089
}
81-
err = server.Serve(listener)
8290
}
8391
```
8492

93+
Note that using convenience functions like `http.ListenAndServe` will not
94+
work since they are hardcoded to depend on the standard `net` package.
95+
8596
## Name Resolution
8697

87-
There are two methods available for resolving a set of IP addresses
88-
for a hostname.
98+
There are two methods available for resolving a set of IP addresses for a
99+
hostname.
89100

90101
### getaddrinfo
91102

@@ -98,6 +109,8 @@ implementation.
98109

99110
Note that `sock_getaddrinfo` may block.
100111

112+
At this time, this is this package defaults to using this approach.
113+
101114
### Pure Go Resolver
102115

103116
The pure Go name resolver is not currently enabled for GOOS=wasip1.
@@ -113,7 +126,7 @@ The library will then automatically configure the `net.DefaultResolver`.
113126
All you need is the following import somewhere in your application:
114127

115128
```go
116-
import _ "github.com/stealthrocket/net"
129+
import _ "github.com/stealthrocket/net/wasip1"
117130
```
118131

119132
You should then be able to use the lookup functions from the standard

wasip1/lookup_wasip1.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,29 @@
33
package wasip1
44

55
import (
6+
"context"
7+
"errors"
68
"net"
79
"os"
810
)
911

12+
func dialResolverNotSupported(ctx context.Context, network, address string) (net.Conn, error) {
13+
// The net.Resolver type makes a call to net.DialUDP to determine which
14+
// resolved addresses are reachable, which does not go through its Dial
15+
// hook. As a result, it is unusable on GOOS=wasip1 because it fails
16+
// even when the Dial function is set because WASI preview 1 does not
17+
// have a mechanism for opening UDP sockets.
18+
//
19+
// Instead of having (often indirect) use of the net.Resolver crash, we
20+
// override the Dial function to error earlier in the resolver lifecycle
21+
// with an error which is more explicit to the end user.
22+
return nil, errors.New("net.Resolver not supported on GOOS=wasip1")
23+
}
24+
25+
func init() {
26+
net.DefaultResolver.Dial = dialResolverNotSupported
27+
}
28+
1029
func lookupAddr(op, network, address string) (net.Addr, error) {
1130
var hints addrInfo
1231
switch network {

wasip1/net_wasip1.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,12 @@
33
package wasip1
44

55
import (
6-
"context"
7-
"errors"
86
"fmt"
97
"net"
108
"os"
119
"syscall"
1210
)
1311

14-
func dialResolverNotSupported(ctx context.Context, network, address string) (net.Conn, error) {
15-
// The net.Resolver type makes a call to net.DialUDP to determine which
16-
// resolved addresses are reachable, which does not go through its Dial
17-
// hook. As a result, it is unusable on GOOS=wasip1 because it fails
18-
// even when the Dial function is set because WASI preview 1 does not
19-
// have a mechanism for opening UDP sockets.
20-
//
21-
// Instead of having (often indirect) use of the net.Resolver crash, we
22-
// override the Dial function to error earlier in the resolver lifecycle
23-
// with an error which is more explicit to the end user.
24-
return nil, errors.New("net.Resolver not supported on GOOS=wasip1")
25-
}
26-
27-
func init() {
28-
net.DefaultResolver.Dial = dialResolverNotSupported
29-
}
30-
3112
func newOpError(op string, addr net.Addr, err error) error {
3213
return &net.OpError{
3314
Op: op,

0 commit comments

Comments
 (0)