beryl/wire/codec
Pluggable wire codec for beryl.
A Codec plugs the runtime into any over-the-wire framing. The
canonical implementation is beryl/wire.phoenix_codec(), which ships
the Phoenix array format ([join_ref, ref, topic, event, payload]).
To run beryl over your own framing, build a Codec value and pass it
to beryl.config(codec). The runtime decodes inbound frames and produces
outbound frames using the configured callbacks. Codec authors can exercise
those callbacks directly with the public apply_* functions.
All codecs must normalise inbound traffic to the Inbound shape so
the runtime can stay framing-agnostic.
pub type CodecA wire codec.
Codec is opaque. Build one with new. For binary support, add
with_binary_decoder.
DecodeError
Section titled “DecodeError”pub type DecodeError { InvalidJson(reason: String) InvalidFormat(reason: String) MissingField(name: String)}Errors a codec may emit when decoding inbound bytes.
Constructors
Section titled “Constructors”InvalidJson
Section titled “InvalidJson”InvalidJson(reason: String)The bytes were not valid JSON; reason describes the parse error.
InvalidFormat
Section titled “InvalidFormat”InvalidFormat(reason: String)The message was valid JSON but did not match the expected framing;
reason describes the mismatch.
MissingField
Section titled “MissingField”MissingField(name: String)A required field was absent; name is the missing field.
pub type Frame { TextFrame(String) BinaryFrame(BitArray)}Encoded WebSocket frame returned by a codec.
Constructors
Section titled “Constructors”TextFrame
Section titled “TextFrame”TextFrame(String)A UTF-8 text frame.
BinaryFrame
Section titled “BinaryFrame”BinaryFrame(BitArray)A binary frame.
Inbound
Section titled “Inbound”pub type InboundA normalized inbound message.
Inbound is opaque: construct it with inbound and read it with the
inbound_* accessors. The hidden record lets beryl add fields with
defaults without breaking custom codecs.
InboundKind
Section titled “InboundKind”pub type InboundKind { Join Leave Heartbeat Event(String)}Structural inbound message kind used for protocol dispatch.
Constructors
Section titled “Constructors”JoinA client joining a topic.
LeaveA client leaving a topic.
Heartbeat
Section titled “Heartbeat”HeartbeatA heartbeat/keep-alive message.
Event(String)A user-defined event; the wrapped String is the event name.
ReplyStatus
Section titled “ReplyStatus”pub type ReplyStatus { StatusOk StatusError}Status of a reply produced by the app.
Constructors
Section titled “Constructors”StatusOk
Section titled “StatusOk”StatusOkThe handler succeeded ("ok" in Phoenix framing).
StatusError
Section titled “StatusError”StatusErrorThe handler failed ("error" in Phoenix framing).
Functions
Section titled “Functions”apply_decode_binary
Section titled “apply_decode_binary”pub fn apply_decode_binary( Codec, data: BitArray) -> option.Option(Result(Inbound, DecodeError))Decode a binary frame with a codec, if it has a binary decoder.
Returns None when the codec has no decoder configured with
with_binary_decoder.
apply_decode_text
Section titled “apply_decode_text”pub fn apply_decode_text( Codec, text: String) -> Result(Inbound, DecodeError)Decode a text frame with a codec.
Codec authors can use this to test the decoder supplied to new.
apply_encode_close
Section titled “apply_encode_close”pub fn apply_encode_close( Codec, join_ref: option.Option(String), topic: String) -> option.Option(Frame)Encode a graceful topic close with a codec, if it has a close encoder.
Returns None when the codec has no encoder configured with
with_close_encoder.
apply_encode_error
Section titled “apply_encode_error”pub fn apply_encode_error( Codec, join_ref: option.Option(String), topic: String) -> option.Option(Frame)Encode an abnormal topic termination with a codec, if it has an error encoder.
Returns None when the codec has no encoder configured with
with_error_encoder.
apply_encode_heartbeat_reply
Section titled “apply_encode_heartbeat_reply”pub fn apply_encode_heartbeat_reply( Codec, ref: option.Option(String)) -> FrameEncode a heartbeat reply with a codec.
apply_encode_push
Section titled “apply_encode_push”pub fn apply_encode_push( Codec, topic: String, event: String, payload: json.Json) -> FrameEncode a server-initiated push with a codec.
apply_encode_reply
Section titled “apply_encode_reply”pub fn apply_encode_reply( Codec, join_ref: option.Option(String), ref: option.Option(String), topic: String, status: ReplyStatus, response: json.Json) -> FrameEncode a reply with a codec.
format_decode_error
Section titled “format_decode_error”pub fn format_decode_error(DecodeError) -> StringFormat a DecodeError as human-readable text.
The runtime log messages and wire.format_decode_error use this text.
inbound
Section titled “inbound”pub fn inbound( join_ref: option.Option(String), ref: option.Option(String), topic: String, kind: InboundKind, payload: dynamic.Dynamic) -> InboundConstruct a normalized inbound message.
join_ref: optional client-side reference assigned at join time (used by some Phoenix replies; codecs without this concept should passNone)ref: optional per-message reference for reply correlationtopic: subscription topic (e.g."room:lobby","doc:abc")kind: structural protocol event or user eventpayload: message body as aDynamicfor the app to decode
inbound_join_ref
Section titled “inbound_join_ref”pub fn inbound_join_ref(Inbound) -> option.Option(String)Return the inbound message's join-time client reference, if any.
inbound_kind
Section titled “inbound_kind”pub fn inbound_kind(Inbound) -> InboundKindReturn the inbound message's structural kind.
inbound_payload
Section titled “inbound_payload”pub fn inbound_payload(Inbound) -> dynamic.DynamicReturn the inbound message body for the app to decode.
inbound_ref
Section titled “inbound_ref”pub fn inbound_ref(Inbound) -> option.Option(String)Return the inbound message's per-message reply reference, if any.
inbound_topic
Section titled “inbound_topic”pub fn inbound_topic(Inbound) -> StringReturn the inbound message's subscription topic.
pub fn new( decode_text: fn(String) -> Result(Inbound, DecodeError), encode_reply: fn(option.Option(String), option.Option(String), String, ReplyStatus, json.Json) -> Frame, encode_push: fn(String, String, json.Json) -> Frame, encode_heartbeat_reply: fn(option.Option(String)) -> Frame) -> CodecBuild a codec without an inbound binary decoder.
decode_text: decode raw inbound text into a normalizedInbound.encode_reply: encode a reply to a client message:(join_ref, ref, topic, status, response_payload).encode_push: encode a server-initiated push:(topic, event, payload).encode_heartbeat_reply: encode a heartbeat reply for a given clientref.
The resulting codec has no binary decoder; binary WebSocket frames are
delivered to the app's update as a raw Binary event. Add a binary
decoder with with_binary_decoder.
uses_topicless_events
Section titled “uses_topicless_events”pub fn uses_topicless_events(Codec) -> BoolWhether the codec routes events without an explicit topic.
Codec authors can use this to test with_topicless_events.
with_binary_decoder
Section titled “with_binary_decoder”pub fn with_binary_decoder( Codec, fn(BitArray) -> Result(Inbound, DecodeError)) -> CodecAdd a binary decoder to a codec.
When set, the decoder converts binary WebSocket frames to a normalized
Inbound via decode_binary. The app's update function does not receive
a raw Binary event.
with_close_encoder
Section titled “with_close_encoder”pub fn with_close_encoder( Codec, fn(option.Option(String), String) -> Frame) -> CodecAdd a topic-close encoder to a codec.
When set, the runtime sends this frame when one of the client's topics
terminates gracefully (leave, server shutdown, heartbeat
eviction): (join_ref, topic). Phoenix clients rely on phx_close to
leave the joined state instead of waiting out push timeouts.
with_error_encoder
Section titled “with_error_encoder”pub fn with_error_encoder( Codec, fn(option.Option(String), String) -> Frame) -> CodecAdd a topic-error encoder to a codec.
When set, the runtime sends this frame when one of the client's topics
terminates abnormally (crashed or stopped with an error):
(join_ref, topic). Phoenix clients rely on phx_error to schedule an
automatic rejoin.
with_topicless_events
Section titled “with_topicless_events”pub fn with_topicless_events(Codec) -> CodecMark a codec's events as topicless.
Some framings, such as Socket.IO-style protocols, do not carry a per-frame topic. When set, an inbound event whose topic is empty is routed to the socket's single joined topic. The runtime drops it when the socket has zero or multiple joins. Topic-carrying codecs (like the Phoenix codec) must leave this off so the runtime rejects empty-topic frames instead of inferring a topic.
