A Go WebSocket client with optional automatic reconnection, designed for use with wspulse/server.
Status: v0 — API is being stabilized. Module path: github.com/wspulse/client-go.
- Thin client: connect, send, receive, auto-reconnect
- Matches server-side
FrameandCodectypes via wspulse/core - Exponential backoff with configurable retries
- Transport drop vs. permanent disconnect callbacks
go get github.com/wspulse/client-goimport (
wspulse "github.com/wspulse/core"
client "github.com/wspulse/client-go"
)
c, err := client.Dial("ws://localhost:8080/ws?room=r1&token=xyz",
client.WithOnMessage(func(f wspulse.Frame) {
fmt.Printf("[%s] %s\n", f.Event, f.Payload)
}),
client.WithAutoReconnect(5, time.Second, 30*time.Second),
)
if err != nil {
log.Fatal(err)
}
defer c.Close()
c.Send(wspulse.Frame{Event: "msg", Payload: []byte(`{"text":"hello"}`)})
<-c.Done()Every frame sent or received is a JSON object on the wire:
{
"id": "msg-001",
"event": "chat.message",
"payload": { "text": "hello" }
}The "event" field is the routing key on the server. Set frame.Event to match the handler registered with r.On("chat.message", ...) on the server side. The "payload" field carries arbitrary JSON — the library does not inspect it.
// Send a typed frame — server routes by "event"
c.Send(wspulse.Frame{
Event: "chat.message",
Payload: []byte(`{"text":"hello world"}`),
})
// Receive typed frames
client.WithOnMessage(func(f wspulse.Frame) {
switch f.Event {
case "chat.message":
// handle message
case "chat.ack":
// handle acknowledgement
case "pong":
// heartbeat response
}
})core/router provides Gin-style middleware and per-event handler dispatch. When using the client, pass nil as the connection (client frames have no server-side Connection concept).
import (
wspulse "github.com/wspulse/core"
"github.com/wspulse/core/router"
client "github.com/wspulse/client-go"
)
rtr := router.New()
rtr.Use(router.Recovery())
rtr.On("chat.message", func(c *router.Context) {
fmt.Printf("[msg] %s\n", c.Frame.Payload)
})
rtr.On("chat.welcome", func(c *router.Context) {
fmt.Println("joined!")
})
c, _ := client.Dial("ws://localhost:8080/ws?room=r1&token=xyz",
client.WithOnMessage(func(f wspulse.Frame) {
rtr.Dispatch(nil, f) // no router.Connection on the client side
}),
client.WithAutoReconnect(5, time.Second, 30*time.Second),
)
defer c.Close()See wspulse/core for the full router API.
| Symbol | Description |
|---|---|
Client |
Interface: Send, Close, Done |
Dial(url, ...) |
Connect and return a Client |
ClientOption |
Functional option type |
| Option | Default |
|---|---|
WithOnMessage(fn) |
— |
WithOnTransportRestore(fn) |
— |
WithOnDisconnect(fn) |
— |
WithOnTransportDrop(fn) |
— |
WithAutoReconnect(max, base, maxDelay) |
disabled |
WithHeartbeat(ping, pong, writeWait) |
20s / 60s / 10s |
WithMaxMessageSize(n) |
1 MiB |
WithCodec(c) |
JSONCodec |
WithDialHeaders(h) |
— |
WithLogger(l) |
zap.NewProduction() |
The client logs internal diagnostics via zap. By default a production logger is used (JSON format, Info+ level).
Replace the logger with your own:
c, _ := client.Dial(url, client.WithLogger(myZapLogger))Disable logging:
c, _ := client.Dial(url, client.WithLogger(zap.NewNop()))- Auto-reconnect — exponential backoff with configurable max retries, base delay, and max delay.
- Transport drop callback —
WithOnTransportDropfires on every transport death, even when auto-reconnect follows. Useful for metrics. - Permanent disconnect callback —
WithOnDisconnectfires only when the client is truly done (Close() called or retries exhausted). - Panic recovery — panics in
OnMessageare recovered; the connection is dropped but the process survives. - Heartbeat — client-side Ping/Pong keeps the connection alive and detects silently-dead servers.
- Backpressure — bounded send buffer;
ErrSendBufferFullreturned when full. - Swappable codec — JSON by default; plug in any
Codecimplementation.
make fmt # auto-format source files (gofmt + goimports)
make check # validate format, lint, test with race detector (pre-commit gate)
make test # go test -race -count=3 ./...
make test-cover # go test with coverage report → coverage.html
make bench # run benchmarks with memory allocation stats
make tidy # go mod tidy (GOWORK=off)
make clean # remove build artifacts and test cache- wspulse/server — WebSocket server library