Find a file
russell@unturf.com 776efaead3
phase 4: distribution data channel
Channel wraps the post-handshake socket and carries 4-byte length-
prefixed distribution messages: pass-through byte ('p') + ETF control
tuple + optional payload term.

API surface:
  send_raw / recv_raw     -- raw 4-byte framed bytes, empty == net_tick
  send_tick               -- send keepalive frame
  send_control / recv_message  -- structured control + payload
  send_reg_send           -- helper for the REG_SEND case (FromPid,
                             registered name, payload)

recv_message() transparently skips inbound ticks; callers wanting tick
awareness use recv_raw().

etf.decode_term(data, offset) exposed as a streaming decoder so the
channel can read control + payload back-to-back from one frame body.

Tests:
  - pure encode/decode round-trips
  - socketpair tests for framing, ticks, helper signatures
  - live end-to-end against an erl node with a registered echo process:
    EPMD -> handshake -> REG_SEND -> recv reply, payload matches
  - boot script writes a /tmp ready-flag after registering `echo`;
    fixture waits for both EPMD registration AND the flag to dodge
    the race where EPMD registers the node before -eval runs

101 tests green, lint clean.
2026-06-16 11:23:16 -04:00
docs phase 4: distribution data channel 2026-06-16 11:23:16 -04:00
erldistpy phase 4: distribution data channel 2026-06-16 11:23:16 -04:00
tests phase 4: distribution data channel 2026-06-16 11:23:16 -04:00
.gitignore phase 0 + 1: repo bones and ETF codec 2026-06-16 10:39:01 -04:00
LICENSE phase 0 + 1: repo bones and ETF codec 2026-06-16 10:39:01 -04:00
Makefile phase 0 + 1: repo bones and ETF codec 2026-06-16 10:39:01 -04:00
pyproject.toml phase 0 + 1: repo bones and ETF codec 2026-06-16 10:39:01 -04:00
README.md phase 0 + 1: repo bones and ETF codec 2026-06-16 10:39:01 -04:00

erldistpy

Native Python client for our Erlang distribution protocol. Talk Erlang/Elixir nodes from CPython without HTTP shim layers.

Built to swap into unfeed's WalletTransport so a Python web app can call Unsandbox.WalletRPC over native dist instead of HTTPS. Same gen_call semantics, lower latency, fewer moving parts.

Status

Phase 0 — repo bones. See docs/ROADMAP.md for the phase plan.

Quick start

make bootstrap   # create venv, install editable + dev deps
make test        # run pytest
make lint        # ruff check

Scope

  • ETF (External Term Format) codec — encode/decode Erlang terms
  • EPMD client — node name → port lookup
  • Distribution handshake — cookie auth, version negotiation
  • gen_call to registered processes on a remote node
  • TLS dist support (Erlang inet_tls_dist)

Out of scope: full Erlang node impersonation, link/monitor lifecycles, distributed Mnesia. We are a client, not a peer node.

Why not Pyrlang?

Pyrlang implements a full asyncio Erlang node. Heavy, asyncio-first, complex. We need a small synchronous client that fits behind the same WalletTransport Protocol as httpx. Different shape.

License

Unlicense (public domain).