router

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package router provides Gin-style event routing for wspulse frames. Inbound frames are dispatched by wspulse.Frame.Event through a middleware chain with flow control (Context.Next/Context.Abort) and metadata passing (Context.Set/Context.Get).

Typical usage:

rtr := router.New()
rtr.Use(router.Recovery())
rtr.On("chat.message", handleChat)
rtr.On("chat.join", handleJoin)

// Integrate with wspulse/server:
srv := server.NewServer(connectFunc,
    server.WithOnMessage(func(connection server.Connection, frame wspulse.Frame) {
        rtr.Dispatch(connection, frame)
    }),
)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Connection

type Connection interface {
	// ID returns the unique connection identifier.
	ID() string

	// RoomID returns the room this connection belongs to.
	RoomID() string

	// Send enqueues frame for delivery to the remote peer.
	Send(frame wspulse.Frame) error

	// Close initiates a graceful shutdown of the session.
	Close() error

	// Done returns a channel that is closed when the session terminates.
	Done() <-chan struct{}
}

Connection represents the logical WebSocket session from the router's perspective. It is a consumer-defined interface: any type that provides these five methods satisfies it.

wspulse/server's server.Connection satisfies this interface via Go structural subtyping — no adapter is required.

type Context

type Context struct {
	// Connection is the logical WebSocket session that sent the frame.
	Connection Connection

	// Frame is the decoded inbound frame being dispatched.
	Frame wspulse.Frame
	// contains filtered or unexported fields
}

Context carries the state for a single frame dispatch. It is obtained from a sync.Pool and reset between dispatches; callers must not hold a reference to a Context after the handler returns.

Context and its handlers are not concurrency-safe. All methods must be called from the goroutine that performs dispatch, and callers are expected to enforce serial handler execution per logical connection.

func (*Context) Abort

func (c *Context) Abort()

Abort prevents any remaining handlers in the chain from being called. The current handler continues executing normally after Abort; only subsequent handlers are skipped.

func (*Context) Get

func (c *Context) Get(key string) (any, bool)

Get returns the value stored under key and whether it exists.

func (*Context) GetString

func (c *Context) GetString(key string) string

GetString returns the string value stored under key, or "" if the key does not exist or its value is not a string.

func (*Context) IsAborted

func (c *Context) IsAborted() bool

IsAborted reports whether Abort has been called on this context.

func (*Context) MustGet

func (c *Context) MustGet(key string) any

MustGet returns the value stored under key. It panics if the key does not exist.

func (*Context) Next

func (c *Context) Next()

Next executes the remaining handlers in the chain. It should be called inside middleware to pass control to the next handler.

func (*Context) Set

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

Set stores a key/value pair in the per-dispatch metadata store. Keys are arbitrary strings. The store is lazily initialized on first use.

type HandlerFunc

type HandlerFunc func(*Context)

HandlerFunc is the function signature for all router handlers and middleware. The *Context argument carries the inbound connection, frame, flow control methods, and a per-dispatch key/value store.

func Recovery

func Recovery() HandlerFunc

Recovery returns a HandlerFunc that catches any panic raised by downstream handlers in the chain. On recovery, it logs the panic value and the full stack trace at ERROR level via log/slog and then returns normally, keeping the connection alive.

Place Recovery as the first middleware so it wraps the entire chain:

r := router.New()
r.Use(router.Recovery())
r.On("chat.message", handleChat)

type HandlersChain

type HandlersChain []HandlerFunc

HandlersChain is an ordered slice of HandlerFunc values representing a middleware + handler pipeline.

type Option

type Option func(*Router)

Option is a functional option for configuring a Router.

func WithFallback

func WithFallback(fn HandlerFunc) Option

WithFallback sets a custom handler invoked when no route matches the incoming frame's Event. The fallback participates in the normal handler chain, so global middleware registered via Use runs before it.

The default fallback logs the unmatched frame event at WARN level using the standard library's log/slog package.

type Router

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

Router dispatches inbound wspulse frames to registered handlers based on Frame.Event. It supports global middleware (Use), per-event handlers (On), and a configurable fallback for unmatched frames.

Router is safe for concurrent reads after all routes have been registered. Do not call On or Use concurrently with Dispatch.

func New

func New(opts ...Option) *Router

New returns a new Router with the provided options applied. The default fallback logs unmatched frame events at WARN level.

func (*Router) Dispatch

func (r *Router) Dispatch(conn Connection, frame wspulse.Frame)

Dispatch looks up the handler chain for frame.Event and executes it. If no handler is registered for frame.Event, the fallback is called instead. Global middleware runs before the matched handler or fallback in all cases.

Dispatch is safe to call concurrently from multiple goroutines after all routes have been registered. However, calling Use or On while Dispatch is running is not safe.

func (*Router) On

func (r *Router) On(event string, handlers ...HandlerFunc)

On registers one or more handlers for the given Frame.Event value ("event" in JSON). Panics if event is empty, if no handlers are provided, if any handler is nil, or if event is already registered. On must not be called concurrently with Dispatch.

func (*Router) Use

func (r *Router) Use(handlers ...HandlerFunc)

Use appends one or more middleware handlers to the global middleware chain. Global middleware runs before every handler, including the fallback. Use must not be called concurrently with Dispatch.

Jump to

Keyboard shortcuts

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