URP

Hex.pmDocs

Pure Elixir client for the UNO Remote Protocol. Talks directly to a soffice process over a TCP socket — no Python, no wrappers, no sidecars.

Installation

{:urp, "~> 0.10"}

Prerequisites

A running soffice with a URP socket listener:

docker build --tag soffice --file benchmarks/Dockerfile.soffice-debian benchmarks/
docker run --detach --name soffice --publish 2002:2002 soffice

Usage

A default pool connects to localhost:2002 automatically.

# file path, {:binary, bytes}, or any Enumerable as input
{:ok, pdf_path} =
URP.convert("/path/to/input.docx",
filter: "writer_pdf_Export",
filter_data: [Quality: 90, ReduceImageResolution: true, MaxImageResolution: 150]
)
# docx to Markdown, output as binary
{:ok, md} = URP.convert({:binary, docx_bytes}, filter: "Markdown", output: :binary)
{:ok, "26.2.0.3"} = URP.version()
{:ok, filters} = URP.filters()

See URP.convert/2 for all options (filter names, FilterData properties).

Configuration

# config/runtime.exs
config :urp, :default,
host: "soffice",
port: 2002,
pool_size: 1

pool_size {: .warning}

A single URP connection handles one operation at a time. LibreOffice accepts multiple connections to one soffice process, but they share process-wide state and generally do not improve conversion throughput. Keep pool_size: 1 unless you have tested your workload. For predictable parallelism and fault isolation, use separate soffice processes with distinct profiles. The current pool sends every worker to the configured host and port; distributing workers across containers requires separate named pools or an external TCP balancer.

Testing

Stub conversions in tests — no running soffice needed. See URP.Test.

URP.Test.stub(fn _input, _opts -> {:ok, "/tmp/fake.pdf"} end)
assert {:ok, _} = MyApp.generate_invoice(order)

mix test always runs the deterministic unit suite without probing local ports. Run the complete suite, including the LibreOffice 26.2+ coverage, explicitly with:

docker compose --file benchmarks/docker-compose.yml up --detach --wait soffice
URP_INTEGRATION=1 nix develop --command mix test --include lo26

Telemetry

Every operation emits a [:urp, :call, :start] event followed by either [:urp, :call, :stop] or [:urp, :call, :exception]. Stop events include queue, service, backoff, and total time. Connection retries emit [:urp, :connection, :retry]. See URP.Telemetry.

Performance

See PERFORMANCE.md for benchmarks and container image recommendations.

References

Releasing

./release.sh patch # or minor, major
git push origin main
# Wait for main CI, then:
git push origin "v$(cat VERSION)"

License

MIT — see LICENSE.