macula_peering (macula v7.0.0)
View SourceMacula peering — connection state machine API.
Each peer connection is one macula_peering_conn gen_statem under the macula_peering_conn_sup simple_one_for_one supervisor.
Two entry points:
connect/1— outbound dial; worker drives the QUIC connect.accept/2— inbound; caller transfers ownership of an already-establishedmacula_quicconnection (areference()) to a new worker.
The caller passes a controlling_pid in opts; that pid receives peering events as messages:
{macula_peering, connected, ConnPid, PeerNodeId}{macula_peering, frame, ConnPid, Frame}(post-handshake){macula_peering, disconnected, ConnPid, Reason}
An optional accept_owner pid in opts receives a single {macula_peering, handshake_complete, ConnPid, PeerNodeId} message the moment the worker transitions from handshaking to connected. Used by accept-side listeners that (a) cap concurrent handshaking workers separately from healthy connected peers, and (b) dedupe duplicate dials from the same peer identity by closing prior workers for the same PeerNodeId.
Summary
Functions
Inbound accept. Caller currently owns Conn (e.g. it's the listener owner that just received {quic, new_conn, Conn, _}). The transfer of ownership and the handshake start are sequenced atomically.
Initiate a graceful close (sends GOODBYE, drains 5s, terminates).
Outbound connect. Spawns a worker that opens a QUIC connection to target and runs the CONNECT/HELLO handshake.
Read the peer's capabilities bitmask as observed in their CONNECT/HELLO frame. Returns {ok, NegotiatedCaps} once the handshake has completed and {error, not_connected} otherwise.
Send a frame through the peer connection. Signs the frame with the local identity if it isn't already signed.
Types
-type opts() :: macula_peering_conn:opts().
Functions
Inbound accept. Caller currently owns Conn (e.g. it's the listener owner that just received {quic, new_conn, Conn, _}). The transfer of ownership and the handshake start are sequenced atomically.
-spec close(pid()) -> ok.
Initiate a graceful close (sends GOODBYE, drains 5s, terminates).
Outbound connect. Spawns a worker that opens a QUIC connection to target and runs the CONNECT/HELLO handshake.
-spec peer_capabilities(pid()) -> {ok, non_neg_integer()} | {error, not_connected}.
Read the peer's capabilities bitmask as observed in their CONNECT/HELLO frame. Returns {ok, NegotiatedCaps} once the handshake has completed and {error, not_connected} otherwise.
Used by relays to tell direct daemon ADVERTISEs from station-to- station gossip relays at frame-dispatch time (see ?CAP_STATION). Daemons send 0; relay stations OR-in ?CAP_STATION. Pre-version peers that don't set the bit are treated as daemons by callers, which matches their actual role.
-spec send_frame(pid(), macula_frame:frame()) -> ok | {error, term()}.
Send a frame through the peer connection. Signs the frame with the local identity if it isn't already signed.
The send is a cast, so encoding happens later, inside the shared connection process. This is therefore the LAST synchronous point at which a caller can be told its frame is unsendable, and every producer — pubsub, RPC calls and results, streaming, advertise, content — funnels through here. Guarding one verb upstream (publish) left the other five able to kill the connection, so the check lives here, where it covers all of them at one seam.
Returns {error, {unsupported_payload_type, Type, Path}} without casting when the frame cannot be encoded. Callers that ignore the return at least no longer take the connection down; callers that check get a structured reason and a path to the offending value.