macula (macula v3.8.0)
View SourceMacula SDK — Public API for mesh applications.
This is the main entry point for applications using the Macula SDK. All functions delegate to macula_mesh_client or macula_multi_relay for relay mesh communication.
Summary
Types
DHT storage key — macula_record:storage_key/1 output.
Functions
Abort the stream with an error frame.
Advertise an RPC procedure handler.
Advertise with options.
Advertise a streaming procedure (default: server_stream). LOCAL dispatch only — see advertise_stream/3,4 for the Client form.
Advertise a streaming procedure.
Advertise with explicit mode / options.
Wait for the terminal reply (client-stream / bidi).
Call a remote procedure (default 5s timeout).
Call a remote procedure with timeout.
Call a remote procedure on a specific target node (default 5s timeout).
Call a remote procedure on a specific target node with timeout.
Open a server-stream call (default mode).
Open a server-stream call with options.
Open a remote server-stream call against a mesh client, with opts.
Close the stream (both sides).
Half-close the write side; recv still drains.
Connect to a Macula relay.
Disconnect from the relay.
Ensure this node is running in distributed mode.
Fetch a record by its macula_record:storage_key/1.
Return every record of a given type currently visible from the connected relay.
Get the Erlang cluster cookie.
Enable Erlang distribution over a dedicated dist relay (macula-io/macula-dist-relay).
Join the Macula relay mesh with Erlang distribution.
List all nodes connected to the relay (default 5s timeout).
List all nodes connected to the relay with options.
Subscribe to node up/down events.
Open a client-stream or bidi call.
Open a stream with explicit mode.
Publish an event to a topic (fire-and-forget).
Publish an event with options.
Store a signed record in the mesh DHT.
Receive the next chunk (blocks).
Resolve a mesh name to node identity information.
Send a binary chunk on the stream.
Send a chunk with explicit encoding.
Set the Erlang cluster cookie.
Server-side: emit the terminal reply value.
Subscribe to a topic.
Subscribe to live record-stored events filtered by type.
Stop advertising a procedure.
Stop advertising a streaming procedure.
Unsubscribe from node up/down events.
Unsubscribe from a topic.
Cancel a subscribe_records/3 subscription.
Types
-type client() :: pid().
-type procedure() :: binary().
-type record() :: macula_record:record().
-type record_key() :: <<_:256>>.
DHT storage key — macula_record:storage_key/1 output.
-type record_type() :: macula_record:type_tag().
-type stream() :: pid().
-type stream_mode() :: server_stream | client_stream | bidi.
-type topic() :: binary().
Functions
Abort the stream with an error frame.
Advertise an RPC procedure handler.
Advertise with options.
-spec advertise_stream(procedure(), stream_handler()) -> ok | {error, term()}.
Advertise a streaming procedure (default: server_stream). LOCAL dispatch only — see advertise_stream/3,4 for the Client form.
-spec advertise_stream(procedure() | client(), stream_mode() | procedure(), stream_handler()) -> ok | {error, term()}.
Advertise a streaming procedure.
Two shapes: advertise_stream(Procedure, Mode, Handler) — LOCAL dispatch advertise_stream(Client, Procedure, Handler) — REMOTE, default mode server_stream
-spec advertise_stream(procedure() | client(), stream_mode() | procedure(), stream_handler() | stream_mode(), map() | stream_handler()) -> ok | {error, term()}.
Advertise with explicit mode / options.
Two shapes: advertise_stream(Procedure, Mode, Handler, Opts) — LOCAL advertise_stream(Client, Procedure, Mode, Handler) — REMOTE
Wait for the terminal reply (client-stream / bidi).
Call a remote procedure (default 5s timeout).
Call a remote procedure with timeout.
Call a remote procedure on a specific target node (default 5s timeout).
Target can be a mesh name, site_id, or node_id (all binaries). The relay resolves the target and routes the CALL directly to that node.
-spec call_node(client(), binary(), procedure(), term(), pos_integer()) -> {ok, term()} | {error, term()}.
Call a remote procedure on a specific target node with timeout.
Open a server-stream call (default mode).
Phase 1 shortcut — dispatches in-process via the local registry. For cross-node streaming use the (Client, Procedure, Args) form.
-spec call_stream(procedure() | client(), procedure() | term(), term() | map()) -> {ok, stream()} | {error, term()}.
Open a server-stream call with options.
Two shapes: call_stream(Procedure, Args, Opts) — LOCAL dispatch only call_stream(Client, Procedure, Args) — REMOTE via mesh client
Open a remote server-stream call against a mesh client, with opts.
-spec close(stream()) -> ok.
Close the stream (both sides).
-spec close_send(stream()) -> ok.
Half-close the write side; recv still drains.
Connect to a Macula relay.
Returns a client PID (macula_mesh_client gen_server) that you pass to all other API functions. Accepts a single URL binary or a list.
-spec disconnect(client()) -> ok.
Disconnect from the relay.
-spec ensure_distributed() -> ok | {error, term()}.
Ensure this node is running in distributed mode.
-spec find_record(client(), record_key()) -> {ok, record()} | {error, not_found | term()}.
Fetch a record by its macula_record:storage_key/1.
Returns {error, not_found} when no record exists at the key. The returned record's signature should be verified via macula_record:verify/1 before its payload is trusted.
-spec find_records_by_type(client(), record_type()) -> {ok, [record()]} | {error, term()}.
Return every record of a given type currently visible from the connected relay.
Coverage depends on the relay's view of the DHT — a single relay sees its local replicas plus whatever its peers have gossiped. Aggregating across the full mesh requires querying multiple relays and deduplicating by record key.
-spec get_cookie() -> atom().
Get the Erlang cluster cookie.
Enable Erlang distribution over a dedicated dist relay (macula-io/macula-dist-relay).
Different from join_mesh/1: - Connects to a dist relay (port 4434, ALPN macula-dist), NOT the pub/sub station mesh - No mesh_client, no pub/sub subscriptions — only dist traffic - Uses raw QUIC stream routing with no MessagePack overhead
Options: - url (required): <<"quic://relay.example.com:4434">>
After this returns ok, standard OTP distribution (rpc:call/4, gen_server:call/3 across nodes, pg groups, etc.) works across firewalls via the dist relay.
Join the Macula relay mesh with Erlang distribution.
After calling this, standard OTP distribution works across firewalls. Options: relays (required list), realm, identity, site, tls_verify.
List all nodes connected to the relay (default 5s timeout).
List all nodes connected to the relay with options.
-spec monitor_nodes() -> ok.
Subscribe to node up/down events.
-spec open_stream(procedure() | client(), procedure() | term(), term() | map()) -> {ok, stream()} | {error, term()}.
Open a client-stream or bidi call.
Two shapes: open_stream(Procedure, Args, Opts) — LOCAL dispatch open_stream(Client, Procedure, Args) — REMOTE, default mode bidi
-spec open_stream(procedure() | client(), procedure() | term(), term() | map(), stream_mode() | map()) -> {ok, stream()} | {error, term()}.
Open a stream with explicit mode.
Two shapes: open_stream(Procedure, Args, Opts, Mode) — LOCAL dispatch, explicit mode open_stream(Client, Procedure, Args, Opts) — REMOTE via mesh client
Publish an event to a topic (fire-and-forget).
Publish an event with options.
Store a signed record in the mesh DHT.
Build the record via the typed constructors in macula_record (node_record/3,4, content_announcement/3,4, tombstone/3,4, realm_directory/3,4, procedure_advertisement/3,4, etc.) then sign it with macula_record:sign/2. The relay validates the signature on receipt; an invalid signature returns {error, bad_signature}. Successful stores propagate to the K-nearest peers in the DHT under the record's macula_record:storage_key/1.
Receive the next chunk (blocks).
Resolve a mesh name to node identity information.
Returns the node's identity including name, site_id, city, endpoint, and connected_at timestamp. Works for names, site_ids, or node_ids.
Send a binary chunk on the stream.
Send a chunk with explicit encoding.
Set the Erlang cluster cookie.
Server-side: emit the terminal reply value.
-spec subscribe(client(), topic(), fun((term()) -> ok) | pid()) -> {ok, reference()} | {error, term()}.
Subscribe to a topic.
The callback receives the event payload (map or binary). Returns a subscription reference for unsubscribing.
-spec subscribe_records(client(), record_type(), fun((record()) -> any()) | pid()) -> {ok, reference()} | {error, term()}.
Subscribe to live record-stored events filtered by type.
The callback (or pid) receives each newly-stored record of the given type as {record, Record} (pid form) or via direct invocation (fun form). Returns a subscription reference for unsubscribe_records/2. Topic shape is _dht.records.<type>.stored, rendered with the type tag as a decimal integer for log friendliness.
Stop advertising a procedure.
-spec unadvertise_stream(procedure()) -> ok.
Stop advertising a streaming procedure.
-spec unmonitor_nodes() -> ok.
Unsubscribe from node up/down events.
Unsubscribe from a topic.
Cancel a subscribe_records/3 subscription.