websocket

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2025 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package websocket is a lightweight yet robust client-only implementation of the WebSocket protocol (RFC 6455).

It focuses on continuous asynchronous reading of text/binary messages, and enables occasional writing.

It is designed primarily for ease of use and availability at scale. Additional design goals: reliability, maintainability, and efficiency.

How does this package optimize for availability at scale?

  1. In-memory map of active clients, keyed by (a secure hash of) their ID, to minimize the number of open connections per app
  2. Preemptively switch connections before each anticipated disconnection, to prevent downtime during reconnections
  3. Fast detection and recovery from unexpected disconnections
  4. Idiomatic, minimalistic, and modern code patterns

Note A: optimization 1 relies on Go channels to dispatch and potentially fan-out messages efficiently and reliably.

Note B: optimization 2 requires careful balancing of optimization 1 with ensuring state isolation, correct and efficient garbage collection, and ensuring that users of this package do not receive duplicate copies of messages while a client temporarily has an extra connection.

Note C: WebSocket extensions and subprotocols are not supported yet.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client added in v0.2.0

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

Client is a long-running wrapper of connections to the same WebSocket server with the same credentials. It usually manages a single Conn, except when it gets disconnected, or is about to be, in which case the client automatically opens another Conn and switches to it seamlessly, to prevent or at least minimize downtime during reconnections.

func NewOrCachedClient added in v0.2.0

func NewOrCachedClient(ctx context.Context, url urlFunc, id string, opts ...DialOpt) (*Client, error)

func (*Client) IncomingMessages added in v0.2.0

func (c *Client) IncomingMessages() <-chan Message

IncomingMessages returns the client's channel that publishes data [Message]s as they are received from the server.

func (*Client) RefreshConnectionIn added in v0.2.0

func (c *Client) RefreshConnectionIn(d time.Duration)

RefreshConnectionIn instructs the client to replace its underlying Conn seamlessly after the given duration of time. This prevents unnecessary downtime during normal reconnections, which is useful in connections where the disconnection time is known or coordinated in advance.

type Conn

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

Conn respresents the configuration and state of an open client connection to a WebSocket server.

func Dial

func Dial(ctx context.Context, wsURL string, opts ...DialOpt) (*Conn, error)

Dial performs a WebSocket handshake to establish a connection to the given URL ("ws://..." or "wss://").

func (*Conn) Close

func (c *Conn) Close(s StatusCode)

Close performs a WebSocket closing handshake to initiate the closure of an open connection.

func (*Conn) IncomingMessages

func (c *Conn) IncomingMessages() <-chan Message

IncomingMessages returns the connection's channel that publishes data [Message]s as they are received from the server.

func (*Conn) IsClosed

func (c *Conn) IsClosed() bool

func (*Conn) IsClosing

func (c *Conn) IsClosing() bool

func (*Conn) SendBinaryMessage

func (c *Conn) SendBinaryMessage(data []byte) <-chan error

SendBinaryMessage sends a binary message to the server.

This is done asynchronously, to manage isolation or safe multiplexing of multiple concurrent calls, including interleaved control frames. Despite that, this function enables the caller to block and/or handle errors, with the returned channel.

func (*Conn) SendTextMessage

func (c *Conn) SendTextMessage(data []byte) <-chan error

SendTextMessage sends a UTF-8 text message to the server.

This is done asynchronously, to manage isolation or safe multiplexing of multiple concurrent calls, including interleaved control frames. Despite that, this function enables the caller to block and/or handle errors, with the returned channel.

type DialOpt added in v0.2.0

type DialOpt func(*Conn)

func WithHTTPClient

func WithHTTPClient(hc *http.Client) DialOpt

WithHTTPClient lets callers of Dial specify a custom http.Client to use for the WebSocket handshake, instead of http.DefaultClient.

Do not specify a custom timeout in the HTTP client! This will interfere with the long-lived WebSocket connection beyond the scope of its initial handshake. Instead, use context.WithTimeout with the context.Context passed to Dial.

func WithHTTPHeader

func WithHTTPHeader(key, value string) DialOpt

WithHTTPHeader lets callers of Dial add a single HTTP header to the WebSocket handshake's HTTP request. Use WithHTTPHeaders to specify multiple ones.

func WithHTTPHeaders

func WithHTTPHeaders(hs http.Header) DialOpt

WithHTTPHeaders lets callers of Dial add multiple HTTP headers to the WebSocket handshake's HTTP request, instead of calling WithHTTPHeader multiple times.

type Message added in v0.2.0

type Message struct {
	Opcode Opcode
	Data   []byte
}

WebSocket data message, from one or more (defragmented) data frames, as defined in https://datatracker.ietf.org/doc/html/rfc6455#section-5.6. Returned by the Go channel that is exposed by Conn.IncomingMessages.

type Opcode

type Opcode int

Opcode denotes the type of a WebSocket frame, as defined in https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 and https://datatracker.ietf.org/doc/html/rfc6455#section-11.8.

const (
	OpcodeText Opcode
	OpcodeBinary
)

func (Opcode) String

func (o Opcode) String() string

String returns the opcode's name, or its number if it's unrecognized.

type StatusCode

type StatusCode int

StatusCode indicates a reason for the closure of an established WebSocket connection, as defined in https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.

See also https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number.

Other status code ranges:

  • 0-999: not used
  • 3000-3999: reserved for use by libraries, frameworks, and applications
  • 4000-4999: reserved for private use and thus can't be registered
const (
	// The purpose for which the connection was established has been fulfilled.
	StatusNormalClosure StatusCode = iota + 1000
	// An endpoint is "going away", such as a server going
	// down or a browser having navigated away from a page.
	StatusGoingAway
	// An endpoint is terminating the connection due to a protocol error.
	StatusProtocolError
	// An endpoint is terminating the connection because it has received a
	// type of data it cannot accept (e.g., an endpoint that understands
	// only text data MAY send this if it receives a binary message).
	StatusUnsupportedData

	// Reserved value, MUST NOT be set as a status code in a Close control
	// frame by an endpoint. It is designated for use in applications expecting
	// a status code to indicate that no status code was actually present.
	StatusNotReceived
	// Reserved value, MUST NOT be set as a status code in a Close control
	// frame by an endpoint. It is designated for use in applications expecting
	// a status code to indicate that the connection was closed abnormally,
	// e.g., without sending or receiving a Close control frame.
	StatusClosedAbnormally
	// An endpoint is terminating the connection because it has received data
	// within a message that was not consistent with the type of the message
	// (e.g., non-UTF-8 RFC 3629 data within a text message).
	StatusInvalidData
	// An endpoint is terminating the connection because it has received a message
	// that violates its policy. This is a generic status code that can be returned
	// when there is no other more suitable status code (e.g., 1003 or 1009)
	// or if there is a need to hide specific details about the policy.
	StatusPolicyViolation
	// An endpoint is terminating the connection because it has
	// received a message that is too big for it to process.
	StatusMessageTooBig
	// An endpoint (client) is terminating the connection because it has expected the
	// server to negotiate one or more extensions, but the server didn't return them in
	// the response message of the WebSocket handshake. The list of extensions that are
	// needed SHOULD appear in the /reason/ part of the Close frame. Note that this status
	// code is not used by the server, because it can fail the WebSocket handshake instead.
	StatusMandatoryExtension
	// A remote endpoint is terminating the connection because it encountered
	// an unexpected condition that prevented it from fulfilling the request.
	// See https://www.rfc-editor.org/errata_search.php?eid=3227.
	StatusInternalError
	// See https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number.
	StatusServiceRestart
	// See https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number.
	StatusTryAgainLater
	// See https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number.
	StatusBadGateway
	// Reserved value, MUST NOT be set as a status code in a Close control frame
	// by an endpoint. It is designated for use in applications expecting a status
	// code to indicate that the connection was closed due to a failure to perform
	// a TLS handshake (e.g., the server certificate can't be verified).
	StatusTLSHandshake
)

func (StatusCode) String

func (s StatusCode) String() string

String returns the status code's name, or its number if it's unrecognized.

Jump to

Keyboard shortcuts

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