grx

websocket

API reference for the websocket package, generated from Go doc comments.

import "github.com/grx-gql/grx/websocket"

Package websocket provides an RFC 6455 WebSocket implementation tailored for GraphQL subscription transports. It implements core.Transport for both the modern graphql-transport-ws subprotocol and the legacy graphql-ws (Apollo subscriptions-transport-ws) subprotocol.

Index

Constants

OpcodeContinuation

Frame opcodes from RFC 6455 §5.2. Exported so callers can inspect the frames produced by the transport.

const (
    OpcodeContinuation byte = 0x0
    OpcodeText         byte = 0x1
    OpcodeBinary       byte = 0x2
    OpcodeClose        byte = 0x8
    OpcodePing         byte = 0x9
    OpcodePong         byte = 0xA
)

DefaultMaxMessageSize

Default values applied when the corresponding Config field is left zero.

const (
    DefaultMaxMessageSize        = 1 << 20 // 1 MiB
    DefaultConnectionInitTimeout = 3 * time.Second
)

Subprotocol

Subprotocol is the only WebSocket subprotocol this transport speaks. The legacy Apollo subscriptions-transport-ws ("graphql-ws") protocol is intentionally not supported; it was deprecated in 2021 and clients that have not migrated should upgrade rather than be carried indefinitely.

const Subprotocol = "graphql-transport-ws"

func IsTimeout

func IsTimeout(err error) bool

IsTimeout reports whether err originated from a deadline exceeded on the underlying connection. The dispatcher uses this to map a missed connection_init into the correct close code.

func IsUpgrade

func IsUpgrade(r *http.Request) bool

IsUpgrade reports whether r is a well-formed WebSocket upgrade request.

type Config

Config tunes WebSocketTransport. All fields are optional; zero values fall back to safe production defaults documented per field.

type Config struct {
    // ConnectionInitTimeout is the maximum time the dispatcher waits for a
    // ConnectionInit message after the WebSocket handshake completes. Once
    // exceeded, the connection is closed with code 4408. Zero defaults to
    // DefaultConnectionInitTimeout (3s); a negative value disables the
    // timeout.
    ConnectionInitTimeout time.Duration

    // ReadIdleTimeout caps the time the dispatcher will wait for any next
    // frame from the peer once the connection is initialised. The deadline
    // resets after each successful ReadMessage. Zero disables the timeout.
    ReadIdleTimeout time.Duration

    // WriteTimeout caps a single frame write. Slow consumers that fail to
    // drain a frame within the deadline are closed; this is the primary
    // backpressure protection. Zero disables the timeout.
    WriteTimeout time.Duration

    // MaxMessageSize bounds the total decoded payload of a single
    // (potentially fragmented) message. Zero defaults to
    // DefaultMaxMessageSize. A negative value disables the limit.
    MaxMessageSize int64

    // CheckOrigin authorises the Origin header during the handshake.
    // Returning false fails the upgrade with HTTP 403. nil accepts every
    // origin and should not be used for browser-facing deployments.
    CheckOrigin func(r *http.Request) bool

    // OnConnect is invoked when the first ConnectionInit message arrives.
    // It receives the request-scoped context and the raw init payload
    // (typically containing auth tokens). Implementations may either:
    //
    //  - Return a derived context (used as the parent for every
    //    subscription on the connection) and an optional ack payload.
    //    A nil ack payload omits the payload from the ack message.
    //
    //  - Return an error to reject the connection. The socket is closed
    //    with code 4403 Forbidden.
    OnConnect func(ctx context.Context, payload json.RawMessage) (context.Context, json.RawMessage, error)

    // PingInterval, when non-zero, makes the server send application-level
    // ping messages on this cadence. The peer is expected to respond with
    // pong; absence of pong combined with ReadIdleTimeout causes the
    // connection to close.
    PingInterval time.Duration
}

type Conn

Conn is a server-side WebSocket connection. Reads are single-threaded and happen on the dispatcher goroutine; writes are guarded by a mutex so concurrent goroutines (e.g. subscription dispatchers, server-side ping) can push frames safely.

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

func (*Conn) Close

func (c *Conn) Close() error

Close terminates the underlying network connection.

func (*Conn) ReadMessage

func (c *Conn) ReadMessage() (opcode byte, payload []byte, err error)

ReadMessage reads the next text or binary message from the peer, reassembling fragmented frames and responding to ping and close control frames automatically. It enforces the RFC 6455 framing rules: control frames must be unfragmented and ≤125 bytes, reserved bits must be zero, continuation frames must follow an in-flight data message, and text messages must be valid UTF-8.

func (*Conn) SendClose

func (c *Conn) SendClose(code uint16, reason string)

SendClose sends a WebSocket close frame with the given code and reason and marks the connection as closed for further writes.

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the absolute time after which a pending read will fail. A zero value disables the deadline. Dispatchers use it to enforce the connection_init timeout and the read idle timeout.

func (*Conn) Subprotocol

func (c *Conn) Subprotocol() string

Subprotocol returns the negotiated WebSocket subprotocol, or the empty string if no subprotocol was agreed upon.

func (*Conn) WriteText

func (c *Conn) WriteText(payload []byte) error

WriteText writes a complete UTF-8 text frame to the peer. Concurrent writes are serialised through the connection's mutex; the configured write deadline (if any) protects against slow consumers.

type WebSocketTransport

WebSocketTransport implements core.Transport for the graphql-transport-ws subprotocol. Construct with New; the zero value also works and applies all defaults.

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

func New

func New(cfg ...Config) *WebSocketTransport

New returns a WebSocketTransport ready to be registered with the server.

func (*WebSocketTransport) Match

func (*WebSocketTransport) Match(r *http.Request) bool

Match reports whether r is a WebSocket upgrade request.

func (*WebSocketTransport) Serve

func (t *WebSocketTransport) Serve(w http.ResponseWriter, r *http.Request, executor core.Executor)

Serve performs the WebSocket handshake, verifies that the negotiated subprotocol is graphql-transport-ws, and runs the dispatcher loop for the lifetime of the session.

Generated by gomarkdoc

Edit this page on GitHub

Last updated on

On this page