Skip to content

beryl/transport

Transport SPI — the contract between beryl core and WebSocket transport implementations such as the beryl_mist package.

A transport implementation:

  1. Admits a connection (origin/auth policy is the transport's concern), acquiring a slot with beryl.acquire_connection_slot and binding it with beryl.bind_connection_slot.
  2. Announces the socket with socket_connected — or socket_connected_with_codec when the connection speaks a framing other than the configured codec — then register_closer.
  3. Decodes inbound frames with the codec from active_codec (see beryl/wire/codec) and routes them with route_decoded / route_binary, shedding over-rate frames via new_message_limiter / take_token and oversized frames via beryl.max_inbound_frame_bytes.
  4. Announces disconnects with socket_disconnected and releases the slot with beryl.release_connection_slot.

WebSocket data frame kinds.

pub type FrameKind {
TextFrame
BinaryFrame
}

Closed terminal outcomes for inbound frame processing.

pub type FrameOutcome {
FrameRouted
FrameOversized
FrameRateLimited
FrameDecodeFailed
}

A named logger for transport diagnostics, routed through beryl's configured logging backend.

pub type Logger

A per-connection token bucket enforcing the configured message rate at the transport edge, so a flooding socket is shed before frames are decoded or enqueued on the coordinator.

pub type RateLimiter

Cheap transport telemetry context. When disabled, starting and stopping an operation avoid VM clock calls and event construction.

pub type Telemetry

WebSocket transport implementations in beryl's telemetry schema.

pub type TelemetryTransport {
Mist
Ewe
}

Closed terminal outcomes for a matched WebSocket upgrade.

pub type UpgradeOutcome {
UpgradeSucceeded
OriginRejected
VersionRejected
AuthRejected
CapacityRejected
HandshakeFailed
}

The wire codec configured for these channels. Transports decode inbound frames with it in the connection process.

pub fn active_codec(beryl.Channels) -> codec.Codec

Log a warning with structured metadata.

pub fn log_warning(
logger: Logger,
message: String,
metadata: List(#(String, String))
) -> Nil

Create a named transport logger (e.g. "beryl.transport.mist").

pub fn logger(String) -> Logger

Create a fresh per-connection message limiter, None when no message rate is configured.

pub fn new_message_limiter(beryl.Channels) -> option.Option(RateLimiter)

Register a function that force-closes the socket's underlying connection so the coordinator can actively evict it (e.g. heartbeat timeout) instead of leaving a zombie socket whose frames are silently dropped.

pub fn register_closer(
channels: beryl.Channels,
socket_id: String,
close: fn() -> Nil
) -> Nil

Route a raw binary frame, for codecs without a binary decoder (fans out to the socket's joined topics' handle_binary).

pub fn route_binary(
channels: beryl.Channels,
socket_id: String,
data: BitArray
) -> Nil

Route a transport-decoded inbound message to the coordinator. Decode in the connection process (see active_codec) so parse cost and malformed input never reach the shared coordinator.

pub fn route_decoded(
channels: beryl.Channels,
socket_id: String,
message: codec.Inbound
) -> Nil

Route a transport-decoded binary message to the coordinator.

This is additive to route_decoded, whose text semantics are retained for third-party transport compatibility.

pub fn route_decoded_binary(
channels: beryl.Channels,
socket_id: String,
message: codec.Inbound
) -> Nil

Announce a newly connected socket. send/send_binary deliver outbound frames on this connection; assigns seeds connect-time socket assigns (type-erased internally) that channels see at join. Call register_closer immediately after this.

pub fn socket_connected(
channels: beryl.Channels,
socket_id: String,
send: fn(String) -> Result(Nil, Nil),
send_binary: fn(BitArray) -> Result(Nil, Nil),
assigns: a
) -> Nil

Announce a newly connected socket that negotiates its own wire format. Some(codec) frames this connection's outbound messages with codec instead of the configured one, so a single coordinator — sharing channels, pubsub and presence — can serve transports speaking different framings. None is equivalent to socket_connected.

pub fn socket_connected_with_codec(
channels: beryl.Channels,
socket_id: String,
send: fn(String) -> Result(Nil, Nil),
send_binary: fn(BitArray) -> Result(Nil, Nil),
codec: option.Option(codec.Codec),
assigns: a
) -> Nil

Announce that a socket's connection has closed.

pub fn socket_disconnected(
channels: beryl.Channels,
socket_id: String
) -> Nil

Take one token; returns the updated limiter and whether the frame is admitted. Transports drop the frame when False.

pub fn take_token(RateLimiter) -> #(RateLimiter, Bool)

Create a telemetry context from the channels configuration.

pub fn telemetry(
beryl.Channels,
TelemetryTransport
) -> Telemetry

Emit exactly one terminal inbound-frame event.

pub fn telemetry_frame_stop(
Telemetry,
Int,
Int,
FrameKind,
FrameOutcome
) -> Nil

Start a timed transport operation. Returns a zero sentinel when disabled.

pub fn telemetry_start(Telemetry) -> Int

Emit exactly one terminal matched-upgrade event.

pub fn telemetry_upgrade_stop(
Telemetry,
Int,
UpgradeOutcome
) -> Nil