Help us shape the future of Go! Take the 2026 Go Developer Survey

websocket

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package websocket serves WebSocket connections for Vukem apps on top of github.com/coder/websocket, with secure defaults: same-origin upgrades only (plus an explicit allowlist), a 32 KiB read limit, ping/pong keepalive that drops dead peers, per-message write timeouts and a 1001 "going away" close when the app shuts down.

Inside a handler, Handle reads like c.WebSocket(fn):

r.Get("/chat", func(c *web.Ctx) error {
	return websocket.Handle(c, func(conn *websocket.Conn) error {
		msg, err := conn.ReadText(conn.Context())
		...
	})
})

or, for a route that only upgrades, r.Get("/chat", websocket.Handler(chat)). Broadcast serves package broadcast channels over the same connection type.

See https://github.com/AlexGalhardo/vukem/blob/main/docs/frontend.md.

Index

Examples

Constants

View Source
const (
	TypeSubscribe    = "subscribe"
	TypeUnsubscribe  = "unsubscribe"
	TypeSubscribed   = "subscribed"
	TypeUnsubscribed = "unsubscribed"
	TypeEvent        = "event"
	TypeHere         = "here"
	TypeJoining      = "joining"
	TypeLeaving      = "leaving"
	TypeError        = "error"
)

Broadcast protocol message types. Clients send subscribe and unsubscribe; the server sends the others.

View Source
const (
	DefaultReadLimit    = 32 << 10
	DefaultPingInterval = 30 * time.Second
	DefaultPingTimeout  = 10 * time.Second
	DefaultWriteTimeout = 10 * time.Second
)

Defaults applied when no Option overrides them.

View Source
const (
	StatusNormalClosure   = websocket.StatusNormalClosure
	StatusGoingAway       = websocket.StatusGoingAway
	StatusPolicyViolation = websocket.StatusPolicyViolation
	StatusMessageTooBig   = websocket.StatusMessageTooBig
	StatusInternalError   = websocket.StatusInternalError
)

Close status codes used by this package.

Variables

View Source
var ErrNotText = errors.New("websocket: binary message, want text")

ErrNotText is returned by ReadText and ReadJSON for binary messages.

Functions

func Broadcast

func Broadcast(srv *broadcast.Server, opts ...Option) web.HandlerFunc

Broadcast returns a route handler serving the broadcast WebSocket protocol for srv: every subscribe is authorized by srv (fail closed) in the context of the upgrade request, so mount it behind the auth middleware that identifies the user.

r.Get("/broadcast/ws", websocket.Broadcast(b))

func Handle

func Handle(c *web.Ctx, fn func(*Conn) error, opts ...Option) error

Handle upgrades the request of c and runs fn with the connection; it is the Vukem counterpart of c.SSE for WebSockets. A refused upgrade (bad origin, not a WebSocket request) returns an HTTP error with the status already sent to the client.

Example

Handle upgrades from inside a regular handler, after any checks it needs. Cross-origin upgrades are refused unless their origin is allowlisted.

package main

import (
	"github.com/AlexGalhardo/vukem/drivers/websocket"
	"github.com/AlexGalhardo/vukem/router"
	"github.com/AlexGalhardo/vukem/web"
)

func main() {
	r := router.New(nil)
	r.Get("/chat", func(c *web.Ctx) error {
		return websocket.Handle(c, func(conn *websocket.Conn) error {
			var msg struct {
				Text string `json:"text"`
			}

			if err := conn.ReadJSON(conn.Context(), &msg); err != nil {
				return err
			}

			return conn.WriteJSON(conn.Context(), map[string]string{"text": msg.Text})
		}, websocket.AllowedOrigins("https://app.example.com"))
	})
}

func Handler

func Handler(fn func(*Conn) error, opts ...Option) web.HandlerFunc

Handler returns a route handler that upgrades the request and runs fn.

Example

An echo endpoint. The handler returns when the client closes the connection or the app shuts down.

package main

import (
	"context"
	"fmt"
	"net/http/httptest"
	"strings"

	cws "github.com/coder/websocket"

	"github.com/AlexGalhardo/vukem/drivers/websocket"
	"github.com/AlexGalhardo/vukem/router"
)

func main() {
	r := router.New(nil)
	r.Get("/ws", websocket.Handler(func(conn *websocket.Conn) error {
		ctx := conn.Context()

		for {
			msg, err := conn.ReadText(ctx)
			if websocket.CloseStatus(err) == websocket.StatusNormalClosure {
				return nil
			} else if err != nil {
				return err
			}

			if err := conn.WriteText(ctx, "echo: "+msg); err != nil {
				return err
			}
		}
	}))

	srv := httptest.NewServer(r)
	defer srv.Close()

	ctx := context.Background()

	c, resp, err := cws.Dial(ctx, "ws"+strings.TrimPrefix(srv.URL, "http")+"/ws", nil)
	if err != nil {
		panic(err)
	}

	if resp.Body != nil {
		_ = resp.Body.Close()
	}

	defer c.CloseNow()

	if err := c.Write(ctx, cws.MessageText, []byte("hi")); err != nil {
		panic(err)
	}

	_, got, err := c.Read(ctx)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(got))

	_ = c.Close(cws.StatusNormalClosure, "")
}
Output:
echo: hi

func Serve

func Serve(w http.ResponseWriter, r *http.Request, fn func(*Conn) error, opts ...Option) error

Serve upgrades r and runs fn until it returns, the client goes away, the peer stops answering pings or the app shuts down; Conn.Context is then done. The connection is closed when Serve returns: StatusNormalClosure when fn returns nil, StatusInternalError when it fails, StatusGoingAway on shutdown.

Types

type Conn

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

Conn is an accepted WebSocket connection. Reads and writes take a context (usually Context()); one reader and one writer may run concurrently.

func (*Conn) Close

func (c *Conn) Close(code StatusCode, reason string) error

Close performs the closing handshake with code and reason. Closing again (or after Serve closed the connection) is a no-op.

func (*Conn) CloseRead

func (c *Conn) CloseRead(ctx context.Context) context.Context

CloseRead discards incoming messages for handlers that only write, so pongs and close frames are still processed; the returned context is done when the connection closes. A data message from the client closes the connection with StatusPolicyViolation.

func (*Conn) Context

func (c *Conn) Context() context.Context

Context is done when the client goes away, the handler returns, the peer stops answering pings or the app shuts down.

func (*Conn) ReadJSON

func (c *Conn) ReadJSON(ctx context.Context, v any) error

ReadJSON reads one text message and decodes it as JSON into v.

func (*Conn) ReadText

func (c *Conn) ReadText(ctx context.Context) (string, error)

ReadText reads one text message.

func (*Conn) Subprotocol

func (c *Conn) Subprotocol() string

Subprotocol returns the negotiated subprotocol ("" when none).

func (*Conn) Unwrap

func (c *Conn) Unwrap() *websocket.Conn

Unwrap returns the underlying coder/websocket connection for features this wrapper does not cover (binary messages, streaming readers).

func (*Conn) WriteJSON

func (c *Conn) WriteJSON(ctx context.Context, v any) error

WriteJSON sends v encoded as JSON in one text message within the write timeout.

func (*Conn) WriteText

func (c *Conn) WriteText(ctx context.Context, s string) error

WriteText sends s as one text message within the write timeout.

type Frame

type Frame struct {
	Type    string          `json:"type"`
	Channel string          `json:"channel,omitempty"`
	Event   string          `json:"event,omitempty"`
	Data    json.RawMessage `json:"data,omitempty"`
	Status  int             `json:"status,omitempty"`
	Message string          `json:"message,omitempty"`
}

Frame is a server message of the broadcast protocol. Event frames carry Event and Data; here carries the member list, joining/leaving one member; error carries Status (400, 403) and Message.

type Option

type Option func(*options)

Option configures an upgrade.

func AllowedOrigins

func AllowedOrigins(patterns ...string) Option

AllowedOrigins authorizes cross-origin upgrades from browsers whose Origin host matches one of patterns (path.Match syntax, case-insensitive; a pattern with "://" matches "scheme://host"). The request's own host is always allowed. "*" is refused: use InsecureSkipOriginCheck to say so.

func InsecureSkipOriginCheck

func InsecureSkipOriginCheck() Option

InsecureSkipOriginCheck accepts upgrades from any origin, which lets any website open a socket with the user's cookies (cross-site WebSocket hijacking). Only for endpoints that authenticate without cookies.

func PingInterval

func PingInterval(d time.Duration) Option

PingInterval sets how often the server pings the client (zero or negative disables keepalive).

func PingTimeout

func PingTimeout(d time.Duration) Option

PingTimeout sets how long a ping waits for its pong before the peer is considered dead and the connection is dropped.

func ReadLimit

func ReadLimit(n int64) Option

ReadLimit caps the size of one incoming message in bytes; a bigger message closes the connection with StatusMessageTooBig.

func Subprotocols

func Subprotocols(protocols ...string) Option

Subprotocols lists the subprotocols the server negotiates, in preference order; Conn.Subprotocol reports the chosen one ("" when none matched).

func WriteTimeout

func WriteTimeout(d time.Duration) Option

WriteTimeout bounds every write; a write that times out closes the connection.

type Request

type Request struct {
	Type    string `json:"type"`
	Channel string `json:"channel"`
}

Request is a client message of the broadcast protocol: {"type":"subscribe","channel":"private-user.42"}.

type StatusCode

type StatusCode = websocket.StatusCode

StatusCode is a WebSocket close status code (RFC 6455, section 7.4).

func CloseStatus

func CloseStatus(err error) StatusCode

CloseStatus returns the close code carried by err, or -1 when err did not come from a close frame.

Jump to

Keyboard shortcuts

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