Skip to content
Lyo Kato edited this page Apr 20, 2022 · 21 revisions

Regarding the handling of streams, basically, we just need to be aware of the handle_stream/4 callback function and the stream_send/3 function on the handler.

@impl Requiem
def handle_stream(stream_id, data, conn, state) do
  stream_send(stream_id, data, false)
  {:ok, conn, state}
end

However, you need to be careful with the stream_id.

The above example may fail.

The lower bits of stream_id change under the following conditions.

  • Whether it was created by the client or the server
  • Bidirectional or unidirectional.

(See: https://datatracker.ietf.org/doc/html/rfc9000#section-2.1)

If you try to send data from the server side using send_stream through a unidirectional stream created by the client, an exception will be thrown.

Here are two utilities.

Requiem.StreamId

It is possible to check the nature of the stream_id in the following way.

  • bidi means bidirectional
  • uni means unidirectional
Requiem.StreamId.is_bidi?(stream_id)
Requiem.StreamId.is_uni?(stream_id)
Requiem.StreamId.is_server_initiated?(stream_id)
Requiem.StreamId.is_client_initiated?(stream_id)

If you just want to know if it can be read or written, you can also write the following.

Requiem.StreamId.is_readable?(stream_id)
Requiem.StreamId.is_writable?(stream_id)

Open Stream

It is also possible to create a new stream on the server side. To do so, use stream_open/2.

The first argument is a boolean indicating whether it is bidirectional or not, and the second argument is an arbitrary string to be used for identification or message relay when the result of stream_open/2 is received in an asynchronous message.

@impl Requiem
def handle_stream(stream_id, data, conn, state) do
  stream_open(false, "NEW_UNI_STREAM" <> data)
  {:ok, new_conn, state}
end

@impl Request
def handle_info({:stream_open, stream_id, message}, conn, state) do
  stream_send(stream_id, message, false)
  {:noreply, conn, state}
end

Then, as in the example above, handle_info can receive the results of stream_open. The newly prepared stream_id is included as an argument, which can be used to send a message to the client using stream_send.

Clone this wiki locally