ReqServerSentEvents.Frame (ReqServerSentEvents v0.2.1)

Copy Markdown View Source

Pure SSE frame parser. No IO, no processes, no external dependencies.

An SSE frame is a sequence of field: value lines terminated by a blank line (\n\n). Recognised fields: event, data, id, retry. Lines starting with : are comments. Multiple data: lines within one frame are concatenated with "\n".

Summary

Functions

Parse one complete raw frame string (without the trailing "\n\n") into a %Frame{}.

Split a byte buffer on the SSE frame delimiter.

Types

t()

@type t() :: %ReqServerSentEvents.Frame{
  comments: [String.t()],
  data: String.t() | nil,
  event: String.t() | nil,
  id: String.t() | nil,
  retry: non_neg_integer() | nil
}

Functions

parse(raw)

@spec parse(binary()) :: t()

Parse one complete raw frame string (without the trailing "\n\n") into a %Frame{}.

Frames with no data: field are returned as-is — the caller decides whether to dispatch or discard them. Unknown field names are silently ignored per the SSE spec.

Examples

iex> ReqServerSentEvents.Frame.parse("event: ping\ndata: {}")
%ReqServerSentEvents.Frame{event: "ping", data: "{}"}

iex> ReqServerSentEvents.Frame.parse(": keepalive")
%ReqServerSentEvents.Frame{comments: ["keepalive"]}

split(buffer)

@spec split(binary()) :: {[binary()], binary()}

Split a byte buffer on the SSE frame delimiter.

Recognises "\n\n", "\r\n\r\n", and "\r\r" as frame delimiters per SSE spec §9.2.4. Returned frame strings retain their original line endings; parse/1 handles all three terminator forms. A leading UTF-8 byte order mark ("\uFEFF") is stripped per the spec.

Returns {complete_frames, leftover} where complete_frames is a list of raw frame strings (without the trailing delimiter) and leftover is the remaining bytes that have not yet formed a complete frame.

Examples

iex> ReqServerSentEvents.Frame.split("data: hello\n\n")
{["data: hello"], ""}

iex> ReqServerSentEvents.Frame.split("data: hello\r\n\r\n")
{["data: hello"], ""}

iex> ReqServerSentEvents.Frame.split("data: partial")
{[], "data: partial"}