wrapper

package module
v1.7.0 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 8 Imported by: 1

README

ws-server-wrapper-go

A lightweight Go WebSocket library that implements the ws-wrapper protocol. It wraps any WebSocket transport and adds named events, request/response (RPC), and channels on top — enabling seamless communication between Go clients/servers, and ws-wrapper JavaScript clients/servers (browser or Node.js).

Go Reference

Features:

  • Named events — emit an event on one end, handle it on the other
  • Request / response — send a request; the handler's return value is sent back as the response
  • Channels — logically namespace events over a single WebSocket connection
  • Bi-directionality — the server can also request data from clients
  • Go client — dial out to any ws-wrapper server with NewClient / Bind; supports reconnection
  • Pluggable transports — use any WebSocket library you want by implementing the Conn interface (see Custom Adapters for supported libraries). This library by itself has no dependencies.

Install

go get github.com/bminer/ws-server-wrapper-go

Then, install the WebSocket library of your choice along with its corresponding adapter:

go get github.com/coder/websocket
go get github.com/bminer/ws-server-wrapper-go/adapters/coder

Server Quick Start

The example below uses the included coder/websocket adapter:

import (
    "net/http"
    wrapper "github.com/bminer/ws-server-wrapper-go"
    "github.com/bminer/ws-server-wrapper-go/adapters/coder"
    "github.com/coder/websocket"
)

wsServer := wrapper.NewServer()
wsServer.On("echo", func(s string) (string, error) {
    return s, nil
})

http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
    conn, err := websocket.Accept(w, r, nil)
    if err != nil {
        return // websocket.Accept writes the HTTP response
    }
    wsServer.Accept(coder.Wrap(conn))
})
http.ListenAndServe(":8080", nil)

Event Handling

// Handle a named event (fire-and-forget from the client side)
wsServer.On("chat", func(msg string) error {
    fmt.Println("chat:", msg)
    return nil
})

// Handle a request and return a value
wsServer.On("add", func(a, b int) (int, error) {
    return a + b, nil
})

// Access the Client inside the handler via Context
wsServer.On("whoami", func(ctx context.Context) (string, error) {
    client := wrapper.ClientFromContext(ctx)
    return client.Get("username").(string), nil
})

Request / Response (Server → Client)

The server can also send requests to a connected client and await a response:

wsServer.On("open", func(c *wrapper.Client) {
    name, err := c.Request(context.Background(), "getName")
    if err == nil {
        c.Set("name", name)
    }
})

Channels

Namespace events to avoid name collisions:

wsServer.Of("io").On("readFile", func(filename string) ([]byte, error) {
    // TODO: Sanitize `filename` for security reasons
    return os.ReadFile(filename)
})

// Remove all handlers on a channel when it is no longer needed.
ioChannel := wsServer.Of("io")
_ = ioChannel.Close()

Anonymous Channels

Anonymous channels let a handler stream events or exchange multiple messages with the requesting client over a single WebSocket connection. Return a *AnonymousChannel from a handler to signal that data will follow asynchronously:

wsServer.On("subscribe", func(ctx context.Context, topic string) (*wrapper.AnonymousChannel, error) {
    ch := wrapper.Channel(ctx) // obtain the anonymous channel for this request
    go func() {
        defer ch.Close()
        for _, update := range fetchUpdates(topic) {
            if err := ch.Emit(ch.Context(), "data", update); err != nil {
                return // client disconnected or aborted
            }
        }
        ch.Emit(ch.Context(), "end")
    }()
    return ch, nil
})

On the client side, the Request call resolves to a *AnonymousChannel:

resp, err := client.Request(ctx, "subscribe", "news")
if ch, ok := resp.(*wrapper.AnonymousChannel); ok {
    ch.On("data", func(update string) error {
        fmt.Println("update:", update)
        return nil
    })
}

Either side can abort the channel early with ch.Abort(err), which sends a cancel message to the remote end and closes the channel. ch.Context() returns a context that is cancelled when the channel closes or is aborted.

Per-Client Handlers

Register handlers on an individual *Client. They take precedence over server-level handlers for that client:

wsServer.On("open", func(c *wrapper.Client) {
    c.On("secret", func(token string) (string, error) {
        return "ok", nil
    })
})

Custom Adapters

Adapters wrap a WebSocket connection from any library into the Conn interface.

Adapter module Library
github.com/bminer/ws-server-wrapper-go/adapters/coder coder/websocket
github.com/bminer/ws-server-wrapper-go/adapters/gorilla gorilla/websocket

Each adapter is a separate Go module, so you only download the one you need.

Client Mode

Use NewClient and Bind to act as a WebSocket client that speaks the ws-wrapper protocol. Register all handlers before calling Bind so that no inbound message can arrive before a handler is in place:

import (
    wrapper "github.com/bminer/ws-server-wrapper-go"
    "github.com/bminer/ws-server-wrapper-go/adapters/coder"
    "github.com/coder/websocket"
)

client := wrapper.NewClient(nil)
client.On("open", func(c *wrapper.Client) {
    fmt.Println("connected!")
})
client.On("news", func(headline string) error {
    // Server is sending us some news
    fmt.Println("breaking news:", headline)
    return nil
})

conn, _ := websocket.Dial(ctx, "ws://example.com/ws", nil)
client.Bind(coder.Wrap(conn))

If you don't need an "open" handler and just want a quick one-liner, pass the connection directly:

client := wrapper.NewClient(coder.Wrap(conn))
Reconnection

All handlers are stored on the Client and survive across calls to Bind, so reconnection is straightforward. Use the userClosed boolean in the "close" handler to distinguish a user-initiated close from a connection drop — only reconnect when userClosed is false:

client := wrapper.NewClient(nil)

client.On("close", func(c *wrapper.Client, status wrapper.StatusCode, reason string, userClosed bool) {
    if userClosed {
        return // explicit close, don't reconnect
    }
    // Connection dropped; reconnect after a short delay.
    time.AfterFunc(10 * time.Second, func() {
        conn, err := websocket.Dial(ctx, "ws://example.com/ws", nil)
        if err != nil {
            log.Println("reconnect failed:", err)
            return
        }
        c.Bind(coder.Wrap(conn))
    })
})

conn, _ := websocket.Dial(ctx, "ws://example.com/ws", nil)
client.Bind(coder.Wrap(conn))

The userClosed parameter is true only when client.Close() is called explicitly by your own code.

See Also

Documentation

Index

Examples

Constants

View Source
const (
	EventOpen       = "open"
	EventConnect    = "connect"
	EventError      = "error"
	EventMessage    = "message"
	EventClose      = "close"
	EventDisconnect = "disconnect"
)

List of reserved event names. It is an error to send or receive events on the main channel with these event names.

Variables

This section is empty.

Functions

func IsReservedEvent

func IsReservedEvent(eventName string) bool

IsReservedEvent checks if the event name is a reserved event name

Types

type AnonymousChannel added in v1.7.0

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

AnonymousChannel is a request-scoped channel created when a handler returns *AnonymousChannel in response to a request. It allows streaming or multi-message patterns over a single WebSocket connection.

Emit and Request are only available once the channel has been delivered to the requestor (i.e. after the handler returns it). Before that point, both methods return errNotReady. On and Once may be called freely at any time, including inside the handler before the channel is returned.

func Channel added in v1.7.0

func Channel(ctx context.Context) *AnonymousChannel

Channel returns the *AnonymousChannel for the current request handler context, creating it lazily on the first call. It returns nil if called outside of a request handler.

Example

ExampleChannel shows how to stream events from a server handler back to the requesting client using an anonymous channel.

The handler calls Channel to obtain an *AnonymousChannel tied to the current request, launches a goroutine that emits a series of "data" events followed by an "end" event, and returns the channel so the library can send the creation response to the client.

On the client side the [Client.Request] return value is a *AnonymousChannel when the server responds with a channel. Register handlers on it before any events can arrive:

resp, err := client.Request(ctx, "subscribe", "news")
if err == nil {
    if ch, ok := resp.(*wrapper.AnonymousChannel); ok {
        ch.On("data", func(update string) error {
            fmt.Println("update:", update)
            return nil
        })
    }
}
package main

import (
	"context"
	"fmt"

	wrapper "github.com/bminer/ws-server-wrapper-go"
)

func main() {
	wsServer := wrapper.NewServer()

	updates := []string{"first", "second", "third"}

	wsServer.On("subscribe", func(ctx context.Context, topic string) (*wrapper.AnonymousChannel, error) {
		ch := wrapper.Channel(ctx) // obtain the anonymous channel for this request
		go func() {
			defer ch.Close()
			for _, u := range updates {
				msg := fmt.Sprintf("[%s] %s", topic, u)
				if err := ch.Emit(ch.Context(), "data", msg); err != nil {
					return // client disconnected or aborted
				}
			}
			ch.Emit(ch.Context(), "end") //nolint:errcheck
		}()
		return ch, nil
	})

	_ = wsServer
}

func (*AnonymousChannel) Abort added in v1.7.0

func (ch *AnonymousChannel) Abort(err error) error

Abort sends an abort message to the remote end with the provided reason and closes this anonymous channel. If err is nil, it defaults to context.Canceled.

func (*AnonymousChannel) Close added in v1.7.0

func (ch *AnonymousChannel) Close() error

Close removes all event handlers for this anonymous channel and cancels its context. It does NOT send an abort message to the remote end; use Abort for that. Close is idempotent and safe to call multiple times.

func (*AnonymousChannel) Context added in v1.7.0

func (ch *AnonymousChannel) Context() context.Context

Context returns a context that is cancelled when this anonymous channel is closed or aborted. The cancellation cause reflects the abort reason when the remote end sends an abort message.

func (*AnonymousChannel) Emit added in v1.7.0

func (ch *AnonymousChannel) Emit(ctx context.Context, arguments ...any) error

Emit sends an event on this anonymous channel. The passed context can be used to cancel writing the message to the client. The first argument must be the event name string. Returns an error if the channel is not yet ready, is closed, or if the message could not be sent.

func (*AnonymousChannel) On added in v1.7.0

func (ch *AnonymousChannel) On(eventName string, handler any) *AnonymousChannel

On adds an event handler for the specified event on this anonymous channel. See ClientChannel.On for handler signature details.

func (*AnonymousChannel) Once added in v1.7.0

func (ch *AnonymousChannel) Once(eventName string, handler any) *AnonymousChannel

Once adds a one-time event handler for the specified event on this anonymous channel. See ClientChannel.On for handler signature details.

func (*AnonymousChannel) Request added in v1.7.0

func (ch *AnonymousChannel) Request(
	ctx context.Context, arguments ...any,
) (any, error)

Request sends a request on this anonymous channel and returns the response. The passed context can be used to cancel the request. The first argument must be the event name string. Returns an error if the channel is not yet ready or is closed.

type ChannelClosedError added in v1.6.0

type ChannelClosedError struct {
	Channel string
}

ChannelClosedError indicates the channel has been closed and cannot be used.

func (ChannelClosedError) Error added in v1.6.0

func (e ChannelClosedError) Error() string

Error returns the error message as a string.

type Client

type Client struct {
	ClientChannel // the "main" client channel with no name
	// contains filtered or unexported fields
}

Client represents a WebSocket client

func ClientFromContext added in v1.1.0

func ClientFromContext(ctx context.Context) *Client

ClientFromContext returns the WebSocket client from the given context. Returns nil if not available.

func NewClient added in v1.6.0

func NewClient(conn Conn) *Client

NewClient creates a new Client not associated with any Server. Register event handlers on the returned Client, then call Client.Bind to attach a WebSocket connection and begin processing messages.

Pass a non-nil conn to bind immediately (useful when no "open" handler is needed):

client := wrapper.NewClient(coder.Wrap(wsConn))

Pass nil when you want to register handlers first — the recommended pattern because it ensures no inbound message can arrive before a handler is in place:

client := wrapper.NewClient(nil)
client.On("open", func(c *wrapper.Client) { /* ... */ })
client.On("news", func(headline string) error { /* ... */ return nil })
conn, _ := websocket.Dial(ctx, "ws://example.com/ws", nil)
client.Bind(coder.Wrap(conn))
Example

ExampleNewClient shows how to create a standalone WebSocket client. Handlers are registered before Bind is called, so no inbound message can arrive before the handlers are in place. The same client can be reused for reconnection by calling Bind again with a new connection.

client := NewClient(nil)

client.On("open", func(c *Client) {
	log.Println("connected to server")
})
client.On("close", func(c *Client, status StatusCode, reason string, userClosed bool) {
	if userClosed {
		return // explicit close, don't reconnect
	}
	log.Println("disconnected:", reason)
	// To reconnect, dial a new connection and call Bind again:
	// conn, _ := websocket.Dial(ctx, "ws://example.com/ws", nil)
	// c.Bind(coder.Wrap(conn))
})
client.On("news", func(headline string) error {
	log.Println("breaking news:", headline)
	return nil
})

// For this runnable example we use a mockConn in place of a real dial.
conn := newMockConn()
client.Bind(conn) // "open" fires here; reading starts here

_ = client.Emit(context.Background(), "subscribe", "sports")
conn.Close(StatusNormalClosure, "done")

func (*Client) Bind added in v1.6.0

func (c *Client) Bind(conn Conn)

Bind attaches conn to the Client and starts reading inbound messages. It can be called on a freshly created Client to establish the initial connection or called again after a disconnect to reconnect; all registered event handlers are preserved across calls.

If the Client already has an active connection, it is closed with StatusGoingAway before the new connection is attached, and any pending outbound requests are cancelled.

Bind fires the "open"/"connect" event handlers synchronously before returning. This guarantees that any handlers registered inside the "open" callback are registered before any inbound messages are processed.

To implement reconnection, call Bind again inside the "close" handler. Use the userClosed parameter to distinguish a user-initiated close from a connection drop — only reconnect when userClosed is false:

client.On("close", func(
	c *wrapper.Client,
	status wrapper.StatusCode,
	reason string,
	userClosed bool,
 ) {
	if userClosed {
		return // don't reconnect when the user explicitly closed
	}
	conn, err := websocket.Dial(ctx, "ws://example.com/ws", nil)
	if err == nil {
		c.Bind(coder.Wrap(conn))
	}
})

func (*Client) Close

func (c *Client) Close(status StatusCode, reason string) error

Close closes the active connection, aborts pending requets, and fires the "close"/"disconnect" event handlers synchronously before returning. If this Client is associated with a Server, Close removes it from the Server's set of connected clients.

func (*Client) Get

func (c *Client) Get(key string) any

Get returns the data for the client at the specified key

func (*Client) Of

func (c *Client) Of(name string) ClientChannel

Of returns a channel for the given name

func (*Client) Set

func (c *Client) Set(key string, value any)

Set sets the data for the client at the specified key

type ClientChannel

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

ClientChannel is a channel on which events can be sent and received. Events emitted or requests sent are sent to the specific client's channel on the remote end. See ClientChannel.On for more information about how received events are handled.

func (*ClientChannel) Close added in v1.6.0

func (ch *ClientChannel) Close() error

Close removes all event handlers for this channel.

Close returns nil.

func (ClientChannel) Emit

func (ch ClientChannel) Emit(ctx context.Context, arguments ...any) error

Emit sends an event to the client on the specified channel. The passed context can be used to cancel writing the message to the client. The first argument must be the event name that tells the remote end which event handler to call. Returns an error if there was an error sending the message to the client.

func (ClientChannel) Name

func (ch ClientChannel) Name() string

Name returns the name of the channel

func (ClientChannel) On

func (ch ClientChannel) On(eventName string, handler any) ClientChannel

On adds an event handler for the specified event to the channel. When an event or request is received from a client, only a single handler is called. The priority of handlers called is as follows:

1. Handlers added via ClientChannel.Once

2. Handlers added via ClientChannel.On

3. Handlers added via ServerChannel.Once

4. Handlers added via ServerChannel.On

Therefore, if a handler is added to a ClientChannel, the corresponding handler on the ServerChannel will never be called for that particular client.

handler must be a function with arbitrary parameters, but it must return one or two values: a request result and an error. The request result is optional and may be of any type, but the error is required and must implement the error interface. When the event handler is called, the arguments of the event are converted to the types expected by handler. If an argument is not convertible to its parameter type (see reflect.Type.ConvertibleTo), the handler is not called and an error is returned to the client; however, there are some notable exceptions to this rule:

  • if the argument is a `nil` interface type and the parameter is a type that can accept `nil`, then `nil` is supplied as the argument

  • if the parameter is a pointer type, the address of the argument will be taken after type conversion

  • if the argument and parameters are slices of convertible types, each element in the slice will be converted into a new slice and supplied as the argument

Optionally, the handler can provide an additional parameter for the context.Context of the request. Call ClientFromContext(ctx) to return the *Client object for the client that emitted the event.

There are also reserved events can occur on the main channel of a client:

  • "error" - called when an error occurs on the client. The handler is passed the error as a single argument and has the form `func(*Client, error)`

  • "message" - called when a message is received from the client. The handler is passed the Message as a single argument and has the form `func(*Client, Message)`. The handler may not modify the message; this event is primarily for logging purposes.

  • "close" or "disconnect" - called when the client disconnects. The handler is passed the status code, reason string, and a boolean indicating whether the close was user-initiated (i.e. Client.Close was called). The handler has the form `func(*Client, StatusCode, string, bool)`

The reserved events that can occur on the main channel of a server include:

  • "open" or "connect" - called when a new client connects. The handler is passed the client and has the form `func(*Client)`

  • "error"

  • "close" or "disconnect" - called when any client disconnects.

If event handlers do not conform to the expected function signature, On will panic.

If On is called multiple times for the same event name, the last handler will be used. If handler is nil, the event handler is removed.

func (ClientChannel) Once

func (ch ClientChannel) Once(eventName string, handler any) ClientChannel

Once adds a one-time event handler for the specified event to the channel. See ClientChannel.On for more information about how event handlers are called.

func (ClientChannel) Request

func (ch ClientChannel) Request(
	ctx context.Context, arguments ...any,
) (response any, err error)

Request sends a request to the client and returns the response. The passed context can be used to cancel the request. The first argument is the event name that tells the remote end which request handler to call.

type ClientError

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

ClientError is an error for a specific client

func (ClientError) Error

func (ce ClientError) Error() string

Error returns the error message as a string

func (ClientError) Unwrap added in v1.6.0

func (ce ClientError) Unwrap() error

Unwrap returns the underlying error.

type CloseHandler

type CloseHandler = func(*Client, StatusCode, string, bool)

type CloseHandlerOld added in v1.6.0

type CloseHandlerOld = func(*Client, StatusCode, string)

type Conn

type Conn interface {
	// ReadMessage reads a message from the WebSocket connection. The context
	// is used to cancel the read operation.
	ReadMessage(ctx context.Context, msg *Message) error
	// WriteMessage writes a message to the WebSocket connection. The context
	// is used to cancel the write operation.
	WriteMessage(ctx context.Context, msg *Message) error
	// Close closes the WebSocket connection with the given status code and
	// reason.
	Close(statusCode StatusCode, reason string) error
	// CloseNow closes the WebSocket connection immediately without waiting for
	// any pending operations to complete.
	CloseNow() error
}

Conn represents a WebSocket connection that can read and write messages. ReadMessage may not be called concurrently, and one must always read from the connection to properly handle control frames.

type ErrorHandler

type ErrorHandler = func(*Client, error)

type HandlerContextFunc

type HandlerContextFunc func(
	ctx context.Context,
	channel string,
	eventName string,
) context.Context

HandlerContextFunc is a function that can modify the context passed to every registered event handler before it is called.

type Message

type Message struct {
	Channel          string            `json:"c,omitempty"`
	AnonymousChannel int               `json:"h,omitempty"`
	Arguments        []json.RawMessage `json:"a,omitempty"` // Arguments[0] is the event name
	RequestID        *int              `json:"i,omitempty"`
	ResponseData     any               `json:"d,omitempty"`
	ResponseError    any               `json:"e,omitempty"`
	ResponseJSError  weakBool          `json:"_,omitempty"`
	CancelReason     any               `json:"x,omitempty"` // Request cancellation signal
	IgnoreIfFalse    *weakBool         `json:"ws-wrapper,omitempty"`
	// contains filtered or unexported fields
}

Message is a ws-wrapper JSON-encoded message. See https://github.com/bminer/ws-wrapper/blob/master/README.md#protocol

func (Message) CancelCause added in v1.4.0

func (m Message) CancelCause() error

CancelCause returns the cancel/abort reason from this message as an error. Works for both inbound request cancellations ({i, x}) and anonymous channel aborts ({h, x}). Returns "message is not a cancellation" if CancelReason is nil; returns context.Canceled if the reason cannot be parsed.

func (Message) EventName

func (m Message) EventName() string

EventName returns the name of the event or empty string if the message is invalid

func (Message) HandlerArguments

func (m Message) HandlerArguments() []json.RawMessage

HandlerArguments returns the arguments for the event handler

func (Message) LogValue

func (m Message) LogValue() slog.Value

func (Message) Processed added in v1.2.0

func (m Message) Processed() <-chan struct{}

Processed returns a channel that is closed when the message is done being processed. This can be used by a "message" handler to measure message processing time.

func (Message) Response

func (m Message) Response() (any, error)

Response returns the response data and error for this message.

type MessageHandler

type MessageHandler = func(*Client, Message)

type OpenHandler

type OpenHandler = func(*Client)

Type aliases for "reserved" event handlers

type Server

type Server struct {
	ServerChannel // the "main" server channel with no name
	// contains filtered or unexported fields
}

Server represents a server that accepts WebSocket connections, handles inbound messages, and sends messages to connected clients. Rather than listening for connections itself, the Accept method takes any connection that implements the Conn interface. This allows the server to be used with any WebSocket library. Various adapter libraries are available in the adapters subdirectory.

Example (Echo)

This example shows how to use create a ws-server-wrapper that echoes a string sent to the "echo" event handler.

// Create ws-wrapper-server and "echo" event handler. Note that the event
// handler function may optionally have a context as its first argument,
// it must always return 2 values, and the second value must implement
// error.
wsServer := NewServer()
wsServer.On("echo", func(s string) (string, error) {
	// If a ws-server client sends a "echo" request, it will receive the
	// echoed response.
	return s, nil
})

// Create HTTP handler function that upgrades the HTTP connection to a
// WebSocket using the github.com/coder/websocket package.
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	// 1. Use your favorite WebSocket library to upgrade the HTTP request to
	//    a WebSocket connection...
	// 2. Use an adapter (or write your own) to write and parse ws-wrapper
	//    messages.
	// 3. Call `wsServer.Accept` to attach the underlying WebSocket
	//    connection to `wsServer`. It will start listening for inbound
	//    messages.
	// See full example in the coder adapter.
})

// Start the HTTP server
log.Fatal(http.ListenAndServe("localhost:8080", h))

func NewServer

func NewServer() *Server

NewServer creates a new server.

func (*Server) Accept

func (s *Server) Accept(conn Conn) error

Accept adds a new client connection to the server. conn only needs to implement the Conn interface. If the server has been closed, Accept will return an error and close conn.

func (*Server) Close

func (s *Server) Close() error

Close closes the server and all connected clients. Returns the first error encountered while closing clients.

func (*Server) Of

func (s *Server) Of(name string) ServerChannel

Of returns a channel for the given name

func (*Server) SetHandlerContext

func (s *Server) SetHandlerContext(f HandlerContextFunc)

SetHandlerContext sets the handler context function. This function is called before every event handler is called and is used to modify the context passed to every event handler. It can be used to implement timeouts for individual event handlers, for example.

type ServerChannel

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

ServerChannel is a channel on which events can be sent and received. Events emitted or requests sent are sent to all connected clients to the channel of the same name on the remote end. See ClientChannel.On for more information about how received events are handled.

func (*ServerChannel) Close added in v1.6.0

func (c *ServerChannel) Close() error

Close removes all event handlers for this channel.

Close returns nil.

func (ServerChannel) Emit

func (c ServerChannel) Emit(
	ctx context.Context, arguments ...any,
) (errs []ClientError)

Emit sends an event to all clients on the specified channel. The passed context can be used to cancel writing the message to the client. The second argument is the event name that tells the remote end which event handler to call. Returns a slice of ClientErrors that contains an entry if an error occurred when sending the message to a specific client.

func (ServerChannel) Name

func (c ServerChannel) Name() string

Name returns the name of the channel

func (ServerChannel) On

func (c ServerChannel) On(eventName string, handler any) ServerChannel

On adds an event handler for the specified event to the channel. See ClientChannel.On for more information about how event handlers are called.

Example

Demonstrates how to add various event handlers.

wsServer := NewServer()

// Simple event handler that does not return a response
// Note: Since no channel name is provided, this handler is attached to the
// "main" channel with no name.
wsServer.On("print", func(s string) (struct{}, error) {
	fmt.Println(s)
	return struct{}{}, nil
})

// Simple request handler that echoes whatever was received
wsServer.On("echo", func(s string) (string, error) {
	return s, nil
})

// Request handler that reads a file from disk. CAUTION: Be sure to sanitize
// user input.
// Note: json.Marshall will return a base64 string to the client because
// `[]byte` is returned by the handler.
wsServer.On("readFile", func(filename string) ([]byte, error) {
	return os.ReadFile(filename)
})
Example (Channel)

Demonstrates adding event handlers to a particular channel.

wsServer := NewServer()

// Adds a "readFile" event handler to the "io" channel.
wsServer.Of("io").On("readFile", func(filename string) ([]byte, error) {
	return os.ReadFile(filename)
})

func (ServerChannel) Once

func (c ServerChannel) Once(eventName string, handler any) ServerChannel

Once adds a one-time event handler for the specified event to the channel. See ClientChannel.On for more information about how event handlers are called.

type StatusCode

type StatusCode int

StatusCode represents a WebSocket status code. https://tools.ietf.org/html/rfc6455#section-7.4

const (
	StatusNormalClosure   StatusCode = 1000
	StatusGoingAway       StatusCode = 1001
	StatusProtocolError   StatusCode = 1002
	StatusUnsupportedData StatusCode = 1003

	StatusInvalidFramePayloadData StatusCode = 1007
	StatusPolicyViolation         StatusCode = 1008
	StatusMessageTooBig           StatusCode = 1009
	StatusMandatoryExtension      StatusCode = 1010
	StatusInternalError           StatusCode = 1011
	StatusServiceRestart          StatusCode = 1012
	StatusTryAgainLater           StatusCode = 1013
	StatusBadGateway              StatusCode = 1014
)

Directories

Path Synopsis
adapters
coder module

Jump to

Keyboard shortcuts

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