actioncable

package module
v0.0.0-...-822e6cf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2026 License: MIT Imports: 20 Imported by: 0

README

actioncable

Go client for Rails' Action Cable.

Installation

go get github.com/basecamp/actioncable-go

Getting started

// Establish a connection
client := actioncable.New("wss://example.com/cable")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

if err := client.Connect(ctx); err != nil {
	return err
}
defer client.Close()

// Subscribe to a channel
room, err := client.Subscribe(ctx, actioncable.Identifier{
	Channel: "RoomChannel",
	Params:  actioncable.Params{"id": 42},
})
if err != nil {
	return err
}

// Listen for incoming messages
go func() {
	for message := range room.Messages() {
		var said struct{ Body string }
		if err := message.Unmarshal(&said); err == nil {
			fmt.Println(said.Body)
		}
	}
}()

// Send messages
if err := room.Perform(ctx, "speak", map[string]any{"body": "Hello!"}); err != nil {
	return err
}

Connect opens a connection and waits for the server to acknowledge. Failed attempts get retried automatically. Pass a context with a deadline to control how long to wait:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

if err := client.Connect(ctx); err != nil {
	var disconnect *actioncable.DisconnectError
	if errors.As(err, &disconnect) && disconnect.Reason == actioncable.ReasonUnauthorized {
		return signInAgain()
	} else {
		return err
	}
}

The errors worth handling:

  • context.DeadlineExceeded or context.Canceled, when the context ends before the welcome arrives. The server hasn't answered yet.
  • *DisconnectError, when the server sends a disconnect message. Reason is one of four strings:
    • ReasonUnauthorized — authentication or authorization failed.
    • ReasonInvalidRequest — the request wasn't a valid Action Cable upgrade.
    • ReasonServerRestart — the Rails server is restarting.
    • ReasonRemote — the app closed this connection with ActionCable.server.disconnect.
  • ErrUnsupportedSubprotocol, when the server picks a protocol this client doesn't speak.

A disconnect message says whether the client should re-connect. Only the ones that say no return an error. The rest are retried, so a server restart shows up in the log and the connection returns on its own.

Subscribe sends the subscription and waits for the channel to confirm it. It returns ErrRejected when the channel's subscribed method rejects it.

Messages closes when the subscription is unsubscribed or the client is closed, so a range loop over it ends on its own.

Read it promptly. A subscription buffers 64 messages, and a message that arrives while the buffer is full gets dropped and logged rather than stalling the connection. Set a bigger buffer if the reader can't keep up with a burst:

client := actioncable.New("wss://example.com/cable",
	actioncable.WithMessageBuffer(1000),
)

The buffer size applies to every subscription on the client.

Authorizing the connection

Action Cable servers can authorize connections using cookies or headers.

Use WithCookie to set a cookie when establishing a connection:

client := actioncable.New("wss://example.com/cable",
	actioncable.WithCookie("_session_id=..."),
)

WithHeader sets any other header:

client := actioncable.New("wss://example.com/cable",
	actioncable.WithHeader(http.Header{"X-Api-Token": {"..."}}),
)

A credential that expires should use WithHeaderFunc, which runs on every reconnect:

client := actioncable.New("wss://example.com/cable",
	actioncable.WithHeaderFunc(func(ctx context.Context) (http.Header, error) {
		token, err := credentials.AccessToken(ctx)
		if err != nil {
			return nil, err
		}
		return http.Header{"Authorization": {"Bearer " + token}}, nil
	}),
)

What it returns is merged over the headers already set, so an Origin or an API token given with WithHeader is kept. An error turns down that dial, and the client tries again on its backoff.

Rails also checks the Origin header and rejects a request that doesn't carry one. By default, the Origin is set to the server's URL, so wss://example.com/cable sends https://example.com.

Set it explicitly when the server sees a different scheme or host than the URL says, behind a proxy that terminates TLS for instance:

client := actioncable.New("wss://example.com/cable",
	actioncable.WithOrigin("http://example.com"),
)

Callbacks

Some channels only send what's new, so a reconnect can leave a gap. Only the client knows a reconnect happened, so Subscribe takes callbacks for the connection events:

room, err := client.Subscribe(ctx, identifier,
	actioncable.OnConnected(func(reconnected bool) {
		if reconnected {
			catchUp()
		}
	}),
	actioncable.OnDisconnected(func(willReconnect bool) { ... }),
	actioncable.OnRejected(func() { ... }),
)

OnConnected runs every time the server confirms the subscription. reconnected is false the first time and true every time after.

OnDisconnected runs when the connection drops. willReconnect says whether the client is coming back or has stopped for good.

OnRejected runs when the channel rejects the subscription.

Callbacks run on their own goroutine, one at a time, in order. Close, Subscribe, and Unsubscribe all work from inside one.

Staying connected

Rails sends a ping every three seconds and the client watches for it. After six seconds of silence the client treats the connection as dead, drops it, and dials again after a second, then two, then four, up to thirty. Each delay carries a little jitter, so a restarted server doesn't get every client back at once.

Both are configurable:

client := actioncable.New("wss://example.com/cable",
	actioncable.WithStaleAfter(10*time.Second),
	actioncable.WithBackoff(time.Second, 30*time.Second),
)

Subscriptions come back on their own. The client resubscribes all of them on the new connection, then resends a subscribe every half second until the server confirms it, because a subscribe that arrives before the connection is set up gets dropped. The same *Subscription and the same Messages channel keep working throughout.

Actions don't come back. Perform and Send return ErrNotConnected while the connection is down, or up but not yet welcomed, since Rails discards anything that arrives that early. Send it again if it matters.

Swapping the transport

The client speaks over the standard library's WebSocket by default.

An application that already uses a WebSocket library can keep using it by implementing two interfaces.

Transport has one function:

type Transport interface {
	Dial(ctx context.Context, url string, options DialOptions) (Conn, error)
}

Dial opens one connection. options carries the sub-protocols the client's protocols negotiate under, and the headers that authorize the request.

Conn has four:

type Conn interface {
	Subprotocol() string
	Read(ctx context.Context) ([]byte, error)
	Write(ctx context.Context, payload []byte) error
	Close() error
}

Subprotocol returns the sub-protocol the server picked, empty if it picked none. Read returns the next complete message. Write sends one text message. Close hangs up, and has to interrupt a Read or Write running at the time.

Implement both and pass the transport to the client:

type coderTransport struct{}

func (coderTransport) Dial(ctx context.Context, url string, options actioncable.DialOptions) (actioncable.Conn, error) {
	socket, _, err := websocket.Dial(ctx, url, &websocket.DialOptions{
		Subprotocols: options.Subprotocols,
		HTTPHeader:   options.Header,
	})
	if err != nil {
		return nil, err
	}

	return &coderConn{socket}, nil
}

type coderConn struct {
	socket *websocket.Conn
}

func (c *coderConn) Subprotocol() string {
	return c.socket.Subprotocol()
}

func (c *coderConn) Read(ctx context.Context) ([]byte, error) {
	_, payload, err := c.socket.Read(ctx)
	return payload, err
}

func (c *coderConn) Write(ctx context.Context, payload []byte) error {
	return c.socket.Write(ctx, websocket.MessageText, payload)
}

func (c *coderConn) Close() error {
	return c.socket.CloseNow()
}

client := actioncable.New(url, actioncable.WithTransport(coderTransport{}))

The default is WebSocketTransport, which speaks RFC 6455 on the standard library and carries no dependencies.

Adding protocols

Action Cable servers can talk multiple protocols. Rails' default is V1-JSON and that's what's supported out-of-the-box. But, if needed, new protocols can be added.

The Protocol interface has just three functions:

type Protocol interface {
	Subprotocol() string
	Encode(command Command) ([]byte, error)
	Decode(payload []byte) (Incoming, error)
}

Subprotocol returns the WebSocket sub-protocol for the protocol. Encode serializes a command to the protocol's wire format, while Decode does the opposite.

All protocols will be offered to the server in that order. If one protocol is preferred over another then it should be defined first:

client := actioncable.New(url, actioncable.WithProtocols(
	V2MessagePack{},
	actioncable.V1JSON{},
))

WithAdditionalProtocols is a shorthand for adding new protocols to the default list. These protocols will get prepended to the list of supported protocols which means that they'll be preferred.

client := actioncable.New(url, actioncable.WithAdditionalProtocols(V2MessagePack{}))

The default is V1JSON, which speaks actioncable-v1-json, Rails' default protocol.

Contributing

Read CONTRIBUTING.md first. Discussions come before issues and pull requests.

License

Released under the MIT License. See LICENSE.

Documentation

Overview

Package actioncable is a client for Rails' Action Cable.

A Client owns one WebSocket connection to an Action Cable server and multiplexes any number of channel subscriptions over it. It keeps the connection alive the way the official JavaScript client does: the server beats a ping every three seconds, and a connection that goes quiet for longer than WithStaleAfter is torn down and redialed with backoff. Subscriptions survive reconnects — they are resubscribed as soon as the server says welcome.

client := actioncable.New("wss://example.com/cable")
if err := client.Connect(ctx); err != nil {
	return err
}
defer client.Close()

room, err := client.Subscribe(ctx, actioncable.Identifier{
	Channel: "RoomChannel",
	Params:  actioncable.Params{"id": 42},
})
if err != nil {
	return err
}

go func() {
	for message := range room.Messages() {
		var said struct{ Body string }
		message.Unmarshal(&said)
		fmt.Println(said.Body)
	}
}()

room.Perform(ctx, "speak", map[string]any{"body": "Hello!"})

Two things are pluggable. A Transport carries bytes — the built-in WebSocketTransport speaks RFC 6455 over the standard library, and any WebSocket package can be dropped in behind the same interface. A Protocol speaks one Action Cable wire format, negotiated as one WebSocket subprotocol — V1JSON implements actioncable-v1-json, and a new format is a new Protocol rather than a fork of this client. WithProtocols offers several, and the server picks the one it knows.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/basecamp/actioncable-go"
)

func main() {
	client := actioncable.New("wss://example.com/cable")

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	if err := client.Connect(ctx); err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	room, err := client.Subscribe(ctx, actioncable.Identifier{
		Channel: "RoomChannel",
		Params:  actioncable.Params{"id": 42},
	})
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for message := range room.Messages() {
			var said struct{ Body string }
			if err := message.Unmarshal(&said); err == nil {
				fmt.Println(said.Body)
			}
		}
	}()

	if err := room.Perform(ctx, "speak", map[string]any{"body": "Hello!"}); err != nil {
		log.Fatal(err)
	}
}

Index

Examples

Constants

View Source
const (
	ReasonUnauthorized   = "unauthorized"
	ReasonInvalidRequest = "invalid_request"
	ReasonServerRestart  = "server_restart"
	ReasonRemote         = "remote"
)

Disconnect reasons an Action Cable server sends before hanging up.

View Source
const SubprotocolUnsupported = "actioncable-unsupported"

SubprotocolUnsupported is the sentinel an Action Cable server names when it speaks none of the subprotocols offered. The client offers it last on every handshake, the way Rails' own clients do, so a server with nothing in common can say so outright instead of leaving the subprotocol blank.

View Source
const SubprotocolV1JSON = "actioncable-v1-json"

SubprotocolV1JSON is the subprotocol every Rails Action Cable server speaks.

Variables

View Source
var (
	// ErrClosed is returned by a client that has been closed, or that stopped
	// because the server told it not to reconnect.
	ErrClosed = errors.New("actioncable: client closed")

	// ErrNotConnected is returned when a command can't be sent because the
	// connection is down. Subscriptions recover on their own; a Perform or Send
	// that hits this is lost and must be retried.
	ErrNotConnected = errors.New("actioncable: not connected")

	// ErrRejected is returned by Subscribe when the channel's subscribed method
	// rejected the subscription.
	ErrRejected = errors.New("actioncable: subscription rejected")

	// ErrUnsupportedSubprotocol is returned when the server negotiated a
	// subprotocol the protocol adapter doesn't speak. Reconnecting won't fix
	// that, so the client stops.
	ErrUnsupportedSubprotocol = errors.New("actioncable: unsupported subprotocol")

	// ErrAlreadyConnected is returned by Connect on a client that is already
	// running.
	ErrAlreadyConnected = errors.New("actioncable: already connected")

	// ErrNoProtocols is returned when there is nothing to offer the server,
	// which means WithProtocols was called without any protocols.
	ErrNoProtocols = errors.New("actioncable: no protocols to offer")
)

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

A Client owns one connection to an Action Cable server and the subscriptions running over it. Create one with New, start it with Connect, and hang up with Close. It is safe for concurrent use.

func New

func New(url string, options ...Option) *Client

New builds a client for an Action Cable endpoint, typically wss://host/cable. It does not touch the network until Connect.

Example (Authorized)

Credentials belong on the client, which sends them while the connection is established.

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/basecamp/actioncable-go"
)

func main() {
	client := actioncable.New("wss://example.com/cable",
		actioncable.WithCookie("_session_id=1234"),
		actioncable.WithHeader(http.Header{"X-Api-Token": {"secret"}}),
	)
	defer client.Close()

	if err := client.Connect(context.Background()); err != nil {
		log.Fatal(err)
	}
}

func (*Client) Close

func (c *Client) Close() error

Close hangs up, stops reconnecting, and closes every subscription's message channel. It is safe to call from a subscription callback, and safe to call twice.

func (*Client) Connect

func (c *Client) Connect(ctx context.Context) error

Connect starts the client and returns once the server has sent its welcome. Failed connection attempts are retried until that happens, ctx is done, or the server tells us not to come back.

ctx bounds the wait, not the client: the connection lives until Close.

func (*Client) Connected

func (c *Client) Connected() bool

Connected reports whether a connection is up and welcomed.

func (*Client) Subscribe

func (c *Client) Subscribe(ctx context.Context, identifier Identifier, options ...SubscriptionOption) (*Subscription, error)

Subscribe subscribes to a channel and returns once the server confirms it. The subscription outlives reconnects — it is resubscribed automatically — so it stays valid until Unsubscribe.

It returns ErrRejected when the channel turns the subscription down.

Example

A subscription outlives reconnects, so OnConnected reports whether this is a fresh subscription or one that came back and may have missed messages.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/basecamp/actioncable-go"
)

func main() {
	client := actioncable.New("wss://example.com/cable")

	ctx := context.Background()
	if err := client.Connect(ctx); err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	room, err := client.Subscribe(ctx, actioncable.Identifier{Channel: "RoomChannel"},
		actioncable.OnConnected(func(reconnected bool) {
			if reconnected {
				catchUp()
			}
		}),
	)
	if err != nil {
		log.Fatal(err)
	}

	for message := range room.Messages() {
		fmt.Println(message)
	}
}

func catchUp() {}

type Command

type Command struct {
	Name       CommandName
	Identifier string
	Data       string
}

A Command is a client-to-server message. Data carries the already encoded action payload and is only set for CommandMessage.

type CommandName

type CommandName string

CommandName is the verb of a client-to-server command.

const (
	CommandSubscribe   CommandName = "subscribe"
	CommandUnsubscribe CommandName = "unsubscribe"
	CommandMessage     CommandName = "message"
)

type Conn

type Conn interface {
	// Subprotocol reports what the server negotiated, empty if it named none.
	Subprotocol() string

	// Read returns the next complete message. It returns an error once the
	// connection is unusable, including when ctx is done.
	Read(ctx context.Context) ([]byte, error)

	// Write sends one text message.
	Write(ctx context.Context, payload []byte) error

	Close() error
}

A Conn is one live connection. Read and Write are each called from a single goroutine at a time, but Close may be called concurrently with either, and must interrupt them.

type DialOptions

type DialOptions struct {
	Subprotocols []string
	Header       http.Header
}

DialOptions are what the client needs the transport to negotiate: the subprotocols its protocol adapter speaks, and the headers that authenticate the request — a cookie or a token, since an Action Cable server authorizes the upgrade request itself.

type DisconnectError

type DisconnectError struct {
	Reason    string
	Reconnect bool
}

A DisconnectError reports that the server sent a disconnect frame.

func (*DisconnectError) Error

func (e *DisconnectError) Error() string

type Identifier

type Identifier struct {
	Channel string
	Params  Params
}

An Identifier names one subscription. It is encoded as a JSON object and the server treats that encoding as an opaque key, echoing it back on every frame it sends for the subscription.

actioncable.Identifier{Channel: "RoomChannel", Params: actioncable.Params{"id": 42}}

A channel with no params needs only the name.

func (Identifier) String

func (i Identifier) String() string

type Incoming

type Incoming struct {
	Kind       Kind
	Identifier string
	Message    Message
	Reason     string
	Reconnect  bool
}

An Incoming is a decoded server-to-client frame. Reason and Reconnect are only set on KindDisconnect, Message on KindMessage and KindPing.

type Kind

type Kind int

Kind is the type of a server-to-client frame.

const (
	KindWelcome Kind = iota
	KindPing
	KindDisconnect
	KindConfirmation
	KindRejection
	KindMessage
)

func (Kind) String

func (k Kind) String() string

type Logger

type Logger interface {
	Printf(format string, args ...any)
}

A Logger takes the client's chatter. The standard library's *log.Logger satisfies it, and so does anything else with a Printf.

type LoggerFunc

type LoggerFunc func(format string, args ...any)

LoggerFunc adapts a function to Logger.

func (LoggerFunc) Printf

func (f LoggerFunc) Printf(format string, args ...any)

type Message

type Message json.RawMessage

A Message is the undecoded payload a channel broadcast or transmitted. Its shape is entirely up to the channel, so Unmarshal it into the expected type.

func (Message) String

func (m Message) String() string

func (Message) Unmarshal

func (m Message) Unmarshal(value any) error

type Option

type Option func(*Client)

An Option configures a client.

func WithAdditionalProtocols

func WithAdditionalProtocols(protocols ...Protocol) Option

WithAdditionalProtocols offers protocols ahead of the ones already there, so preferring a new protocol doesn't mean restating the ones to fall back to.

func WithBackoff

func WithBackoff(initial, longest time.Duration) Option

WithBackoff sets the reconnect delay. It starts at initial, doubles per failed attempt up to longest, and is spread with jitter. Defaults to a second and half a minute.

func WithCookie

func WithCookie(cookie string) Option

WithCookie is shorthand for sending one Cookie header.

func WithHeader

func WithHeader(header http.Header) Option

WithHeader sets the headers sent on the upgrade request. An Action Cable server authorizes that request, so this is where a session cookie or a bearer token goes.

func WithHeaderFunc

func WithHeaderFunc(build func(ctx context.Context) (http.Header, error)) Option

WithHeaderFunc sets the headers the same way WithHeader does, except that it is asked on every dial rather than once. A client reconnects on its own for as long as it runs, which is longer than a credential that expires lives, and a reconnect carrying the token the first dial used would be turned down for good. What this returns is laid over the headers already set, so an Origin or a token given with WithHeader survives.

An error turns down that dial, and the client tries again on its backoff.

func WithLogger

func WithLogger(logger Logger) Option

WithLogger sends the client's chatter — dropped messages, failed connections, retries — somewhere. Nothing is logged by default.

func WithMessageBuffer

func WithMessageBuffer(messages int) Option

WithMessageBuffer sets how many messages a subscription buffers before it starts dropping them. Defaults to 64.

func WithOrigin

func WithOrigin(origin string) Option

WithOrigin sets the Origin header. Rails checks it unless the server disables request forgery protection.

func WithProtocols

func WithProtocols(protocols ...Protocol) Option

WithProtocols sets the protocols offered during the handshake, most preferred first, replacing the default of V1JSON. The server picks one of them and the client speaks it for the rest of the connection.

func WithStaleAfter

func WithStaleAfter(after time.Duration) Option

WithStaleAfter sets how long a connection may go without a frame before it counts as dead. The server beats every three seconds; the default is six, so two missed beats.

func WithSubscribeRetry

func WithSubscribeRetry(retry time.Duration) Option

WithSubscribeRetry sets how often an unconfirmed subscribe command is resent. Defaults to half a second, like the JavaScript client's guarantor.

func WithTransport

func WithTransport(transport Transport) Option

WithTransport swaps the network handler. The default is WebSocketTransport.

type Params

type Params map[string]any

Params are the extra attributes that identify a subscription alongside its channel name, like the id of the record a channel streams for.

type Protocol

type Protocol interface {
	// Subprotocol is the name this protocol negotiates under.
	Subprotocol() string

	// Encode turns a command into one outgoing message.
	Encode(command Command) ([]byte, error)

	// Decode turns one incoming message into a frame the client understands.
	Decode(payload []byte) (Incoming, error)
}

A Protocol translates between Action Cable commands and the bytes on the wire. It is the seam where an Action Cable protocol plugs in.

One protocol speaks one subprotocol. A client offers every protocol it was given and speaks the one the server picks, so supporting a new protocol means adding one rather than replacing the list.

Implementations must be safe for concurrent use.

type Subscription

type Subscription struct {
	// contains filtered or unexported fields
}

A Subscription is one channel subscription on a client. Read what the channel sends from Messages, and talk back with Perform or Send.

func (*Subscription) Key

func (s *Subscription) Key() string

Key is the JSON identifier string the server knows this subscription by, and the one it echoes back on everything it sends here.

func (*Subscription) Messages

func (s *Subscription) Messages() <-chan Message

Messages carries everything the channel broadcasts or transmits to this subscription. It closes when the subscription is unsubscribed or the client is closed.

Read it promptly. Messages that arrive with the buffer full are dropped and logged rather than stalling the connection — WithMessageBuffer sizes the buffer for a slow consumer.

func (*Subscription) Perform

func (s *Subscription) Perform(ctx context.Context, action string, data any) error

Perform invokes an action on the channel — the equivalent of the JavaScript client's perform. data must encode to a JSON object, and may be nil.

func (*Subscription) Send

func (s *Subscription) Send(ctx context.Context, data any) error

Send delivers data to the channel as-is, without naming an action. Rails routes it to the channel's receive method.

func (*Subscription) Unsubscribe

func (s *Subscription) Unsubscribe(ctx context.Context) error

Unsubscribe tells the server to drop the subscription and closes Messages.

type SubscriptionOption

type SubscriptionOption func(*Subscription)

A SubscriptionOption configures a subscription. Callbacks run on their own goroutine, one at a time, in the order the events happened, so Close, Subscribe, and Unsubscribe all work from inside one.

func OnConnected

func OnConnected(callback func(reconnected bool)) SubscriptionOption

OnConnected is called every time the server confirms the subscription, including after a reconnect — which is what reconnected reports.

func OnDisconnected

func OnDisconnected(callback func(willReconnect bool)) SubscriptionOption

OnDisconnected is called when the connection drops, with whether the client intends to dial again.

func OnRejected

func OnRejected(callback func()) SubscriptionOption

OnRejected is called when the channel rejects the subscription.

type Transport

type Transport interface {
	Dial(ctx context.Context, url string, options DialOptions) (Conn, error)
}

A Transport dials the network connection a client talks over. It is the seam where a network handler plugs in: the built-in WebSocketTransport speaks RFC 6455 on the standard library, and wrapping gorilla/websocket, coder/websocket, or an in-memory pipe for tests means implementing these two interfaces and nothing else.

type V1JSON

type V1JSON struct{}

V1JSON implements the actioncable-v1-json protocol: JSON objects in text frames, keyed by command going out and by type coming in.

func (V1JSON) Decode

func (V1JSON) Decode(payload []byte) (Incoming, error)

func (V1JSON) Encode

func (V1JSON) Encode(command Command) ([]byte, error)

func (V1JSON) Subprotocol

func (V1JSON) Subprotocol() string

type WebSocketTransport

type WebSocketTransport struct {
	// Dialer opens the TCP connection. A zero value dialer is used when nil.
	Dialer *net.Dialer

	// TLSConfig configures wss:// connections.
	TLSConfig *tls.Config

	// HandshakeTimeout bounds the upgrade request. Defaults to 10 seconds.
	HandshakeTimeout time.Duration

	// WriteTimeout bounds a single write when the caller's context has no
	// deadline. Defaults to 10 seconds.
	WriteTimeout time.Duration

	// MaxMessageSize is the largest message accepted, in bytes. Defaults to 8 MB.
	MaxMessageSize int64
}

WebSocketTransport is the built-in transport: an RFC 6455 client written on the standard library, so the package carries no dependencies. It handles the upgrade handshake, masks what it sends, answers pings, and reassembles fragmented messages.

func (*WebSocketTransport) Dial

func (t *WebSocketTransport) Dial(ctx context.Context, rawURL string, options DialOptions) (Conn, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL