# SAL Mycelium Module (`sal::mycelium`) ## Overview The `sal::mycelium` module provides a client interface for interacting with a [Mycelium](https://mycelium.com/) node's HTTP API. Mycelium is a decentralized networking project, and this SAL module allows Rust applications and `herodo` Rhai scripts to manage and communicate over a Mycelium network. The module enables operations such as: - Querying node status and information. - Managing peer connections (listing, adding, removing). - Inspecting routing tables (selected and fallback routes). - Sending messages to other Mycelium nodes. - Receiving messages from subscribed topics. All interactions with the Mycelium API are performed asynchronously. ## Key Design Points - **Async HTTP Client**: Leverages `reqwest` for asynchronous HTTP requests to the Mycelium node's API, ensuring non-blocking operations suitable for concurrent applications. - **JSON Interaction**: Expects and processes JSON-formatted data from the Mycelium API, using `serde_json::Value` for flexible data handling. - **Base64 Encoding**: Message payloads and topics are Base64 encoded/decoded when communicating with the Mycelium API, as per its expected format. - **Rhai Scriptability**: All core functionalities are exposed to Rhai scripts via `herodo` through the `sal::rhai::mycelium` bridge. This allows for easy automation of Mycelium network tasks. - **Error Handling**: Provides clear error messages, converting HTTP and parsing errors into `String` results in Rust, which are then translated to `EvalAltResult` for Rhai. - **Tokio Runtime Management**: For Rhai script execution, a Tokio runtime is managed internally by the wrapper functions to bridge Rhai's synchronous world with the asynchronous Rust client. ## Rhai Scripting with `herodo` The `sal::mycelium` module can be scripted using `herodo`. The following functions are available in Rhai, typically prefixed with `mycelium_`: All functions take `api_url` (String) as their first argument, which is the base URL of the Mycelium node's HTTP API (e.g., `"http://localhost:7777"`). - `mycelium_get_node_info(api_url: String) -> Dynamic` - Retrieves general information about the Mycelium node. - Returns a dynamic object (map) representing the JSON response. - `mycelium_list_peers(api_url: String) -> Dynamic` - Lists all peers currently connected to the node. - Returns a dynamic array of peer information objects. - `mycelium_add_peer(api_url: String, peer_address: String) -> Dynamic` - Adds a new peer to the node. - `peer_address`: The endpoint address of the peer to add (e.g., `"tcp://192.168.1.10:7778"`). - Returns a success status or an error. - `mycelium_remove_peer(api_url: String, peer_id: String) -> Dynamic` - Removes a peer from the node. - `peer_id`: The ID of the peer to remove. - Returns a success status or an error. - `mycelium_list_selected_routes(api_url: String) -> Dynamic` - Lists the currently selected (active) routes in the node's routing table. - Returns a dynamic array of route objects. - `mycelium_list_fallback_routes(api_url: String) -> Dynamic` - Lists the fallback routes in the node's routing table. - Returns a dynamic array of route objects. - `mycelium_send_message(api_url: String, destination: String, topic: String, message: String, reply_deadline_secs: Int) -> Dynamic` - Sends a message to a specific destination over the Mycelium network. - `destination`: The Mycelium address of the recipient node. - `topic`: The topic for the message (will be Base64 encoded). - `message`: The content of the message (will be Base64 encoded). - `reply_deadline_secs`: An integer specifying the timeout in seconds to wait for a reply. If negative, no reply is waited for. - Returns a response from the Mycelium API, potentially including a reply if waited for. - `mycelium_receive_messages(api_url: String, topic: String, wait_deadline_secs: Int) -> Dynamic` - Subscribes to a topic and waits for messages. - `topic`: The topic to subscribe to (will be Base64 encoded). - `wait_deadline_secs`: An integer specifying the maximum time in seconds to wait for a message. If negative, waits indefinitely (or until the API's default timeout). - Returns an array of received messages, or an empty array if the deadline is met before messages arrive. ### Rhai Example ```rhai // Assuming a Mycelium node is running and accessible at http://localhost:7777 let api_url = "http://localhost:7777"; // Get Node Info print("Fetching node info..."); let node_info = mycelium_get_node_info(api_url); if node_info.is_ok() { print(`Node Info: ${node_info}`); } else { print(`Error fetching node info: ${node_info}`); } // List Peers print("\nListing peers..."); let peers = mycelium_list_peers(api_url); if peers.is_ok() { print(`Peers: ${peers}`); } else { print(`Error listing peers: ${peers}`); } // Example: Send a message (destination and topic are illustrative) let dest_addr = "some_mycelium_destination_address"; // Replace with actual address let msg_topic = "sal/test_topic"; let msg_content = "Hello from SAL Mycelium via Rhai!"; print(`\nSending message to '${dest_addr}' on topic '${msg_topic}'...`); // No reply wait (deadline = -1) let send_result = mycelium_send_message(api_url, dest_addr, msg_topic, msg_content, -1); if send_result.is_ok() { print(`Send Result: ${send_result}`); } else { print(`Error sending message: ${send_result}`); } // Example: Receive messages (topic is illustrative) // This will block for up to 10 seconds, or until a message arrives. print(`\nAttempting to receive messages on topic '${msg_topic}' for 10 seconds...`); let received = mycelium_receive_messages(api_url, msg_topic, 10); if received.is_ok() { if received.len() > 0 { print(`Received Messages: ${received}`); } else { print("No messages received within the deadline."); } } else { print(`Error receiving messages: ${received}`); } print("\nMycelium Rhai script finished."); ``` This module facilitates integration with Mycelium networks, enabling automation of peer management, message exchange, and network monitoring through `herodo` scripts or direct Rust integration.