roadrunner_gleam/push

Responses that stay open and push data as messages arrive, such as server-sent events.

The response’s headers go out first, then whatever on_init sends. After that the handler runs for every message sent to the Subject that on_init got, or selected with with_selector, and sends data to the client, until it stops or the client goes away. It works the same over HTTP/1.1, HTTP/2 and HTTP/3. A HEAD request gets the headers only, and on_init is not called.

fn events(request: Request) -> Response {
  push.new(
    on_init: fn(subject) {
      pubsub.subscribe(subject)
      push.continue(Nil)
      |> push.send_event(push.event("connected") |> push.event_retry(5000))
    },
    handler: fn(state, message) {
      case message {
        push.Custom(text) ->
          push.continue(state) |> push.send_event(push.event(text))
        push.Draining(_) -> push.stop(state)
      }
    },
  )
  |> push.response(200)
  |> http_response.set_header("content-type", "text/event-stream")
}

Types

A response that pushes, built with new and the functions that follow it.

pub opaque type Builder(state, custom)

A server-sent event, built with event and the functions that follow it.

pub opaque type Event

What the handler gets.

pub type Message(custom) {
  Custom(custom)
  Draining(remaining: Int)
}

Constructors

  • Custom(custom)

    A message sent to the Subject that on_init got, or one selected by with_selector.

  • Draining(remaining: Int)

    The listener is draining: stop within remaining milliseconds, or the response is closed for you.

What to do after a callback, built with continue or stop and the functions that follow them.

pub opaque type Next(state, custom)

Values

pub fn continue(state: state) -> Next(state, custom)

Keep the response open.

pub fn event(data: String) -> Event

A server-sent event with this data. Data with line breaks is sent as several data: lines, which the browser joins back.

pub fn event_id(event: Event, id: String) -> Event

The event’s id, which the browser sends back as last-event-id when it reconnects.

pub fn event_name(event: Event, name: String) -> Event

The event’s name: the browser’s EventSource delivers it to the listeners of that name instead of onmessage.

pub fn event_retry(event: Event, milliseconds: Int) -> Event

How many milliseconds the browser waits before reconnecting.

pub fn event_to_bytes(event: Event) -> bytes_tree.BytesTree

The event as it goes on the wire.

pub fn new(
  on_init on_init: fn(process.Subject(custom)) -> Next(
    state,
    custom,
  ),
  handler handler: fn(state, Message(custom)) -> Next(
    state,
    custom,
  ),
) -> Builder(state, custom)

A response that pushes. on_init runs once, before the headers go out, and gets a Subject owned by the response: messages sent to it reach handler as Custom. What it sends goes out right after the headers.

pub fn on_disconnect(
  builder: Builder(state, custom),
  on_disconnect: fn(state) -> Nil,
) -> Builder(state, custom)

Run on_disconnect when the client goes away before the handler stops, to drop subscriptions and stop work.

pub fn response(
  builder: Builder(state, custom),
  status: Int,
) -> response.Response(response.Body)

The response, with this status. Add headers with gleam/http/response.set_header.

pub fn send(
  next: Next(state, custom),
  data: bytes_tree.BytesTree,
) -> Next(state, custom)

Send this data to the client after the callback.

pub fn send_event(
  next: Next(state, custom),
  event: Event,
) -> Next(state, custom)

Send a server-sent event to the client after the callback.

pub fn stop(state: state) -> Next(state, custom)

End the response, after sending what was given to send.

pub fn with_selector(
  next: Next(state, custom),
  selector: process.Selector(custom),
) -> Next(state, custom)

Also receive the messages this selector selects, as Custom, from now on: monitors, messages to other subjects, or anything else. It replaces the selector set before; messages to the response’s Subject always arrive.

✨ Search Document