Francis.SSE (Francis v0.3.3)

View Source

Helper functions for Server-Sent Events (SSE) handlers generated by the Francis.sse/3 macro.

This module centralizes the SSE lifecycle logic (keepalive, join/close events, response formatting, chunked streaming) so that the generated per-route handler modules stay small. It is not intended for direct use by application code.

SSE Wire Format

Each event is encoded as one or more field: value lines followed by a blank line (\n\n). Supported fields:

  • data: – the event payload (required)
  • event: – named event type (optional, defaults to "message")
  • id: – event ID for reconnection (optional)
  • retry: – reconnection interval hint in ms (optional)

Summary

Functions

Safely calls a handler for the {:close, reason} event.

Safely calls a handler for the :join event.

Invokes the handler for a received message and formats the response. Errors are logged but do not crash the connection.

Cancels the keepalive timer during termination.

Formats a value into an SSE-encoded iodata chunk.

Translates a handler return value into an action for the SSE loop.

Reschedules the keepalive timer and sends a comment line to keep the connection alive.

Sends the initial SSE headers and switches the connection to chunked mode.

The main SSE receive loop. Waits for keepalive ticks or messages forwarded via send(socket.transport, msg).

Initializes the SSE connection, sends the join event, and enters the receive loop.

Sets up the keepalive timer if configured.

Cleans up the keepalive timer and invokes the close handler. Returns conn for the outer Plug pipeline.

Functions

call_close(handler, event, state)

Safely calls a handler for the {:close, reason} event.

If the handler doesn't pattern-match close events, silently succeeds.

call_join(handler, state)

Safely calls a handler for the :join event.

If the handler doesn't pattern-match :join (raises FunctionClauseError or MatchError), silently returns {:noreply, state} — join handling is optional.

call_received(handler, msg, state)

Invokes the handler for a received message and formats the response. Errors are logged but do not crash the connection.

cancel_keepalive(state)

Cancels the keepalive timer during termination.

format_event(fields)

Formats a value into an SSE-encoded iodata chunk.

Accepts:

  • a binary string – sent as data: <string>\n\n
  • a map or list – JSON-encoded and sent as data: <json>\n\n
  • a map with :event, :data, and optionally :id / :retry keys – sent with the corresponding SSE fields

format_response(arg1, state)

Translates a handler return value into an action for the SSE loop.

Returns {:chunk, iodata, state} when there is data to send, or {:noreply, state} when there is nothing to send.

handle_keepalive(conn, state)

Reschedules the keepalive timer and sends a comment line to keep the connection alive.

init_conn(conn)

Sends the initial SSE headers and switches the connection to chunked mode.

loop(conn, state, handler)

The main SSE receive loop. Waits for keepalive ticks or messages forwarded via send(socket.transport, msg).

run(conn, state, handler)

Initializes the SSE connection, sends the join event, and enters the receive loop.

Returns conn when the loop terminates so the outer handle_response/3 receives a Plug.Conn struct.

setup_keepalive(state)

Sets up the keepalive timer if configured.

terminate(conn, reason, handler, state)

Cleans up the keepalive timer and invokes the close handler. Returns conn for the outer Plug pipeline.