URP.Stream
(urp v0.10.0)
Copy Markdown
Bidirectional URP dispatch for XInputStream/XOutputStream/XSeekable.
When we pass a stream object reference to soffice (e.g. as an InputStream in a MediaDescriptor), soffice calls methods on our object over the same TCP connection. This module handles those incoming calls while we wait for the reply to our original request.
XInputStream funcIDs (depth-first interface traversal)
XInterface: queryInterface=0, acquire=1, release=2
XInputStream: readBytes=3, readSomeBytes=4, skipBytes=5, available=6, closeInput=7XSeekable funcIDs
XInterface: queryInterface=0, acquire=1, release=2
XSeekable: seek=3, getPosition=4, getLength=5Since XInputStream and XSeekable share funcIDs 3-5, we use the URP type cache to disambiguate: each request carries a type reference telling us which interface it targets.
XOutputStream funcIDs
XInterface: queryInterface=0, acquire=1, release=2
XOutputStream: writeBytes=3, flush=4, closeOutput=5
Summary
Functions
Receive frames while handling XInputStream/XSeekable calls from soffice.
Receive frames while handling XOutputStream calls from soffice.
Spawn a linked process that iterates enumerable, sending chunks to the caller.
Try to handle a stray request as an input stream call.
Types
Functions
@spec recv_handling_input(URP.Bridge.t(), input_source() | source(), String.t() | nil) :: {binary(), URP.Bridge.t()}
Receive frames while handling XInputStream/XSeekable calls from soffice.
source is either a binary (in-memory), {:file, pid, size} for
file-backed streaming, or {:enum, buffer, reader} for enumerables.
When stream_oid is provided and the source is seekable (memory or file),
queryInterface for XSeekable is supported — enabling ZIP-based formats
like docx and xlsx.
Dispatches calls until we receive the reply to our pending request.
Returns {reply_payload, updated_conn}.
@spec recv_handling_output(URP.Bridge.t(), sink()) :: {binary(), binary() | :ok, URP.Bridge.t()}
Receive frames while handling XOutputStream calls from soffice.
sink controls where output bytes go:
nil(default) — accumulate in memory, returns{reply, binary, conn}{:path, path}— write chunks to file as they arrive, returns{reply, :ok, conn}fun/1— call with each chunk, returns{reply, :ok, conn}
@spec start_enum_reader(Enumerable.t()) :: pid()
Spawn a linked process that iterates enumerable, sending chunks to the caller.
The reader sends {pid, {:chunk, data}} for each element and {pid, :eof}
when the enumerable is exhausted. The caller receives these in fill_buffer/3.
@spec try_handle_input(URP.Bridge.t(), binary()) :: {:handled, URP.Bridge.t()} | :not_input
Try to handle a stray request as an input stream call.
Called by Bridge.recv_reply/1 when it encounters a non-reply message
outside the main stream recv loop. Returns :not_input if the request
doesn't match the active input stream context.