Documentation
¶
Overview ¶
Package realtime is the OniWorks realtime platform — the nervous system of the framework. It provides a WebSocket connection manager, channel/room router, broadcast via Oni Memory, presence tracking, backpressure, auth per connection, and reconnect/resume support.
Index ¶
- Constants
- type Conn
- func (c *Conn) Close()
- func (c *Conn) Get(key string) (any, bool)
- func (c *Conn) ID() string
- func (c *Conn) IsSubscribed(channel string) bool
- func (c *Conn) Send(e *Event) bool
- func (c *Conn) Set(key string, value any)
- func (c *Conn) Subscribe(channel string)
- func (c *Conn) Unsubscribe(channel string)
- type ConnectHandler
- type DisconnectHandler
- type Event
- type EventBuffer
- type HandlerFunc
- type Hub
- func (h *Hub) Broadcast(channel string, payload any) error
- func (h *Hub) BroadcastEvent(channel string, e *Event) error
- func (h *Hub) Channel(pattern string, fn HandlerFunc)
- func (h *Hub) ConnCount() int
- func (h *Hub) Handler() onihttp.HandlerFunc
- func (h *Hub) Members(channel string) []PresenceInfo
- func (h *Hub) OnConnect(fn ConnectHandler)
- func (h *Hub) OnDisconnect(fn DisconnectHandler)
- func (h *Hub) Presence(pattern string)
- func (h *Hub) Push(connID string, e *Event) bool
- func (h *Hub) RoomSize(channel string) int
- func (h *Hub) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (h *Hub) Shutdown()
- type Options
- type PresenceInfo
- type PresenceManager
- func (pm *PresenceManager) Count(channel string) int
- func (pm *PresenceManager) Join(channel string, info PresenceInfo)
- func (pm *PresenceManager) Leave(channel string, connID string)
- func (pm *PresenceManager) LeaveAll(connID string)
- func (pm *PresenceManager) Members(channel string) []PresenceInfo
- func (pm *PresenceManager) Refresh(channel, connID string)
Constants ¶
const ( EventTypeConnect = "oni:connect" EventTypeDisconnect = "oni:disconnect" EventTypeError = "oni:error" EventTypePing = "oni:ping" EventTypePong = "oni:pong" EventTypeResume = "oni:resume" EventTypeAck = "oni:ack" EventTypeSubscribe = "oni:subscribe" EventTypeUnsubscribe = "oni:unsubscribe" )
System event types (reserved — prefixed with "oni:")
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Conn ¶
type Conn struct {
// Authenticated user (0 = anonymous)
UserID int64
// contains filtered or unexported fields
}
Conn represents a single WebSocket connection to a client. It runs two goroutines: a read loop and a write loop. The send channel provides backpressure — slow clients are dropped after write timeout.
func (*Conn) IsSubscribed ¶
IsSubscribed reports whether this connection is subscribed to a channel.
func (*Conn) Subscribe ¶
Subscribe marks this connection as interested in a channel pattern. It also maintains the hub's channel→conns broadcast index so Broadcast only touches subscribers instead of scanning every connection on the node.
func (*Conn) Unsubscribe ¶
Unsubscribe removes a channel subscription (and the broadcast-index entry).
type ConnectHandler ¶
ConnectHandler is called after a WebSocket connection is established and authenticated.
type DisconnectHandler ¶
type DisconnectHandler func(c *Conn)
DisconnectHandler is called when a WebSocket connection closes.
type Event ¶
type Event struct {
// ID is a server-assigned monotonic event ID used for reconnect/resume.
ID string `json:"id,omitempty"`
// Type classifies the event (e.g. "chat.message", "presence.join").
Type string `json:"type"`
// Channel is the pub/sub channel this event belongs to.
Channel string `json:"channel,omitempty"`
// Payload is the event body — arbitrary JSON.
Payload json.RawMessage `json:"payload,omitempty"`
// Params are wildcard segments extracted by the channel router (not serialized).
Params map[string]string `json:"-"`
// ConnID is the sender's connection ID (not sent to clients).
ConnID string `json:"-"`
// UserID is the authenticated user's ID (0 = anonymous).
UserID int64 `json:"-"`
// Ts is a Unix timestamp in seconds.
Ts int64 `json:"ts,omitempty"`
}
Event is the wire-format envelope for all messages flowing over a WebSocket connection.
JSON wire format:
{"id":"01J...","type":"chat.message","channel":"chat.room1","payload":{...},"ts":1713000000}
type EventBuffer ¶
type EventBuffer struct {
// contains filtered or unexported fields
}
EventBuffer stores recent events per channel for reconnect/resume. When a client reconnects with a last_event_id, the hub replays all events published after that ID — no messages lost during brief disconnects.
Rings are created on demand per channel and evicted again once idle for idleTTL (see janitor/evictIdle), so per-user or short-lived channels don't grow the buffer map without bound.
func NewEventBuffer ¶
func NewEventBuffer(maxSize int, maxAge time.Duration) *EventBuffer
NewEventBuffer creates a buffer retaining the last maxSize events per channel, up to maxAge old. Channel rings idle beyond the default idle TTL are eligible for eviction once a janitor is running (the Hub starts one automatically).
func (*EventBuffer) Push ¶
func (eb *EventBuffer) Push(channel string, e *Event)
Push appends an event to the channel's ring buffer.
lastTouched is stamped while eb.mu is held: evictIdle holds the write lock while it checks the stamp, so a ring being pushed to concurrently is always seen as fresh and can't be evicted out from under the push.
func (*EventBuffer) Since ¶
func (eb *EventBuffer) Since(channel, lastEventID string) []*Event
Since returns all buffered events for channel published after lastEventID. Pass "" to get all buffered events.
type HandlerFunc ¶
HandlerFunc handles an incoming realtime event.
type Hub ¶
type Hub struct {
// contains filtered or unexported fields
}
Hub is the central OniWorks realtime hub. It manages all WebSocket connections, routes events to channel handlers, broadcasts via Oni Memory (cross-node safe), and tracks presence.
func (*Hub) Broadcast ¶
Broadcast sends an event to all connections subscribed to channel, including connections on other nodes (via Oni Memory pub/sub).
hub.Broadcast("chat.room1", myPayload)
func (*Hub) BroadcastEvent ¶
BroadcastEvent broadcasts a pre-built Event to a channel.
func (*Hub) Channel ¶
func (h *Hub) Channel(pattern string, fn HandlerFunc)
Channel registers a handler for events arriving on a channel pattern.
hub.Channel("chat.{room}", func(c *Conn, e *Event) error {
return hub.Broadcast("chat."+e.Params["room"], e.Payload)
})
func (*Hub) Handler ¶
func (h *Hub) Handler() onihttp.HandlerFunc
Handler returns an onihttp.HandlerFunc that upgrades HTTP connections to WebSocket. Mount it with: router.Get("/ws", hub.Handler())
func (*Hub) Members ¶
func (h *Hub) Members(channel string) []PresenceInfo
Members returns all presence info for a channel (cross-node via Oni Memory).
func (*Hub) OnConnect ¶
func (h *Hub) OnConnect(fn ConnectHandler)
OnConnect registers a hook called after every successful connection.
func (*Hub) OnDisconnect ¶
func (h *Hub) OnDisconnect(fn DisconnectHandler)
OnDisconnect registers a hook called when a connection closes.
func (*Hub) Presence ¶
Presence marks a channel pattern as a presence channel. When a client subscribes/unsubscribes, their entry is written to Oni Memory.
hub.Presence("room.{id}")
func (*Hub) RoomSize ¶
RoomSize returns the number of connections subscribed to a channel. Uses Oni Memory for cross-node accuracy.
type Options ¶
type Options struct {
// Memory is the Oni Memory store used for cross-node broadcast and presence.
Memory *memory.Store
// CheckOrigin validates the WebSocket origin header. Return true to allow.
// Defaults to allowing all origins (override in production).
CheckOrigin func(r *http.Request) bool
// AuthFunc authenticates a connection during the HTTP upgrade handshake.
// Return the user ID (0 = anonymous) and an error to reject the connection.
AuthFunc func(r *http.Request) (userID int64, err error)
// EventBufferSize is the max number of events buffered per channel for resume.
EventBufferSize int
// EventBufferAge is how long events stay in the buffer (default: 2 minutes).
EventBufferAge time.Duration
// EventBufferIdleTTL is how long a channel's event ring may sit untouched
// (no push, no resume read) before the janitor evicts it. Without eviction,
// per-user channels grow the buffer map without bound. Default: 10 minutes.
EventBufferIdleTTL time.Duration
// PresenceChannels lists channel patterns that auto-track presence.
PresenceChannels []string
// Logger (defaults to slog.Default).
Logger *slog.Logger
}
Options configures the Hub.
type PresenceInfo ¶
type PresenceInfo struct {
UserID int64 `json:"user_id"`
ConnID string `json:"conn_id"`
Meta map[string]any `json:"meta,omitempty"`
}
PresenceInfo is the data stored per-member in a presence channel.
type PresenceManager ¶
type PresenceManager struct {
// contains filtered or unexported fields
}
PresenceManager manages who is "online" in each channel. Presence state is stored in Oni Memory so it is visible to all nodes.
func (*PresenceManager) Count ¶
func (pm *PresenceManager) Count(channel string) int
Count returns the number of online members in a channel.
func (*PresenceManager) Join ¶
func (pm *PresenceManager) Join(channel string, info PresenceInfo)
Join marks a user as present in a channel.
func (*PresenceManager) Leave ¶
func (pm *PresenceManager) Leave(channel string, connID string)
Leave removes a user from a presence channel.
func (*PresenceManager) LeaveAll ¶
func (pm *PresenceManager) LeaveAll(connID string)
LeaveAll removes all presence entries for a connection across all channels.
func (*PresenceManager) Members ¶
func (pm *PresenceManager) Members(channel string) []PresenceInfo
Members returns all currently online members of a channel.
func (*PresenceManager) Refresh ¶
func (pm *PresenceManager) Refresh(channel, connID string)
Refresh extends the TTL for a connection's presence (call periodically).