Current section
Files
Jump to
Current section
Files
lib/native.ex
defmodule IrohEx.Native do
alias IrohEx.NodeConfig
# use Rustler,
# otp_app: :iroh_ex,
# crate: :iroh_ex
version = Mix.Project.config()[:version]
use RustlerPrecompiled,
otp_app: :iroh_ex,
crate: :iroh_ex,
base_url: "https://github.com/adiibanez/iroh_ex/releases/download/v#{version}",
force_build: System.get_env("RUSTLER_IROHEX_BUILD") in ["1", "true"],
version: version,
max_retries: 0,
targets: [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
# "aarch64-apple-ios-sim",
# "aarch64-apple-ios",
# "x86_64-apple-ios",
"aarch64-unknown-linux-gnu",
# "aarch64-unknown-linux-musl",
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu"
# "x86_64-unknown-linux-musl"
]
# skip_compilation?: true,
# load_from: {:iroh_ex, "priv/native/libiroh_ex"}
# skip_compilation?: true
_version = Mix.Project.config()[:version]
@spec add(number(), number()) :: {:ok, number()} | {:error, term()}
def add(_a, _b), do: error()
@spec create_node(pid(), NodeConfig.t()) :: {:ok, reference()} | {:error, term()}
def create_node(_pid, _node_config), do: error()
@spec gen_node_addr(reference()) :: {:ok, binary()} | {:error, term()}
def gen_node_addr(_node), do: error()
@spec send_message(reference(), binary()) :: {:ok, reference()} | {:error, term()}
def send_message(_node, _message), do: error()
@spec create_ticket(reference()) :: {:ok, binary()} | {:error, term()}
def create_ticket(_node), do: error()
@spec connect_node_by_pubkey(binary()) :: {:ok, reference()} | {:error, term()}
def connect_node_by_pubkey(_pubkey), do: error()
@spec connect_node(reference(), binary()) :: {:ok, reference()} | {:error, term()}
def connect_node(_node, _ticket), do: error()
@spec cleanup(reference()) :: {:ok, reference()} | {:error, term()}
def cleanup(_node), do: error()
@spec generate_secretkey() :: {:ok, binary()} | {:error, term()}
def generate_secretkey(), do: error()
@spec list_peers(reference()) :: {:ok, [binary()]} | {:error, term()}
def list_peers(_node), do: error()
@spec disconnect_node(reference()) :: {:ok} | {:error, term()}
def disconnect_node(_node), do: error()
@spec subscribe_to_topic(reference(), binary(), [binary()]) :: {:ok, reference()} | {:error, term()}
def subscribe_to_topic(_node, _topic_str, _node_ids), do: error()
@spec unsubscribe_from_topic(reference(), binary()) :: {:ok, reference()} | {:error, term()}
def unsubscribe_from_topic(_node, _topic_str), do: error()
@spec broadcast_message(reference(), binary(), binary()) :: {:ok, reference()} | {:error, term()}
def broadcast_message(_node, _topic_str, _message), do: error()
@spec list_topics(reference()) :: {:ok, [binary()]} | {:error, term()}
def list_topics(_node), do: error()
@spec shutdown(reference()) :: :ok | {:error, term()}
def shutdown(_node), do: error()
# ============================================================================
# BLOB FUNCTIONS
# ============================================================================
@doc """
Add binary data as a blob, returns the hash as hex string.
"""
@spec blob_add(reference(), binary()) :: {:ok, binary()} | {:error, term()}
def blob_add(_node, _data), do: error()
@doc """
Get a blob by hash, returns the binary data.
"""
@spec blob_get(reference(), binary()) :: {:ok, binary()} | {:error, term()}
def blob_get(_node, _hash), do: error()
@doc """
List all blob hashes in the store.
"""
@spec blob_list(reference()) :: {:ok, [binary()]} | {:error, term()}
def blob_list(_node), do: error()
# ============================================================================
# DOCS FUNCTIONS
# ============================================================================
@doc """
Create a new author for documents, returns author_id.
"""
@spec docs_create_author(reference()) :: {:ok, binary()} | {:error, term()}
def docs_create_author(_node), do: error()
@doc """
Create a new document, returns namespace_id.
"""
@spec docs_create(reference()) :: {:ok, binary()} | {:error, term()}
def docs_create(_node), do: error()
@doc """
Set an entry in a document.
"""
@spec docs_set_entry(reference(), binary(), binary(), binary(), binary()) :: {:ok, binary()} | {:error, term()}
def docs_set_entry(_node, _namespace_id, _author_id, _key, _value), do: error()
@doc """
Get an entry from a document - returns content hash.
"""
@spec docs_get_entry(reference(), binary(), binary(), binary()) :: {:ok, binary()} | {:error, term()}
def docs_get_entry(_node, _namespace_id, _author_id, _key), do: error()
@doc """
Get an entry value directly from a document.
"""
@spec docs_get_entry_value(reference(), binary(), binary(), binary()) :: {:ok, binary()} | {:error, term()}
def docs_get_entry_value(_node, _namespace_id, _author_id, _key), do: error()
@doc """
List all documents.
"""
@spec docs_list(reference()) :: {:ok, [binary()]} | {:error, term()}
def docs_list(_node), do: error()
# ============================================================================
# DHT AUTO-DISCOVERY FUNCTIONS
# ============================================================================
@doc """
Subscribe to a gossip topic with DHT-based auto-discovery.
This allows nodes to find each other without exchanging tickets.
## Parameters
- `node` - The node reference
- `topic_name` - The topic name to subscribe to
- `secret_seed` - Optional secret seed for key derivation (nil for random)
## Returns
- `{:ok, node_ref}` on success
- `{:error, term()}` on failure
"""
@spec subscribe_with_auto_discovery(reference(), binary(), binary() | nil) :: {:ok, reference()} | {:error, term()}
def subscribe_with_auto_discovery(_node, _topic_name, _secret_seed), do: error()
# ============================================================================
# AUTOMERGE CRDT FUNCTIONS
# ============================================================================
# Document Management
@doc """
Create a new automerge document, returns doc_id.
"""
@spec automerge_create_doc(reference()) :: binary()
def automerge_create_doc(_node), do: error()
@doc """
Fork an existing document (create a copy with same history).
"""
@spec automerge_fork_doc(reference(), binary()) :: binary()
def automerge_fork_doc(_node, _doc_id), do: error()
@doc """
Load a document from saved binary data.
"""
@spec automerge_load_doc(reference(), binary()) :: binary()
def automerge_load_doc(_node, _data), do: error()
@doc """
Save document to binary format.
"""
@spec automerge_save_doc(reference(), binary()) :: binary()
def automerge_save_doc(_node, _doc_id), do: error()
@doc """
Delete a document from memory.
"""
@spec automerge_delete_doc(reference(), binary()) :: boolean()
def automerge_delete_doc(_node, _doc_id), do: error()
@doc """
List all document IDs.
"""
@spec automerge_list_docs(reference()) :: [binary()]
def automerge_list_docs(_node), do: error()
# Map Operations
@doc """
Put a value in a map at the given path.
Path is a list of keys like ["users", "alice", "name"].
"""
@spec automerge_map_put(reference(), binary(), [binary()], binary(), term()) :: :ok
def automerge_map_put(_node, _doc_id, _path, _key, _value), do: error()
@doc """
Put an object (map, list, or text) at path, returns the object ID.
obj_type must be "map", "list", or "text".
"""
@spec automerge_map_put_object(reference(), binary(), [binary()], binary(), binary()) :: binary()
def automerge_map_put_object(_node, _doc_id, _path, _key, _obj_type), do: error()
@doc """
Get a value from a map at the given path.
Returns :not_found if key doesn't exist.
"""
@spec automerge_map_get(reference(), binary(), [binary()], binary()) :: term()
def automerge_map_get(_node, _doc_id, _path, _key), do: error()
@doc """
Delete a key from a map.
"""
@spec automerge_map_delete(reference(), binary(), [binary()], binary()) :: :ok
def automerge_map_delete(_node, _doc_id, _path, _key), do: error()
@doc """
Get all keys from a map.
"""
@spec automerge_map_keys(reference(), binary(), [binary()]) :: [binary()]
def automerge_map_keys(_node, _doc_id, _path), do: error()
# List Operations
@doc """
Insert a value into a list at index.
"""
@spec automerge_list_insert(reference(), binary(), [binary()], non_neg_integer(), term()) :: :ok
def automerge_list_insert(_node, _doc_id, _path, _index, _value), do: error()
@doc """
Push a value to the end of a list.
"""
@spec automerge_list_push(reference(), binary(), [binary()], term()) :: :ok
def automerge_list_push(_node, _doc_id, _path, _value), do: error()
@doc """
Get a value from a list at index.
Returns :not_found if index doesn't exist.
"""
@spec automerge_list_get(reference(), binary(), [binary()], non_neg_integer()) :: term()
def automerge_list_get(_node, _doc_id, _path, _index), do: error()
@doc """
Delete a value from a list at index.
"""
@spec automerge_list_delete(reference(), binary(), [binary()], non_neg_integer()) :: :ok
def automerge_list_delete(_node, _doc_id, _path, _index), do: error()
@doc """
Get list length.
"""
@spec automerge_list_length(reference(), binary(), [binary()]) :: non_neg_integer()
def automerge_list_length(_node, _doc_id, _path), do: error()
# Text Operations
@doc """
Create a text object at path with optional initial text.
Returns the text object ID.
"""
@spec automerge_text_create(reference(), binary(), [binary()], binary(), binary()) :: binary()
def automerge_text_create(_node, _doc_id, _path, _key, _initial_text), do: error()
@doc """
Insert text at position.
"""
@spec automerge_text_insert(reference(), binary(), [binary()], non_neg_integer(), binary()) :: :ok
def automerge_text_insert(_node, _doc_id, _path, _position, _text), do: error()
@doc """
Delete text at position.
"""
@spec automerge_text_delete(reference(), binary(), [binary()], non_neg_integer(), non_neg_integer()) :: :ok
def automerge_text_delete(_node, _doc_id, _path, _position, _length), do: error()
@doc """
Get full text content.
"""
@spec automerge_text_get(reference(), binary(), [binary()]) :: binary()
def automerge_text_get(_node, _doc_id, _path), do: error()
# Counter Operations
@doc """
Create or increment a counter. Returns the new value.
"""
@spec automerge_counter_increment(reference(), binary(), [binary()], binary(), integer()) :: integer()
def automerge_counter_increment(_node, _doc_id, _path, _key, _delta), do: error()
@doc """
Get counter value.
"""
@spec automerge_counter_get(reference(), binary(), [binary()], binary()) :: integer()
def automerge_counter_get(_node, _doc_id, _path, _key), do: error()
# Merge and Sync Operations
@doc """
Merge another document (as binary) into this one.
"""
@spec automerge_merge(reference(), binary(), binary()) :: :ok
def automerge_merge(_node, _doc_id, _other_doc_bytes), do: error()
@doc """
Generate a sync message to send to a peer.
Returns :not_found if no sync is needed.
"""
@spec automerge_generate_sync_message(reference(), binary(), binary()) :: binary() | :not_found
def automerge_generate_sync_message(_node, _doc_id, _peer_id), do: error()
@doc """
Receive and apply a sync message from a peer.
"""
@spec automerge_receive_sync_message(reference(), binary(), binary(), binary()) :: :ok
def automerge_receive_sync_message(_node, _doc_id, _peer_id, _message), do: error()
@doc """
Sync document via gossip (broadcast full document to all peers).
"""
@spec automerge_sync_via_gossip(reference(), binary()) :: :ok
def automerge_sync_via_gossip(_node, _doc_id), do: error()
@doc """
Get document as JSON string for debugging/inspection.
"""
@spec automerge_to_json(reference(), binary()) :: binary()
def automerge_to_json(_node, _doc_id), do: error()
## Handle NIF errors when Rust module isn't loaded
defp error, do: :erlang.nif_error(:nif_not_loaded)
end
defmodule IrohEx.NodeConfig do
@moduledoc false
@enforce_keys [:is_whale_node, :active_view_capacity, :passive_view_capacity, :relay_urls, :discovery]
defstruct [:is_whale_node, :active_view_capacity, :passive_view_capacity, :relay_urls, :discovery]
@default_relay_urls ["https://euw1-1.relay.iroh.network./"]
@default_discovery ["n0", "local_network"]
@type t :: %__MODULE__{
is_whale_node: boolean(),
active_view_capacity: integer(),
passive_view_capacity: integer(),
relay_urls: [String.t()],
discovery: [String.t()]
}
def build, do: %__MODULE__{
is_whale_node: false,
active_view_capacity: 10,
passive_view_capacity: 10,
relay_urls: @default_relay_urls,
discovery: @default_discovery
}
end