Search documentation of macula

# macula_peer_connector (macula v0.44.2)

View Source

Peer Connector - Establishes direct QUIC connections to remote peers (v0.8.0+).

This module enables peer-to-peer communication by establishing outbound QUIC connections to arbitrary peers. Used by DHT for STORE/FIND_VALUE message propagation and by RPC/PubSub for direct delivery.

### Overview

Pattern: Connection-pooled utility module with NAT-aware fallback - Uses `macula_peer_connection_pool` for connection reuse - Falls back to NAT-aware routing (hole punch, relay) on failure - Fire-and-forget message sending

### Connection Strategy (v0.12.0+)

1. Try pooled connection (fastest, cached) 2. Try direct QUIC connection (new connection) 3. Fall back returns error (NAT traversal removed — relay mesh handles connectivity): a. Direct connection (if NAT allows) b. Hole punch (coordinated NAT traversal) c. Relay via gateway (guaranteed fallback)

### Usage

Used internally by: - `macula_pubsub_dht`: Direct pub/sub delivery to discovered subscribers - `macula_service_registry`: DHT STORE propagation to k=20 nodes - Future: Multi-hop RPC routing

       %% Send a DHT STORE message to a peer
       Endpoint = <<"192.168.1.100:9443">>,
       Message = #{
           key => <<"service.calculator.add">>,
           value => <<"192.168.1.50:9443">>,
           ttl => 300
       },
       ok = macula_peer_connector:send_message(Endpoint, dht_store, Message).

### Performance Characteristics

v0.8.0: Fire-and-forget pattern (now legacy fallback) - Creates new connection per message - Simple but inefficient for high-frequency messaging

v0.10.0: Connection pooling (current) - Reuses existing connections via macula_peer_connection_pool - 1.5-2x latency improvement for repeated messaging

v0.12.0: NAT-aware routing (current) - Automatic fallback to hole punch and relay - Works across all NAT types

# Summary

## Functions

send_message(Endpoint, MessageType, Message)

Send a message to a remote peer (fire-and-forget). Uses connection pool for efficiency, falls back to direct connection.

send_message(Endpoint, MessageType, Message, Timeout)

Send a message to a remote peer with custom timeout.

send_message_and_wait(Endpoint, MessageType, Message, Timeout)

Send a message and wait for a reply (request-response pattern). This is used for messages like NAT_PROBE that expect a reply. Returns {ok, ReplyMessage} on success, {error, timeout} if no reply received.

send_message_nat_aware(LocalNodeId, TargetNodeId, MessageType, Message)

Send a message using NAT-aware routing (hole punch, relay fallback). Use this when sending to peers that may be behind NAT. LocalNodeId is required for hole punch coordination.

send_message_nat_aware(LocalNodeId, TargetNodeId, MessageType, Message, Opts)

Send a message using NAT-aware routing with options. Options: - endpoint: Target endpoint (if known, skips DHT lookup) - relay_endpoint: Specific relay to use - skip_hole_punch: true to skip hole punch attempts

# Functions

# send_message(Endpoint, MessageType, Message)

    -spec send_message(binary(), atom(), map()) -> ok | {error, term()}.

Send a message to a remote peer (fire-and-forget). Uses connection pool for efficiency, falls back to direct connection.

# send_message(Endpoint, MessageType, Message, Timeout)

    -spec send_message(binary(), atom(), map(), timeout()) -> ok | {error, term()}.

Send a message to a remote peer with custom timeout.

# send_message_and_wait(Endpoint, MessageType, Message, Timeout)

    -spec send_message_and_wait(binary(), atom(), map(), timeout()) ->
                                   {ok, {atom(), map()}} | {error, term()}.

Send a message and wait for a reply (request-response pattern). This is used for messages like NAT_PROBE that expect a reply. Returns {ok, ReplyMessage} on success, {error, timeout} if no reply received.

# send_message_nat_aware(LocalNodeId, TargetNodeId, MessageType, Message)

    -spec send_message_nat_aware(binary(), binary(), atom(), map()) -> ok | {error, term()}.

Send a message using NAT-aware routing (hole punch, relay fallback). Use this when sending to peers that may be behind NAT. LocalNodeId is required for hole punch coordination.

# send_message_nat_aware(LocalNodeId, TargetNodeId, MessageType, Message, Opts)

    -spec send_message_nat_aware(binary(), binary(), atom(), map(), map()) -> ok | {error, term()}.

Send a message using NAT-aware routing with options. Options: - endpoint: Target endpoint (if known, skips DHT lookup) - relay_endpoint: Specific relay to use - skip_hole_punch: true to skip hole punch attempts