Documentation
¶
Overview ¶
Package client is a Go Socket.IO client. It connects to a Socket.IO server (this module's server or the Node reference server) over the WebSocket transport and provides the familiar On/Emit/EmitWithAck API that mirrors the browser socket.io-client, letting a Go process act as a first-class Socket.IO peer rather than merely a server:
c, err := client.Dial("http://localhost:3000")
c.On("news", func(args []any) []any { fmt.Println(args); return nil })
c.Emit("hello", "world")
Use it whenever a Go program needs to talk to a Socket.IO endpoint as a client: integration and end-to-end tests against a running server, service-to- service messaging where the other side already speaks Socket.IO, bots and load generators, or bridging a Socket.IO event stream into another system. Dial blocks until the Socket.IO CONNECT handshake for the chosen namespace completes (or DialTimeout elapses), so a successful return means the client is fully connected and ready to Emit. Optional authentication data is sent with the CONNECT packet via Options.Auth, matching the server-side socket.Auth().
Under the hood the client speaks Engine.IO v4 directly over a single WebSocket (it does not use HTTP long-polling): it dials ws(s)://.../socket.io/ with EIO=4&transport=websocket, reads the Engine.IO OPEN handshake, sends the Socket.IO CONNECT packet, and then runs a background read loop that answers heartbeat pings, dispatches inbound EVENT packets to handlers registered with On, and resolves acknowledgements. Outgoing events are encoded with the shared socketio packet codec, so binary ([]byte) arguments are automatically split into BINARY_EVENT attachment frames and reassembled on receipt.
Concurrency and lifecycle: On, Emit, EmitWithAck, and Close are safe to call from multiple goroutines. Handlers run on the read-loop goroutine, so a handler that itself blocks on EmitWithAck should hand off to another goroutine to avoid deadlocking the loop; returning a non-nil slice from a handler acknowledges an event the server sent with an ack id. EmitWithAck waits up to the supplied timeout and returns an error if no acknowledgement arrives. When Options.Reconnection is enabled, an unexpected transport drop triggers an exponential-backoff reconnect loop (ReconnectionDelay doubling up to five seconds, bounded by ReconnectionAttempts) and fires the local "reconnect" event; a user-initiated Close suppresses reconnection.
Compared with the JavaScript socket.io-client the surface is intentionally small: one namespace per Client, no long-polling fallback, and lifecycle events surfaced as ordinary events ("disconnect", "reconnect") registered through On. The wire protocol is identical, so this client interoperates with the Node reference server and with this module's server package. For multi-namespace usage, Dial a separate Client per namespace.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Backoff ¶ added in v0.3.0
type Backoff struct {
// contains filtered or unexported fields
}
Backoff computes an exponentially increasing delay with optional jitter, mirroring the JavaScript client's backo2 module used for reconnection. Each call to Duration returns the delay for the current attempt and advances the attempt counter; Reset returns to the initial delay. A Backoff is safe for concurrent use.
func NewBackoff ¶ added in v0.3.0
func NewBackoff(opts BackoffOptions) *Backoff
NewBackoff creates a Backoff from the supplied options, filling in defaults for any zero field.
func (*Backoff) Attempts ¶ added in v0.3.0
Attempts returns how many times Duration has been called since the last Reset.
type BackoffOptions ¶ added in v0.3.0
type BackoffOptions struct {
// Min is the initial delay (default 100ms).
Min time.Duration
// Max is the ceiling the delay is clamped to (default 10s).
Max time.Duration
// Factor is the exponential growth base per attempt (default 2).
Factor float64
// Jitter is the randomization fraction in [0,1]; 0 disables jitter. A value
// of 0.5 spreads each delay by up to ±50%. Jitter is only applied when Rand
// is non-nil, keeping a default Backoff fully deterministic.
Jitter float64
// Rand supplies the randomness used for jitter; it must return a value in
// [0,1). Inject a deterministic function in tests, or math/rand's Float64 in
// production. When nil, no jitter is applied.
Rand func() float64
}
BackoffOptions configures a Backoff. The zero value yields sensible defaults (100ms initial, 10s ceiling, factor 2, no jitter).
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a connected Socket.IO client.
func Dial ¶
Dial connects to a Socket.IO server at rawURL (http:// or ws://) and returns once the Socket.IO CONNECT handshake completes.
Example ¶
ExampleDial demonstrates the full lifecycle of a Go Socket.IO client. It calls Dial to connect to a running server, passing Options to select a namespace and to enable automatic reconnection; Dial blocks until the CONNECT handshake completes, so a nil error means the client is ready to use. The example then registers a handler for the server-pushed "news" event with On, sends a fire-and-forget event with Emit, and issues a request/response round-trip with EmitWithAck that waits up to five seconds for the server's acknowledgement. Finally it closes the connection with a deferred Close, which also suppresses any pending reconnection. The reader should take away how a Go program becomes a first-class Socket.IO peer using the same On/Emit/EmitWithAck vocabulary as the browser client. (This example is compiled to verify the API but is not run here, since it needs a live server to connect to.)
package main
import (
"fmt"
"log"
"time"
"github.com/malcolmston/socketio/client"
)
func main() {
c, err := client.Dial("http://localhost:3000", client.Options{
Namespace: "/",
Auth: map[string]any{"token": "s3cret"},
Reconnection: true,
})
if err != nil {
log.Fatal(err)
}
defer c.Close()
// Handle events the server pushes to us.
c.On("news", func(args []any) []any {
fmt.Println("news:", args)
return nil
})
// Fire-and-forget emit.
if err := c.Emit("hello", "world"); err != nil {
log.Fatal(err)
}
// Request/response with an acknowledgement.
reply, err := c.EmitWithAck("question", 5*time.Second, "what is 2+2?")
if err != nil {
log.Fatal(err)
}
fmt.Println("answer:", reply)
}
Output:
func (*Client) EmitWithAck ¶
EmitWithAck sends an event and waits for the server's acknowledgement, up to timeout.
type Handler ¶
Handler handles an inbound event. Returning a non-nil slice acknowledges an event the server sent with an ack id.
type Options ¶
type Options struct {
// Namespace to connect to (default "/").
Namespace string
// Auth is an optional payload sent with the CONNECT packet.
Auth any
// DialTimeout bounds the connection handshake (default 10s).
DialTimeout time.Duration
// Reconnection enables automatic reconnection after an unexpected
// disconnect.
Reconnection bool
// ReconnectionAttempts bounds reconnection tries (0 = unlimited).
ReconnectionAttempts int
// ReconnectionDelay is the initial backoff between attempts (default 1s,
// doubling up to 5s).
ReconnectionDelay time.Duration
}
Options configures Dial.