beryl/channel
Channel - Topic-based message callbacks
Channels handle real-time communication for topic patterns. Each channel defines how to handle joins, incoming messages, and cleanup.
Example
Section titled “Example”pub type RoomAssigns { RoomAssigns(user_id: String, room_id: String)}
pub fn new() -> Channel(RoomAssigns, info) { channel.new(join) |> channel.with_handle_in(handle_in) |> channel.with_terminate(terminate)}
fn join(topic, payload, socket) { let assigns = RoomAssigns(user_id: "...", room_id: "...") channel.JoinOk(reply: None, socket: socket.set_assigns(socket, assigns))}Channel
Section titled “Channel”Channel behavior definition
Type parameters:
assigns: Socket state type for this channelinfo: Server-originated/internal message type delivered tohandle_info(seeberyl.send_info). Channels that do not usehandle_infoleave this parameter generic.
pub type Channel(a, b)HandleResult
Section titled “HandleResult”Result of handling an incoming message
pub type HandleResult(a) { NoReply(socket: socket.Socket(a)) Reply( event: String, payload: json.Json, socket: socket.Socket(a) ) ReplyError( payload: json.Json, socket: socket.Socket(a) ) Push( event: String, payload: json.Json, socket: socket.Socket(a) ) Stop(reason: StopReason)}Constructors
Section titled “Constructors”NoReply(socket: socket.Socket(a))
Section titled “NoReply(socket: socket.Socket(a))”Continue without sending a reply
`Reply(
Section titled “`Reply(”event: String, payload: json.Json, socket: socket.Socket(a) )`
Send a successful reply to the client in response to their message.
When returned from handle_in, this is encoded as a Phoenix phx_reply
with "status": "ok", tied to the original client ref — the event
field is ignored by the coordinator. When returned from handle_info
(where no client ref exists), it is sent as a push using event as the
event name.
The status is always "ok": Reply("error", payload, socket) reaches
the client's push.receive("ok", ...) hook, not receive("error", ...).
Use ReplyError to signal failure.
`ReplyError(
Section titled “`ReplyError(”payload: json.Json, socket: socket.Socket(a) )`
Send an error reply to the client in response to their message
("status": "error" in Phoenix framing, delivered to the client's
push.receive("error", ...) hook).
Only meaningful from handle_in for messages carrying a client ref;
from handle_info/handle_binary (where no ref exists) the reply is
dropped with a warning.
`Push(
Section titled “`Push(”event: String, payload: json.Json, socket: socket.Socket(a) )`
Push a message to the client (server-initiated)
Stop(reason: StopReason)
Section titled “Stop(reason: StopReason)”Stop the channel with a reason
JoinResult
Section titled “JoinResult”Result of joining a channel
pub type JoinResult(a) { JoinOk( reply: option.Option(json.Json), socket: socket.Socket(a) ) JoinError(reason: json.Json)}Constructors
Section titled “Constructors”`JoinOk(
Section titled “`JoinOk(”reply: option.Option(json.Json), socket: socket.Socket(a) )`
Join succeeded, optionally send a reply payload
JoinError(reason: json.Json)
Section titled “JoinError(reason: json.Json)”Join failed with error payload
StopReason
Section titled “StopReason”Why a channel is stopping.
Delivered to every channel's terminate callback. Match with a catch-all
(_) arm: new stop reasons may be added in minor releases.
pub type StopReason { Normal Shutdown HeartbeatTimeout Errored(String)}Constructors
Section titled “Constructors”Normal
Section titled “Normal”Normal shutdown (client left or disconnected cleanly)
Shutdown
Section titled “Shutdown”Server-initiated shutdown
HeartbeatTimeout
Section titled “HeartbeatTimeout”Client failed to send heartbeat within the configured timeout
Errored(String)
Section titled “Errored(String)”The channel stopped because of an error (named Errored so importing
it unqualified does not shadow the prelude's Result Error
constructor)
Functions
Section titled “Functions”decode_payload
Section titled “decode_payload”Decode an inbound channel payload into an application type.
pub fn decode_payload( dynamic.Dynamic, decode.Decoder(a)) -> Result(a, List(decode.DecodeError))Create a simple error response
pub fn error(String) -> json.Jsonerror_with_code
Section titled “error_with_code”Create an error response with code
pub fn error_with_code( Int, String) -> json.JsonCreate a new channel with just a join callback.
Other callbacks can be added using the with_* functions.
pub fn new(fn(String, dynamic.Dynamic, socket.Socket(a)) -> JoinResult(a)) -> Channel(a, b)with_handle_binary
Section titled “with_handle_binary”Add a binary message callback
pub fn with_handle_binary( Channel(a, b), fn(BitArray, socket.Socket(a)) -> HandleResult(a)) -> Channel(a, b)with_handle_in
Section titled “with_handle_in”Add an incoming message callback
pub fn with_handle_in( Channel(a, b), fn(String, dynamic.Dynamic, socket.Socket(a)) -> HandleResult(a)) -> Channel(a, b)with_handle_info
Section titled “with_handle_info”Add a server-originated OTP message callback.
The callback receives the typed info value sent via beryl.send_info.
Reply results are sent as pushes because server-originated messages do not
have a client message ref to reply to.
pub fn with_handle_info( Channel(a, b), fn(b, socket.Socket(a)) -> HandleResult(a)) -> Channel(a, b)with_terminate
Section titled “with_terminate”Add a terminate callback for cleanup
pub fn with_terminate( Channel(a, b), fn(StopReason, socket.Socket(a)) -> Nil) -> Channel(a, b)