Documentation
¶
Index ¶
- Constants
- Variables
- func IsTransportKind(kind string) bool
- func NewLocalRoom(opts RoomOptions) *local.LocalRoom
- func NewMember(opts streaming.MemberOptions) streaming.Member
- func NewSSEConnection(stream forge.Stream, remoteAddr, localAddr string) forge.Connection
- func NewSubscription(opts streaming.SubscriptionOptions) streaming.Subscription
- func TransportKinds() []string
- type ActivityInfo
- type AnalyticsEvent
- type AnalyticsQuery
- type AnalyticsResult
- type Availability
- type BackendError
- type BinaryCodec
- type Channel
- type ChannelStore
- type Codec
- type CodecRegistry
- func (r *CodecRegistry) Decode(data []byte, msg *streaming.Message) error
- func (r *CodecRegistry) DecodeWithType(contentType string, data []byte, msg *streaming.Message) error
- func (r *CodecRegistry) Default() Codec
- func (r *CodecRegistry) Encode(msg *streaming.Message) ([]byte, error)
- func (r *CodecRegistry) EncodeWithType(contentType string, msg *streaming.Message) ([]byte, error)
- func (r *CodecRegistry) Get(contentType string) (Codec, bool)
- func (r *CodecRegistry) Register(codec Codec)
- func (r *CodecRegistry) SetDefault(contentType string) error
- type Config
- type ConfigOption
- func WithAuthentication(username, password string) ConfigOption
- func WithBackend(backend string) ConfigOption
- func WithBackendURLs(urls ...string) ConfigOption
- func WithBufferSizes(read, write int) ConfigOption
- func WithConfig(config Config) ConfigOption
- func WithConnectionLimits(perUser, roomsPerUser, channelsPerUser int) ConfigOption
- func WithFeatures(rooms, channels, presence, typing, history bool) ConfigOption
- func WithLoadBalancer(strategy string) ConfigOption
- func WithLocalBackend() ConfigOption
- func WithMessageLimits(maxSize, maxPerSecond int) ConfigOption
- func WithMessageRetention(retention time.Duration) ConfigOption
- func WithNATSBackend(urls ...string) ConfigOption
- func WithNodeID(nodeID string) ConfigOption
- func WithPresenceTimeout(timeout time.Duration) ConfigOption
- func WithRedisBackend(url string) ConfigOption
- func WithRequireConfig(require bool) ConfigOption
- func WithSessionResumption(ttl time.Duration) ConfigOption
- func WithTLS(certFile, keyFile, caFile string) ConfigOption
- func WithTimeouts(ping, pong, write time.Duration) ConfigOption
- func WithTypingTimeout(timeout time.Duration) ConfigOption
- type ConnOption
- type Connection
- type ConnectionHook
- type ConnectionInfo
- type DeviceInfo
- type DistributedBackend
- type DistributedBackendOptions
- type ErrorHook
- type Extension
- func (e *Extension) AsyncAPISpec() *forge.AsyncAPISpec
- func (e *Extension) Codecs() *CodecRegistry
- func (e *Extension) DashboardContributor() contributor.LocalContributor
- func (e *Extension) Health(ctx context.Context) error
- func (e *Extension) Hooks() *HookRegistry
- func (e *Extension) Manager() Manager
- func (e *Extension) Register(app forge.App) error
- func (e *Extension) RegisterCodec(codec Codec)
- func (e *Extension) RegisterContractContributor(disp *dispatcher.Dispatcher, reg dashcontract.Registry, ...) error
- func (e *Extension) RegisterDashboardBridge(b *bridge.Bridge) error
- func (e *Extension) RegisterHook(hook StreamingHook)
- func (e *Extension) RegisterRoutes(router forge.Router, wsPath, ssePath string) error
- func (e *Extension) Start(ctx context.Context) error
- func (e *Extension) Stop(ctx context.Context) error
- func (e *Extension) UnregisterHook(name string)
- type FileInfo
- type FileQuery
- type FileUpload
- type HistoryQuery
- type HookRegistry
- func (r *HookRegistry) Add(hook StreamingHook)
- func (r *HookRegistry) Close() error
- func (r *HookRegistry) DroppedDeliveries() uint64
- func (r *HookRegistry) FireOnConnect(ctx context.Context, conn streaming.EnhancedConnection) error
- func (r *HookRegistry) FireOnDisconnect(ctx context.Context, conn streaming.EnhancedConnection)
- func (r *HookRegistry) FireOnError(ctx context.Context, conn streaming.EnhancedConnection, err error)
- func (r *HookRegistry) FireOnMessageDelivered(ctx context.Context, conn streaming.EnhancedConnection, msg *streaming.Message)
- func (r *HookRegistry) FireOnMessageReceived(ctx context.Context, conn streaming.EnhancedConnection, msg *streaming.Message) (*streaming.Message, error)
- func (r *HookRegistry) FireOnPresenceChange(ctx context.Context, userID, oldStatus, newStatus string)
- func (r *HookRegistry) FireOnRawMessage(ctx context.Context, conn streaming.EnhancedConnection, data []byte) ([]byte, error)
- func (r *HookRegistry) FireOnRoomCreate(ctx context.Context, room streaming.Room) error
- func (r *HookRegistry) FireOnRoomDelete(ctx context.Context, roomID string)
- func (r *HookRegistry) FireOnRoomJoin(ctx context.Context, conn streaming.EnhancedConnection, roomID string) error
- func (r *HookRegistry) FireOnRoomLeave(ctx context.Context, conn streaming.EnhancedConnection, roomID string)
- func (r *HookRegistry) List() []StreamingHook
- func (r *HookRegistry) Remove(name string)
- type Invite
- type InviteOptions
- type JSONCodec
- type LocalRoom
- type Lock
- type Manager
- type ManagerOption
- func WithCodecRegistry(cr *CodecRegistry) ManagerOption
- func WithCoordinator(c coordinator.StreamCoordinator) ManagerOption
- func WithFilterChain(fc filters.FilterChain) ManagerOption
- func WithHookRegistry(hr *HookRegistry) ManagerOption
- func WithManagerHealthChecker(hc lb.HealthChecker) ManagerOption
- func WithManagerLoadBalancer(l lb.LoadBalancer) ManagerOption
- func WithManagerNodeID(id string) ManagerOption
- func WithMessageAuthorizer(ma streamauth.MessageAuthorizer) ManagerOption
- func WithRateLimiter(rl ratelimit.RateLimiter) ManagerOption
- func WithRoomAuthorizer(ra streamauth.RoomAuthorizer) ManagerOption
- func WithSessionStore(ss SessionStore) ManagerOption
- func WithValidator(v validation.MessageValidator) ManagerOption
- type ManagerStats
- type Member
- type MemberOptions
- type Message
- type MessageEdit
- type MessageHandler
- type MessageHook
- type MessageReaction
- type MessageSearchQuery
- type MessageStore
- type ModerationEvent
- type ModerationStatus
- type NodeChangeEvent
- type NodeChangeHandler
- type NodeInfo
- type OnlineStats
- type OutboundFrame
- type PresenceEvent
- type PresenceFilters
- type PresenceHook
- type PresenceOptions
- type PresenceStore
- type PresenceTracker
- type RateLimitStatus
- type RawMessageHook
- type Room
- type RoomBan
- type RoomEvent
- type RoomHook
- type RoomOptions
- type RoomStats
- type RoomStore
- type SendQueueStats
- type SessionSnapshot
- type SessionStore
- type StreamingHook
- type TextCodec
- type TypingOptions
- type TypingStore
- type TypingTracker
- type UserPresence
- type UserPresenceStats
- type UserStats
- type WebhookConfig
Constants ¶
const ( TransportWebSocket = "websocket" TransportSSE = "sse" )
Transport type constants.
const ( // DefaultSendQueueCapacity is the number of frames a connection may have // queued for the socket before the overflow policy kicks in. DefaultSendQueueCapacity = 256 // DefaultSendQueueFlushTimeout bounds how long Close waits for already // queued frames to reach the socket before the connection is torn down. // It exists so a final frame (a kick notice, a close reason) is not // discarded, without letting one slow consumer stall connection cleanup. DefaultSendQueueFlushTimeout = time.Second // DefaultSendQueueExitTimeout bounds how long Close waits for the writer // goroutine to exit after the underlying connection has been closed. DefaultSendQueueExitTimeout = 5 * time.Second )
Send queue defaults.
const ContentTypeBinary = internal.ContentTypeBinary
const ContentTypeJSON = internal.ContentTypeJSON
Content type constants.
const ContentTypeMsgPack = internal.ContentTypeMsgPack
const ContentTypeProtobuf = internal.ContentTypeProtobuf
const ContentTypeText = internal.ContentTypeText
const LifecycleMetadataKey = "lifecycle"
LifecycleMetadataKey is the Metadata key under which NewLifecycleMessage records the lifecycle name.
Exported so neither the client nor any other consumer has to match a bare string literal against an envelope this package owns. A literal spelled in three places is a rename away from a reader that silently finds nothing, and a lifecycle frame whose name cannot be read is indistinguishable from one that never carried a name at all.
const (
// ManagerKey is the DI key for the streaming manager.
ManagerKey = "streaming"
)
DI container keys for streaming extension services.
const MessageTypeError = internal.MessageTypeError
const MessageTypeJoin = internal.MessageTypeJoin
const MessageTypeLeave = internal.MessageTypeLeave
const MessageTypeMessage = internal.MessageTypeMessage
Message type constants.
All seven kinds `internal` declares, deliberately: `TransportKinds` needs the complete set, and a reserved set that silently listed only some of them would be wrong in the direction that matters -- a kind missing from it is a frame the client reports as an unknown message forever. Exporting them all also spares a caller outside this package spelling any value of `Message.Type` as a string literal.
const MessageTypePresence = internal.MessageTypePresence
const MessageTypeSystem = internal.MessageTypeSystem
const MessageTypeTyping = internal.MessageTypeTyping
const StatusAway = internal.StatusAway
const StatusBusy = internal.StatusBusy
const StatusOffline = internal.StatusOffline
const StatusOnline = internal.StatusOnline
Status constants.
Variables ¶
var ( // ErrSendQueueClosed is returned when a frame is enqueued on a connection // whose writer has already stopped. ErrSendQueueClosed = errors.New("streaming: connection send queue closed") // ErrSendQueueOverflow is returned when a non-droppable frame arrives on a // full queue. The connection is disconnected; the client is expected to // reconnect and resynchronise. ErrSendQueueOverflow = errors.New("streaming: connection send queue overflow") )
Send queue errors.
var DefaultPresenceOptions = internal.DefaultPresenceOptions
Default option functions.
var DefaultTypingOptions = internal.DefaultTypingOptions
var ErrAlreadyRoomMember = internal.ErrAlreadyRoomMember
var ErrAlreadySubscribed = internal.ErrAlreadySubscribed
var ErrBackendNotFound = internal.ErrBackendNotConnected
var ErrBackendTimeout = internal.ErrBackendTimeout
var ErrChannelAccessDenied = internal.ErrChannelAccessDenied
var ErrChannelAlreadyExists = internal.ErrChannelAlreadyExists
var ErrChannelLimitReached = internal.ErrChannelLimitReached
var ErrChannelNotFound = internal.ErrChannelNotFound
Channel errors.
var ErrChannelsDisabled = internal.ErrChannelsDisabled
var ErrConnectionClosed = internal.ErrConnectionClosed
var ErrConnectionLimitReached = internal.ErrConnectionLimitReached
var ErrConnectionNotFound = internal.ErrConnectionNotFound
Connection errors.
var ErrHistoryDisabled = internal.ErrHistoryDisabled
var ErrInsufficientRole = internal.ErrInsufficientRole
var ErrInvalidChannel = internal.ErrInvalidChannel
var ErrInvalidConfig = internal.ErrInvalidConfig
var ErrInvalidConnection = internal.ErrInvalidConnection
var ErrInvalidMessage = internal.ErrInvalidMessage
var ErrInvalidPermission = internal.ErrInvalidPermission
var ErrInvalidRoom = internal.ErrInvalidRoom
var ErrInvalidStatus = internal.ErrInvalidStatus
var ErrInviteExpired = internal.ErrInviteExpired
var ErrInviteNotFound = internal.ErrInviteNotFound
Invite errors.
var ErrLockAcquisitionFailed = internal.ErrLockAcquisitionFailed
var ErrLockNotHeld = internal.ErrLockNotHeld
var ErrMessageNotFound = internal.ErrMessageNotFound
var ErrMessageTooLarge = internal.ErrMessageTooLarge
var ErrNodeNotFound = internal.ErrNodeNotFound
var ErrNotRoomMember = internal.ErrNotRoomMember
var ErrNotSubscribed = internal.ErrNotSubscribed
var ErrPermissionDenied = internal.ErrPermissionDenied
Permission errors.
var ErrPresenceDisabled = internal.ErrPresenceDisabled
var ErrPresenceNotFound = internal.ErrPresenceNotFound
var ErrRateLimitExceeded = internal.ErrRateLimitExceeded
Rate limiting.
var ErrRoomAccessDenied = internal.ErrRoomAccessDenied
Authorization errors.
var ErrRoomAlreadyExists = internal.ErrRoomAlreadyExists
var ErrRoomFull = internal.ErrRoomFull
var ErrRoomLimitReached = internal.ErrRoomLimitReached
var ErrRoomNotFound = internal.ErrRoomNotFound
Room errors.
var ErrRoomsDisabled = internal.ErrRoomsDisabled
Feature-flag errors.
var ErrSendDenied = internal.ErrSendDenied
var ErrSessionNotOwned = internal.ErrSessionNotOwned
var ErrTypingDisabled = internal.ErrTypingDisabled
var ErrUserBanned = internal.ErrUserBanned
var ErrUserMuted = internal.ErrUserMuted
var NewBackendError = internal.NewBackendError
var NewChannelError = internal.NewChannelError
var NewConnectionError = internal.NewConnectionError
Error constructors.
var NewMessageError = internal.NewMessageError
var NewRoomError = internal.NewRoomError
Functions ¶
func IsTransportKind ¶ added in v1.9.5
IsTransportKind reports whether kind is one of the reserved transport kinds.
Useful to a producer choosing an Event name: a domain event that collides with a reserved kind is unbindable on the client, because a frame naming it cannot be told apart from the transport frame of the same name.
func NewMember ¶ added in v1.9.5
func NewMember(opts streaming.MemberOptions) streaming.Member
NewMember creates a Member suitable for handing to any RoomStore.
func NewSSEConnection ¶ added in v0.10.0
func NewSSEConnection(stream forge.Stream, remoteAddr, localAddr string) forge.Connection
NewSSEConnection creates a new SSE connection adapter.
func NewSubscription ¶ added in v1.9.5
func NewSubscription(opts streaming.SubscriptionOptions) streaming.Subscription
NewSubscription creates a Subscription suitable for handing to any ChannelStore.
func TransportKinds ¶ added in v1.9.5
func TransportKinds() []string
TransportKinds returns the reserved values of Message.Type, in the order they are declared.
Mirrored by TRANSPORT_KINDS in packages/client-core/src/streaming.ts, which drops a frame whose name resolves to one of these through the Type fallback. The mirror is asserted in frame_test.go rather than trusted: an eighth kind added to this package and not to that set would arrive at the client as a frame name no binding can claim, and be reported as an unknown message on every channel for as long as it existed.
A fresh slice per call, so a caller ranging over it cannot reorder the set every other consumer reads.
Types ¶
type ActivityInfo ¶
type ActivityInfo = internal.ActivityInfo
type AnalyticsEvent ¶
type AnalyticsEvent = internal.AnalyticsEvent
type AnalyticsQuery ¶
type AnalyticsQuery = internal.AnalyticsQuery
type Availability ¶
type Availability = internal.Availability
type BinaryCodec ¶ added in v1.3.0
type BinaryCodec struct{}
BinaryCodec handles raw binary data. On decode, it stores the raw bytes in msg.RawData and sets the content type. On encode, it returns msg.RawData directly.
func (*BinaryCodec) ContentType ¶ added in v1.3.0
func (c *BinaryCodec) ContentType() string
type ChannelStore ¶
type ChannelStore = internal.ChannelStore
type Codec ¶ added in v1.3.0
type Codec interface {
// ContentType returns the MIME type this codec handles (e.g. "application/json").
ContentType() string
// Encode serializes a message to bytes.
Encode(msg *streaming.Message) ([]byte, error)
// Decode deserializes bytes into a message.
Decode(data []byte, msg *streaming.Message) error
}
Codec handles encoding and decoding messages for a specific content type.
type CodecRegistry ¶ added in v1.3.0
type CodecRegistry struct {
// contains filtered or unexported fields
}
CodecRegistry manages codecs by content type and provides encode/decode dispatch based on message content type.
func NewCodecRegistry ¶ added in v1.3.0
func NewCodecRegistry() *CodecRegistry
NewCodecRegistry creates a new codec registry pre-loaded with a JSON codec as default.
func (*CodecRegistry) Decode ¶ added in v1.3.0
func (r *CodecRegistry) Decode(data []byte, msg *streaming.Message) error
Decode deserializes bytes into a message using the default codec. If decoding fails with the default codec, it returns the error.
func (*CodecRegistry) DecodeWithType ¶ added in v1.3.0
func (r *CodecRegistry) DecodeWithType(contentType string, data []byte, msg *streaming.Message) error
DecodeWithType deserializes bytes into a message using the codec for the given content type.
func (*CodecRegistry) Default ¶ added in v1.3.0
func (r *CodecRegistry) Default() Codec
Default returns the default codec (JSON).
func (*CodecRegistry) Encode ¶ added in v1.3.0
func (r *CodecRegistry) Encode(msg *streaming.Message) ([]byte, error)
Encode serializes a message using the codec matching msg.ContentType, or the default codec if ContentType is empty.
Callers that resolve a content type from somewhere other than the message — notably a connection's SetContentType preference — must use EncodeWithType instead, or the resolved type is discarded here.
func (*CodecRegistry) EncodeWithType ¶ added in v1.9.5
EncodeWithType serializes a message using the codec for the given content type, falling back to the default codec when contentType is empty. It mirrors DecodeWithType and lets the caller supply a type resolved from the connection rather than from the message itself.
func (*CodecRegistry) Get ¶ added in v1.3.0
func (r *CodecRegistry) Get(contentType string) (Codec, bool)
Get returns the codec for the given content type.
func (*CodecRegistry) Register ¶ added in v1.3.0
func (r *CodecRegistry) Register(codec Codec)
Register adds a codec. If a codec for the same content type already exists, it is replaced.
func (*CodecRegistry) SetDefault ¶ added in v1.3.0
func (r *CodecRegistry) SetDefault(contentType string) error
SetDefault changes the default codec to the one registered for the given content type.
type ConfigOption ¶
type ConfigOption = internal.ConfigOption
func WithAuthentication ¶
func WithAuthentication(username, password string) ConfigOption
func WithBackend ¶
func WithBackend(backend string) ConfigOption
func WithBackendURLs ¶
func WithBackendURLs(urls ...string) ConfigOption
func WithBufferSizes ¶
func WithBufferSizes(read, write int) ConfigOption
func WithConfig ¶
func WithConfig(config Config) ConfigOption
func WithConnectionLimits ¶
func WithConnectionLimits(perUser, roomsPerUser, channelsPerUser int) ConfigOption
func WithFeatures ¶
func WithFeatures(rooms, channels, presence, typing, history bool) ConfigOption
func WithLoadBalancer ¶ added in v1.9.5
func WithLoadBalancer(strategy string) ConfigOption
func WithLocalBackend ¶
func WithLocalBackend() ConfigOption
func WithMessageLimits ¶
func WithMessageLimits(maxSize, maxPerSecond int) ConfigOption
func WithMessageRetention ¶
func WithMessageRetention(retention time.Duration) ConfigOption
func WithNATSBackend ¶
func WithNATSBackend(urls ...string) ConfigOption
func WithNodeID ¶
func WithNodeID(nodeID string) ConfigOption
func WithPresenceTimeout ¶
func WithPresenceTimeout(timeout time.Duration) ConfigOption
func WithRedisBackend ¶
func WithRedisBackend(url string) ConfigOption
func WithRequireConfig ¶
func WithRequireConfig(require bool) ConfigOption
func WithSessionResumption ¶ added in v1.9.5
func WithSessionResumption(ttl time.Duration) ConfigOption
func WithTLS ¶
func WithTLS(certFile, keyFile, caFile string) ConfigOption
func WithTimeouts ¶
func WithTimeouts(ping, pong, write time.Duration) ConfigOption
func WithTypingTimeout ¶
func WithTypingTimeout(timeout time.Duration) ConfigOption
type ConnOption ¶ added in v1.9.5
type ConnOption func(*connOptions)
ConnOption configures an enhanced connection.
func WithConnectionLogger ¶ added in v1.9.5
func WithConnectionLogger(logger forge.Logger) ConnOption
WithConnectionLogger gives the connection a logger for writer-goroutine teardown reasons.
func WithConnectionMetrics ¶ added in v1.9.5
func WithConnectionMetrics(metrics forge.Metrics) ConnOption
WithConnectionMetrics gives the connection a metrics handle for send queue depth, drops, and overflow disconnects. Without one the same numbers remain readable through SendQueueStats.
func WithSendQueueCapacity ¶ added in v1.9.5
func WithSendQueueCapacity(capacity int) ConnOption
WithSendQueueCapacity sets how many frames may be queued for the socket before the per-message-type overflow policy applies. Zero or negative selects DefaultSendQueueCapacity.
func WithSendQueueTimeouts ¶ added in v1.9.5
func WithSendQueueTimeouts(flush, exit time.Duration) ConnOption
WithSendQueueTimeouts bounds connection teardown: flush is how long Close waits for queued frames to reach the socket, exit is how long it then waits for the writer goroutine to unwind after the socket has been closed.
type Connection ¶
type Connection = internal.EnhancedConnection
func NewConnection ¶
func NewConnection(conn forge.Connection, opts ...ConnOption) Connection
NewConnection creates a new enhanced connection with default transport "websocket".
func NewConnectionWithTransport ¶ added in v1.3.0
func NewConnectionWithTransport(conn forge.Connection, transport string, opts ...ConnOption) Connection
NewConnectionWithTransport creates a new enhanced connection with a specified transport type.
type ConnectionHook ¶ added in v1.3.0
type ConnectionHook interface {
StreamingHook
// OnConnect is called before registration. Return error to reject connection.
OnConnect(ctx context.Context, conn Connection) error
// OnDisconnect is called after unregistration.
OnDisconnect(ctx context.Context, conn Connection)
}
ConnectionHook fires on connection lifecycle events.
type DeviceInfo ¶
type DeviceInfo = internal.DeviceInfo
type DistributedBackend ¶
type DistributedBackend = internal.DistributedBackend
Distributed backend.
type DistributedBackendOptions ¶
type DistributedBackendOptions = internal.DistributedBackendOptions
type ErrorHook ¶ added in v1.3.0
type ErrorHook interface {
StreamingHook
// OnError is called when a message handling error occurs.
OnError(ctx context.Context, conn Connection, err error)
}
ErrorHook fires on message handling errors.
type Extension ¶
type Extension struct {
*forge.BaseExtension
// contains filtered or unexported fields
}
Extension implements forge.Extension for streaming functionality.
func NewExtension ¶
func NewExtension(opts ...ConfigOption) *Extension
NewExtension creates a new streaming extension with functional options.
Returns the concrete *Extension rather than forge.Extension because the type carries surface the interface does not — RegisterRoutes, RegisterHook, RegisterCodec, Manager — and every one of those is needed in ordinary use. Returning the interface made the documented quick-start unable to compile.
This widens the return type rather than narrowing it: *Extension satisfies forge.Extension, so `var e forge.Extension = streaming.NewExtension(...)` still works.
func NewExtensionWithConfig ¶
NewExtensionWithConfig creates a new streaming extension with a complete config.
func (*Extension) AsyncAPISpec ¶
func (e *Extension) AsyncAPISpec() *forge.AsyncAPISpec
AsyncAPISpec generates AsyncAPI 3.0.0 specification for the streaming extension This documents all streaming channels, operations, and message types.
func (*Extension) Codecs ¶ added in v1.3.0
func (e *Extension) Codecs() *CodecRegistry
Codecs returns the codec registry for direct access.
func (*Extension) DashboardContributor ¶ added in v1.3.0
func (e *Extension) DashboardContributor() contributor.LocalContributor
DashboardContributor implements dashboard.DashboardAware. Returns a streaming dashboard contributor for auto-registration. Uses resolver closures so the manager/config are resolved at render time, not at discovery time (when they may not yet be initialized).
func (*Extension) Hooks ¶ added in v1.3.0
func (e *Extension) Hooks() *HookRegistry
Hooks returns the hook registry for direct access.
func (*Extension) RegisterCodec ¶ added in v1.3.0
RegisterCodec adds a message codec for a specific content type.
func (*Extension) RegisterContractContributor ¶ added in v1.6.4
func (e *Extension) RegisterContractContributor( disp *dispatcher.Dispatcher, reg dashcontract.Registry, wreg dashcontract.WardenRegistry, ) error
RegisterContractContributor implements dashboard.ContractContributorAware. Wires the streaming-contract handlers (slice f migration target) into the dashboard's contract dispatcher and registers the embedded YAML manifest. Coexists with DashboardContributor: both are registered during dashboard startup, so the legacy /dashboard/ext/streaming/* and the new /dashboard/contract/streaming-contract/* paths both stay live during the migration window. See extensions/dashboard/contract/SLICE_F_DESIGN.md.
func (*Extension) RegisterDashboardBridge ¶ added in v1.3.0
RegisterDashboardBridge implements dashboard.BridgeAware. Registers streaming bridge functions for Go↔JS communication. Uses resolver closures so the manager/config are resolved at request time.
func (*Extension) RegisterHook ¶ added in v1.3.0
func (e *Extension) RegisterHook(hook StreamingHook)
RegisterHook adds a streaming hook for lifecycle events. Hooks can implement one or more hook interfaces (ConnectionHook, MessageHook, RawMessageHook, RoomHook, PresenceHook, ErrorHook).
func (*Extension) RegisterRoutes ¶
RegisterRoutes is a helper to register WebSocket and SSE routes with the router.
func (*Extension) Stop ¶
Stop stops the streaming extension.
Connections are drained before the manager is torn down. Drain was implemented but never called from anywhere, so shutdown dropped every live socket without notice — clients saw an abrupt close and could not tell a deploy from a crash, which matters because the two deserve different reconnect behaviour.
func (*Extension) UnregisterHook ¶ added in v1.3.0
UnregisterHook removes a streaming hook by name.
type HookRegistry ¶ added in v1.3.0
type HookRegistry struct {
// contains filtered or unexported fields
}
HookRegistry manages streaming hooks and dispatches events.
Hooks fire in registration order. Several of the fire methods are a pipeline — FireOnMessageReceived threads the message through each hook in turn, and FireOnConnect stops at the first rejection — so the order has to be defined and stable, not whatever a map range happens to produce.
func NewHookRegistry ¶ added in v1.3.0
func NewHookRegistry() *HookRegistry
NewHookRegistry creates a new hook registry.
func (*HookRegistry) Add ¶ added in v1.3.0
func (r *HookRegistry) Add(hook StreamingHook)
Add registers a hook. The hook is type-asserted to categorize it into the appropriate dispatch lists.
Registering a name that already exists replaces the hook in place, keeping its original position in the dispatch order.
func (*HookRegistry) Close ¶ added in v1.9.5
func (r *HookRegistry) Close() error
Close shuts down the delivery worker pool and waits for in-flight delivery hooks to finish. It is safe to call concurrently and more than once; calls after the first are no-ops. Deliveries fired after Close are dropped.
func (*HookRegistry) DroppedDeliveries ¶ added in v1.9.5
func (r *HookRegistry) DroppedDeliveries() uint64
DroppedDeliveries returns the number of delivery-hook batches that were never run, either because the pool's queue was saturated or because the registry was already closed. Delivery hooks are non-blocking by contract, so overload is shed here rather than pushed back onto the delivery path — this counter is how that shedding becomes visible. A steadily climbing value means hooks are too slow for the message rate, and any hook doing billing or audit work is losing events.
func (*HookRegistry) FireOnConnect ¶ added in v1.3.0
func (r *HookRegistry) FireOnConnect(ctx context.Context, conn streaming.EnhancedConnection) error
FireOnConnect fires ConnectionHook.OnConnect for all registered hooks. Returns the first error encountered, which should be used to reject the connection.
func (*HookRegistry) FireOnDisconnect ¶ added in v1.3.0
func (r *HookRegistry) FireOnDisconnect(ctx context.Context, conn streaming.EnhancedConnection)
FireOnDisconnect fires ConnectionHook.OnDisconnect for all registered hooks. Errors are ignored (post-hook).
func (*HookRegistry) FireOnError ¶ added in v1.3.0
func (r *HookRegistry) FireOnError(ctx context.Context, conn streaming.EnhancedConnection, err error)
FireOnError fires ErrorHook.OnError for all hooks (post-hook).
func (*HookRegistry) FireOnMessageDelivered ¶ added in v1.3.0
func (r *HookRegistry) FireOnMessageDelivered(ctx context.Context, conn streaming.EnhancedConnection, msg *streaming.Message)
FireOnMessageDelivered fires MessageHook.OnMessageDelivered on a bounded worker pool. This is non-blocking to avoid slowing down message delivery: the call is made once per recipient, so a broadcast to a large room reaches this path thousands of times for a single message.
If the pool's queue is saturated the batch is dropped rather than queued or awaited, because blocking here would stall delivery itself.
func (*HookRegistry) FireOnMessageReceived ¶ added in v1.3.0
func (r *HookRegistry) FireOnMessageReceived(ctx context.Context, conn streaming.EnhancedConnection, msg *streaming.Message) (*streaming.Message, error)
FireOnMessageReceived fires MessageHook.OnMessageReceived for all hooks in sequence. Each hook can transform or block (return nil) the message.
func (*HookRegistry) FireOnPresenceChange ¶ added in v1.3.0
func (r *HookRegistry) FireOnPresenceChange(ctx context.Context, userID, oldStatus, newStatus string)
FireOnPresenceChange fires PresenceHook.OnPresenceChange for all hooks (post-hook).
func (*HookRegistry) FireOnRawMessage ¶ added in v1.3.0
func (r *HookRegistry) FireOnRawMessage(ctx context.Context, conn streaming.EnhancedConnection, data []byte) ([]byte, error)
FireOnRawMessage fires RawMessageHook.OnRawMessage for all hooks in sequence. Each hook can transform the bytes or block (return error) the message.
func (*HookRegistry) FireOnRoomCreate ¶ added in v1.3.0
FireOnRoomCreate fires RoomHook.OnRoomCreate for all hooks. Returns the first error encountered, which should be used to reject creation.
func (*HookRegistry) FireOnRoomDelete ¶ added in v1.3.0
func (r *HookRegistry) FireOnRoomDelete(ctx context.Context, roomID string)
FireOnRoomDelete fires RoomHook.OnRoomDelete for all hooks (post-hook).
func (*HookRegistry) FireOnRoomJoin ¶ added in v1.3.0
func (r *HookRegistry) FireOnRoomJoin(ctx context.Context, conn streaming.EnhancedConnection, roomID string) error
FireOnRoomJoin fires RoomHook.OnRoomJoin for all hooks. Returns the first error encountered, which should be used to reject the join.
func (*HookRegistry) FireOnRoomLeave ¶ added in v1.3.0
func (r *HookRegistry) FireOnRoomLeave(ctx context.Context, conn streaming.EnhancedConnection, roomID string)
FireOnRoomLeave fires RoomHook.OnRoomLeave for all hooks (post-hook).
func (*HookRegistry) List ¶ added in v1.3.0
func (r *HookRegistry) List() []StreamingHook
List returns all registered hooks in registration order.
func (*HookRegistry) Remove ¶ added in v1.3.0
func (r *HookRegistry) Remove(name string)
Remove unregisters a hook by name.
type InviteOptions ¶
type InviteOptions = internal.InviteOptions
type JSONCodec ¶ added in v1.3.0
type JSONCodec struct{}
JSONCodec encodes/decodes messages as JSON. This is the default codec.
func (*JSONCodec) ContentType ¶ added in v1.3.0
type Manager ¶
Core interfaces.
func GetManager ¶
GetManager retrieves the streaming Manager from the container. Returns error if not found or type assertion fails.
func GetManagerFromApp ¶
GetManagerFromApp retrieves the streaming Manager from the app. Returns error if not found or type assertion fails.
func MustGetManager ¶
MustGetManager retrieves the streaming Manager from the container. Panics if not found or type assertion fails.
func MustGetManagerFromApp ¶
MustGetManagerFromApp retrieves the streaming Manager from the app. Panics if not found or type assertion fails.
func NewManager ¶
func NewManager( config Config, roomStore RoomStore, channelStore ChannelStore, messageStore MessageStore, presenceTracker PresenceTracker, typingTracker TypingTracker, distributed DistributedBackend, logger forge.Logger, metrics forge.Metrics, opts ...ManagerOption, ) Manager
NewManager creates a new streaming manager.
type ManagerOption ¶ added in v0.10.0
type ManagerOption func(*manager)
ManagerOption configures the manager.
func WithCodecRegistry ¶ added in v1.3.0
func WithCodecRegistry(cr *CodecRegistry) ManagerOption
WithCodecRegistry sets the codec registry for message encoding/decoding.
func WithCoordinator ¶ added in v0.10.0
func WithCoordinator(c coordinator.StreamCoordinator) ManagerOption
WithCoordinator sets the distributed coordinator.
func WithFilterChain ¶ added in v0.10.0
func WithFilterChain(fc filters.FilterChain) ManagerOption
WithFilterChain sets the message filter chain.
func WithHookRegistry ¶ added in v1.3.0
func WithHookRegistry(hr *HookRegistry) ManagerOption
WithHookRegistry sets the hook registry for lifecycle hooks.
func WithManagerHealthChecker ¶ added in v0.10.0
func WithManagerHealthChecker(hc lb.HealthChecker) ManagerOption
WithManagerHealthChecker sets the health checker.
func WithManagerLoadBalancer ¶ added in v0.10.0
func WithManagerLoadBalancer(l lb.LoadBalancer) ManagerOption
WithManagerLoadBalancer sets the load balancer.
func WithManagerNodeID ¶ added in v0.10.0
func WithManagerNodeID(id string) ManagerOption
WithNodeID sets the node ID for distributed mode.
func WithMessageAuthorizer ¶ added in v1.9.5
func WithMessageAuthorizer(ma streamauth.MessageAuthorizer) ManagerOption
WithMessageAuthorizer sets the message authorizer. Sends, edits, deletes and reactions are checked against it.
func WithRateLimiter ¶ added in v0.10.0
func WithRateLimiter(rl ratelimit.RateLimiter) ManagerOption
WithRateLimiter sets the rate limiter.
func WithRoomAuthorizer ¶ added in v1.9.5
func WithRoomAuthorizer(ra streamauth.RoomAuthorizer) ManagerOption
WithRoomAuthorizer sets the room authorizer. Join, leave and room-targeted sends are checked against it.
func WithSessionStore ¶ added in v0.10.0
func WithSessionStore(ss SessionStore) ManagerOption
WithSessionStore sets the session store for session resumption.
func WithValidator ¶ added in v0.10.0
func WithValidator(v validation.MessageValidator) ManagerOption
WithValidator sets the message validator.
type ManagerStats ¶
type ManagerStats = internal.ManagerStats
type MemberOptions ¶
type MemberOptions = internal.MemberOptions
type Message ¶
Message types.
func NewEventMessage ¶ added in v1.9.5
NewEventMessage builds a frame carrying a domain event, named so the generated client can bind it.
Type is MessageTypeMessage and Event is the domain name -- never the reverse, which is the mistake this constructor exists to make unavailable. Callers wanting a different transport kind may set Type afterwards; the client honours Event regardless of the kind it rides on, which is what makes the existing system-kind events in manager.go (message.deleted, message.edited) bindable without being reclassified.
ID, UserID and the routing fields are deliberately left alone. They are the producer's, and identity in particular has semantics -- deduplication, history -- that a wire-contract helper has no business inventing. Timestamp is set because a frame without one marshals as the zero time, which is a wrong answer rather than an absent one.
An event whose name collides with a reserved transport kind is accepted and is a mistake: the client will look for a binding named "presence" and find none. It is not rejected here because the failure is visible -- an event name always takes the client's event branch, so the frame is reported rather than dropped -- and because a constructor that can fail is a worse trade than a caller running IsTransportKind when the name is not a literal.
func NewLifecycleMessage ¶ added in v1.9.5
NewLifecycleMessage builds a transport frame announcing a connection lifecycle moment -- a ping, a kick, a shutdown -- named in Metadata rather than in Event.
Event is left empty, and that is the entire point of this constructor. Event is the binding key: it is what the generated client's manifest is keyed on, one row per AsyncAPI domain message, and what forgeStreamingDecoder reads first. A lifecycle name sitting in Event is therefore a name no manifest binds, and worse, it is non-empty, so the decoder takes its event branch and never reaches the reserved-kind filter that exists to drop transport frames quietly. The frame is passed through to the runtime, no slot matches it, and it surfaces through onUnknown as an unknown message on a channel that is working exactly as designed. For a heartbeat firing on a ticker for every connection that is a permanent recurring false signal -- into an application's own onUnknown, which is typically wired to metrics or Sentry.
The alternatives were both worse. Leaving the name in Event costs every heartbeat a spurious unknown-message report and cannot be fixed on the decoder side, because a lifecycle name and a genuine system-kind domain event (message.deleted, message.edited in manager.go) have the same shape on the wire and no decoder-side rule can separate them. Dropping the name entirely would make the frames clean but would throw away information a client may legitimately want -- a client that wants to show "you were removed by a moderator" needs to know a kicked frame from an idle_cleanup one. Metadata carries the name where a curious client can still read it, while the frame stays a pure transport frame by shape: it sets only Type, so the client drops it silently, which is the correct outcome for a frame no manifest was ever going to bind.
This is a deliberate wire change. A consumer previously reading event: "kicked" must now read metadata.lifecycle.
ID, UserID, Data and the routing fields are left to the caller for the same reason NewEventMessage leaves them: they are the producer's, and identity in particular carries deduplication and history semantics a wire-contract helper has no business inventing. Timestamp is set because a frame without one marshals as the zero time, which is a wrong answer rather than an absent one.
type MessageEdit ¶
type MessageEdit = internal.MessageEdit
type MessageHandler ¶
type MessageHandler = internal.MessageHandler
type MessageHook ¶ added in v1.3.0
type MessageHook interface {
StreamingHook
// OnMessageReceived is called before message processing. Can transform or block (return nil).
OnMessageReceived(ctx context.Context, conn Connection, msg *Message) (*Message, error)
// OnMessageDelivered is called after delivery (non-blocking, runs async).
OnMessageDelivered(ctx context.Context, conn Connection, msg *Message)
}
MessageHook fires on message events.
type MessageReaction ¶
type MessageReaction = internal.MessageReaction
type MessageSearchQuery ¶
type MessageSearchQuery = internal.MessageSearchQuery
type MessageStore ¶
type MessageStore = internal.MessageStore
type ModerationEvent ¶
type ModerationEvent = internal.ModerationEvent
type NodeChangeEvent ¶
type NodeChangeEvent = internal.NodeChangeEvent
type NodeChangeHandler ¶
type NodeChangeHandler = internal.NodeChangeHandler
type OnlineStats ¶
type OnlineStats = internal.OnlineStats
type OutboundFrame ¶ added in v1.9.5
type OutboundFrame struct {
// Data is the encoded payload. The queue retains it until it is written, so
// callers must not reuse the slice.
Data []byte
// Type is the streaming message type, one of the MessageType* constants. It
// selects the overflow policy; empty means unknown, which is treated
// conservatively.
Type string
// Binary requests a binary frame. A text frame promises valid UTF-8, and a
// browser fails the connection with close code 1007 when that is broken.
Binary bool
}
OutboundFrame is a pre-encoded frame plus the two things its bytes no longer carry: the streaming message type it was encoded from, and whether the wire needs a binary frame rather than a text one.
type PresenceFilters ¶
type PresenceFilters = internal.PresenceFilters
type PresenceHook ¶ added in v1.3.0
type PresenceHook interface {
StreamingHook
// OnPresenceChange is called after a user's presence status changes.
OnPresenceChange(ctx context.Context, userID, oldStatus, newStatus string)
}
PresenceHook fires on presence changes.
type PresenceOptions ¶
type PresenceOptions = internal.PresenceOptions
type PresenceStore ¶
type PresenceStore = internal.PresenceStore
type RawMessageHook ¶ added in v1.3.0
type RawMessageHook interface {
StreamingHook
// OnRawMessage processes raw bytes before decoding. Return error to drop the message.
OnRawMessage(ctx context.Context, conn Connection, data []byte) ([]byte, error)
}
RawMessageHook fires before deserialization on raw bytes from the connection.
type RoomHook ¶ added in v1.3.0
type RoomHook interface {
StreamingHook
// OnRoomJoin is called before join. Return error to reject.
OnRoomJoin(ctx context.Context, conn Connection, roomID string) error
// OnRoomLeave is called after leave.
OnRoomLeave(ctx context.Context, conn Connection, roomID string)
// OnRoomCreate is called before room creation. Return error to reject.
OnRoomCreate(ctx context.Context, room Room) error
// OnRoomDelete is called after room deletion.
OnRoomDelete(ctx context.Context, roomID string)
}
RoomHook fires on room lifecycle events.
type RoomOptions ¶
type RoomOptions = internal.RoomOptions
type SendQueueStats ¶ added in v1.9.5
type SendQueueStats struct {
Capacity int
Depth int
Enqueued uint64
Written uint64
Dropped uint64
OverflowDisconnects uint64
WriteErrors uint64
Closed bool
}
SendQueueStats is a snapshot of one connection's outbound queue. The manager can read it off a connection with a type assertion:
if s, ok := conn.(interface{ SendQueueStats() streaming.SendQueueStats }); ok {
depth := s.SendQueueStats().Depth
}
type SessionSnapshot ¶ added in v0.10.0
type SessionSnapshot struct {
SessionID string `json:"session_id"`
UserID string `json:"user_id"`
Rooms []string `json:"rooms"`
Channels []string `json:"channels"`
Metadata map[string]string `json:"metadata,omitempty"`
DisconnectedAt time.Time `json:"disconnected_at"`
// LastEventIDs is the position each channel had reached when the session
// dropped, so a resumption can ask for the gap instead of resynchronising.
LastEventIDs map[string]string `json:"last_event_ids,omitempty"`
}
SessionSnapshot captures the state of a connection for resumption.
type SessionStore ¶ added in v0.10.0
type SessionStore interface {
// Save stores a session snapshot with a TTL.
Save(ctx context.Context, snapshot *SessionSnapshot, ttl time.Duration) error
// Get retrieves a session snapshot by session ID.
Get(ctx context.Context, sessionID string) (*SessionSnapshot, error)
// Delete removes a session snapshot.
Delete(ctx context.Context, sessionID string) error
// Close releases any background resources held by the store. It must be
// safe to call more than once.
Close() error
}
SessionStore stores session snapshots for resumption.
func NewInMemorySessionStore ¶ added in v0.10.0
func NewInMemorySessionStore() SessionStore
NewInMemorySessionStore creates an in-memory session store.
type StreamingHook ¶ added in v1.3.0
type StreamingHook interface {
Name() string
}
StreamingHook is the base interface for all streaming hooks. Hooks implement one or more of the optional hook interfaces below.
type TextCodec ¶ added in v1.3.0
type TextCodec struct{}
TextCodec handles plain text data. On decode, it stores the text in msg.Data as a string. On encode, it converts msg.Data to a string and returns bytes.
func (*TextCodec) ContentType ¶ added in v1.3.0
type TypingStore ¶
type TypingStore = internal.TypingStore
type TypingTracker ¶
type TypingTracker = internal.TypingTracker
type UserPresence ¶
type UserPresence = internal.UserPresence
type UserPresenceStats ¶
type UserPresenceStats = internal.UserPresenceStats
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
storetest
Package storetest holds the behavioural contract every MessageStore backend must satisfy, so the backends can be proven to agree rather than merely to each work.
|
Package storetest holds the behavioural contract every MessageStore backend must satisfy, so the backends can be proven to agree rather than merely to each work. |
|
Package contract is the streaming extension's dashboard contract contributor.
|
Package contract is the streaming extension's dashboard contract contributor. |
|
examples
|
|
|
chat
command
|
|