macula_dist_relay_client (macula v3.13.0)
View SourceClient for the Macula dist relay (macula-io/macula-dist-relay).
Maintains a persistent QUIC connection to a dedicated dist relay and exposes a simple API for establishing point-to-point tunnels between Erlang nodes. Each tunnel is backed by a raw QUIC stream — no framing, no pub/sub, no application-level encryption.
This replaces the pub/sub bridge approach in macula_dist_relay (the SDK's previous dist-over-mesh implementation) which forced dist bytes through the station's MessagePack/handler pipeline.
Protocol
Control frames on stream 0 (length-prefixed MessagePack):
node → relay identify{node_name}
relay → node identified{status}
node → relay tunnel_request{target}
relay → node tunnel_ok{tunnel_id} | tunnel_error{reason}
relay → node tunnel_notify{tunnel_id, source}
node → relay tunnel_close{tunnel_id}Tunnel data streams (stream 1+) carry the raw dist wire bytes after a 32-byte tunnel_id prefix (written by the relay on stream open) that lets the client match new_stream events to pending tunnels.
Lifecycle
1. start_link(RelayUrl, NodeName) connects + sends identify 2. Await identified reply 3. request_tunnel(TargetNode) blocks until tunnel_ok + tunnel stream arrive; returns {ok, ConnRef, StreamRef} for use as the dist Socket in macula_dist 4. Incoming tunnels: tunnel_notify arrives on control, then a new_stream event; client reads 32-byte prefix, matches to the notified tunnel, hands the stream to net_kernel via the standard {accept, _, Socket, Family, Driver} protocol.
Not yet implemented (Phase 2 MVP)
- net_kernel handoff for incoming tunnels (needs macula_dist integration on the accept side) - automatic reconnect on relay disconnect - multiple relay failover
Summary
Functions
Request a tunnel to TargetNode. Blocks until the tunnel stream is ready or the request fails/times out. Returns a {ConnRef, StreamRef} tuple suitable for use as the dist Socket in macula_dist.
Tell the client which process to deliver {accept, ...} messages to when inbound tunnels arrive. Called by macula_dist:accept/1 with the net_kernel pid (self() at that call site).
Start the client with a locally-registered name so macula_dist can find it without being passed the pid. Only one dist_relay_client per node makes sense — a node connects to exactly one dist relay for its cluster traffic.
Locate the registered client, if any.
Functions
Request a tunnel to TargetNode. Blocks until the tunnel stream is ready or the request fails/times out. Returns a {ConnRef, StreamRef} tuple suitable for use as the dist Socket in macula_dist.
Tell the client which process to deliver {accept, ...} messages to when inbound tunnels arrive. Called by macula_dist:accept/1 with the net_kernel pid (self() at that call site).
Start the client with a locally-registered name so macula_dist can find it without being passed the pid. Only one dist_relay_client per node makes sense — a node connects to exactly one dist relay for its cluster traffic.
-spec whereis_client() -> pid() | undefined.
Locate the registered client, if any.