wrapper

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: May 2, 2025 License: MIT Imports: 6 Imported by: 0

README

ws-server-wrapper-go

Lightweight WebSocketServer wrapper library for Go. See ws-wrapper JavaScript package for more details.

Go Reference

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.

View Source
const ClientKey = contextKey("client")

ClientKey is the value to be passed to the context's Value method to return the *wrapper.Client object that emitted the event.

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 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 (*Client) Close

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

Close closes the client connection and removes it from the list of clients connected to the server.

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) Emit

func (c 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 second argument is 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 (c ClientChannel) Name() string

Name returns the name of the channel

func (ClientChannel) On

func (c 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 and reason and has the form `func(*Client, StatusCode, string)`

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 (c 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 (c 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 second 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

type CloseHandler

type CloseHandler = 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, context.CancelFunc)

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"`
	Arguments       []any  `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 bool   `json:"_,omitempty"`
	IgnoreIfFalse   *bool  `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) 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() []any

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) 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.

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
This package enables the use of the github.com/coder/websocket package with the ws-server-wrapper library.
This package enables the use of the github.com/coder/websocket package with the ws-server-wrapper library.
internal

Jump to

Keyboard shortcuts

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