URP.Bridge (urp v0.10.0)

Copy Markdown

Mid-level UNO operations over a URP connection.

Manages a TCP connection to a soffice process and provides functions for the UNO operations needed for document conversion: loading documents, storing to URL, and closing.

Each connection performs a handshake and bootstraps a Desktop reference on open/2. A connection handles one conversion at a time (soffice is single-threaded). Close the connection with close!/1 when done.

All functions take and return conn, following the Plug pattern. Document OIDs and conversion state are stashed on the conn struct — no separate values to track.

Example

"localhost"
|> URP.Bridge.open(2002)
|> URP.Bridge.load_document("file:///tmp/input.docx")
|> URP.Bridge.store_to_url("file:///tmp/output.pdf", "writer_pdf_Export")
|> URP.Bridge.close_document()
|> URP.Bridge.close!()

Streaming

load_document_stream/2 and store_to_stream/2 use UNO's XInputStream/XOutputStream interfaces to transfer document bytes over the URP socket, eliminating the need for a shared filesystem.

conn =
  "localhost"
  |> URP.Bridge.open(2002)
  |> URP.Bridge.load_document_stream(File.read!("input.docx"))
  |> URP.Bridge.store_to_stream(filter: "writer_pdf_Export")

pdf = conn.reply
URP.Bridge.close!(conn)

Private storage

Diagnostic functions stash results in conn.private:

conn =
  "localhost"
  |> URP.Bridge.open(2002)
  |> URP.Bridge.version()

conn.private.version
# => "26.2.0.3"

Summary

Functions

Apply soffice configuration settings via ConfigurationUpdateAccess.

Close the TCP connection.

Close the loaded document, releasing soffice resources.

Delete a temp file on soffice's filesystem via XSimpleFileAccess.kill().

List all export filter names registered in soffice.

Load a document from a file:// URL. Stashes the document OID on conn.doc_oid.

Load a document from an enumerable via XInputStream.

Load a document from a local file via XInputStream.

Load a document from in-memory bytes via XInputStream.

Load a document by writing bytes to soffice's filesystem via XSimpleFileAccess.

Query the soffice locale string over URP.

Connect to soffice, perform URP handshake, and bootstrap a Desktop reference.

Read a file from soffice's filesystem via XSimpleFileAccess.

List all service names registered in the UNO service manager.

Store a document to soffice's filesystem and read back the result.

Store a document via XOutputStream.

Store a document to a file:// URL with the given export filter.

List all document type names registered in soffice.

Query the soffice version string over URP.

Types

t()

@type t() :: %URP.Bridge{
  cleanup_url: String.t() | nil,
  ctx_oid: String.t() | nil,
  desktop_oid: String.t() | nil,
  doc_oid: String.t() | nil,
  error: String.t() | nil,
  input_ctx: map() | nil,
  max_frame_size: pos_integer(),
  private: map(),
  reader_type: non_neg_integer() | nil,
  recv_timeout: timeout(),
  reply: term(),
  reply_tid: binary() | nil,
  sfa_oid: String.t() | nil,
  smgr_oid: String.t() | nil,
  sock: :gen_tcp.socket() | nil,
  tid_cache: map()
}

Functions

apply_settings(conn, settings)

@spec apply_settings(t(), list()) :: t()

Apply soffice configuration settings via ConfigurationUpdateAccess.

Each setting is a {path, property, value} triplet where path is the registry node (e.g. "org.openoffice.Office.Common/Cache/GraphicManager"), property is the property name, and value is a boolean, integer, or string.

Settings sharing the same path are batched into a single ConfigurationUpdateAccess call for efficiency.

close!(bridge)

@spec close!(t()) :: :ok

Close the TCP connection.

close_document(conn)

@spec close_document(t()) :: t()

Close the loaded document, releasing soffice resources.

delete_file(conn, url)

@spec delete_file(t(), String.t()) :: t()

Delete a temp file on soffice's filesystem via XSimpleFileAccess.kill().

filters(conn)

@spec filters(t()) :: t()

List all export filter names registered in soffice.

Creates a FilterFactory instance and calls getElementNames() via XNameAccess. Stashes the result in conn.private.filters.

load_document(conn, url)

@spec load_document(t(), String.t()) :: t()

Load a document from a file:// URL. Stashes the document OID on conn.doc_oid.

On failure, stashes the error on conn.error.

load_document_enum_stream(conn, enumerable)

@spec load_document_enum_stream(t(), Enumerable.t()) :: t()

Load a document from an enumerable via XInputStream.

Like load_document_stream/2 but pulls chunks lazily from any Enumerable (e.g. File.stream!/2, an S3 download stream). The enumerable is iterated in a linked process; chunks are buffered and fed to soffice on demand. Stashes the document OID on conn.doc_oid.

load_document_file_stream(conn, path)

@spec load_document_file_stream(t(), Path.t()) :: t()

Load a document from a local file via XInputStream.

Like load_document_stream/2 but reads from a file on demand instead of holding the entire document in memory. The file must be accessible to the Elixir node (not soffice). Stashes the document OID on conn.doc_oid.

load_document_stream(conn, bytes)

@spec load_document_stream(t(), binary()) :: t()

Load a document from in-memory bytes via XInputStream.

No shared filesystem needed — bytes are streamed over the URP socket. soffice calls readBytes() on our exported stream object. Stashes the document OID on conn.doc_oid.

load_document_write(conn, bytes)

@spec load_document_write(t(), binary()) :: t()

Load a document by writing bytes to soffice's filesystem via XSimpleFileAccess.

Instead of streaming bytes through XInputStream (which causes thousands of tiny read/seek round-trips), this writes the entire document to a temp file on soffice's filesystem and loads from a file:// URL.

Stashes the document OID on conn.doc_oid and the temp file URL on conn.cleanup_url. The caller should delete the temp file after conversion via delete_file/2.

locale(conn)

@spec locale(t()) :: t()

Query the soffice locale string over URP.

Reads ooLocale from /org.openoffice.Setup/L10N via the configuration API. Stashes the result in conn.private.locale.

open(host \\ "localhost", port \\ 2002)

@spec open(String.t(), non_neg_integer()) :: t()

Connect to soffice, perform URP handshake, and bootstrap a Desktop reference.

read_file(conn, url)

@spec read_file(t(), String.t()) :: t()

Read a file from soffice's filesystem via XSimpleFileAccess.

Opens the file, reads all bytes in one frame, closes the stream. Stashes the file contents in conn.reply.

services(conn)

@spec services(t()) :: t()

List all service names registered in the UNO service manager.

Calls XMultiComponentFactory.getAvailableServiceNames(). Stashes the result in conn.private.services.

store_document_write(conn, opts)

@spec store_document_write(
  t(),
  keyword()
) :: t()

Store a document to soffice's filesystem and read back the result.

Uses store_to_url/4 to write the converted output to a temp file on soffice's filesystem, then reads it back in one shot via read_file/2. Replaces hundreds of round-trips with ~6. Stashes the output bytes in conn.reply.

store_to_stream(conn, opts \\ [])

@spec store_to_stream(
  t(),
  keyword()
) :: t()

Store a document via XOutputStream.

No shared filesystem needed — output bytes are streamed back over the URP socket. soffice calls writeBytes() on our exported stream object.

Stashes the result in conn.reply:

  • no sink (default) — conn.reply is the accumulated output bytes
  • sink: {:path, path} — writes to file, conn.reply is :ok
  • sink: fun/1 — calls with each chunk, conn.reply is :ok

store_to_url(conn, url, filter, filter_data \\ [])

@spec store_to_url(t(), String.t(), String.t(), keyword()) :: t()

Store a document to a file:// URL with the given export filter.

Common filters: "writer_pdf_Export", "calc_pdf_Export", "impress_pdf_Export".

filter_data is an optional keyword list of export-specific options passed as a nested FilterData property (e.g. [UseLosslessCompression: true]).

types(conn)

@spec types(t()) :: t()

List all document type names registered in soffice.

Creates a TypeDetection instance and calls getElementNames() via XNameAccess. Stashes the result in conn.private.types.

version(conn)

@spec version(t()) :: t()

Query the soffice version string over URP.

Reads ooSetupVersionAboutBox from the configuration API via 5 UNO round trips. Stashes the result in conn.private.version.