net
net copied to clipboard
Compatibility with Gorilla Websockets
Hi!
I've been trying to compile some of the example netcode in the gorilla/websockets project using the net
extensions package. Specifically I'm going with the fairly straightforward echo server example at https://github.com/gorilla/websocket/tree/main/examples/echo.
I have no issues when I try to replace the server code (in server.go
) with the wasip1
bindings, I just swap a single err := server.ListenAndServe()
line out and replace it with a call to wasip1.Listen
along with a follow-up definition of an http.Server
and call to .Serve()
. I can use wasirun
to execute the example perfectly by building with GOOS=wasip1 GOARCH=wasm go build -o server.wasm server.go
and then running wasirun server.wasm
. It works perfectly!
When I try to replace the client code however, I run into some weirdness. I'm including the entire file of client.go
here after my changes:
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
// +build ignore
package main
import (
"flag"
"github.com/stealthrocket/net/wasip1"
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
var addr = flag.String("addr", "127.0.0.1:8080", "http service address")
func main() {
flag.Parse()
log.SetFlags(0)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
log.Printf("connecting to %s", u.String())
dialer := websocket.DefaultDialer
dialer.NetDialContext = wasip1.DialContext
dialer.NetDialTLSContext = wasip1.DialContext
c, _, err := dialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
done := make(chan struct{})
go func() {
defer close(done)
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s, type: %s", message, websocket.FormatMessageType(mt))
}
}()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case t := <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}
The key change I've tried to make here is that I've swapped:
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
into
dialer := websocket.DefaultDialer
dialer.NetDialContext = wasip1.DialContext
dialer.NetDialTLSContext = wasip1.DialContext
c, _, err := dialer.Dial(u.String(), nil)
From what I can tell in the codebase at https://github.com/gorilla/websocket/blob/main/client.go#L255-L277 - this should be the right place to be replacing the dial contexts, though I'm not certain.
I compile the code with GOOS=wasip1 GOARCH=wasm go build -o client.wasm client.go
and then try running it with wasirun --trace --dial 127.0.0.1:8080 --sockets=auto --non-blocking-stdio client.wasm
. It hangs for a while and then the connection times out. What's interesting is that it only hangs if the server is listening, otherwise I get an immediate dial:dial tcp 127.0.0.1:8080: connect: Connection refused
error. And after it times out (dial:read tcp 127.0.0.1:60849->127.0.0.1:8080: i/o timeout
) I can see the server warn me that a connection to it has been reset, read: read tcp 127.0.0.1:8080->127.0.0.1:60849: fd_read: Connection reset by peer
. So it looks like this is at least partially working, but I'm not quite sure why it's hanging and timing out. Maybe there's an issue with threading I need to figure out how to avoid?
Any tips on how to proceed further / am I using the package incorrectly?
Cheers!