sal/src/rhai/mycelium.rs
2025-05-13 10:20:08 +02:00

235 lines
7.0 KiB
Rust

//! Rhai wrappers for Mycelium client module functions
//!
//! This module provides Rhai wrappers for the functions in the Mycelium client module.
use rhai::{Engine, EvalAltResult, Array, Dynamic, Map};
use crate::mycelium as client;
use tokio::runtime::Runtime;
use serde_json::Value;
use crate::rhai::error::ToRhaiError;
/// Register Mycelium module functions with the Rhai engine
///
/// # Arguments
///
/// * `engine` - The Rhai engine to register the functions with
///
/// # Returns
///
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
pub fn register_mycelium_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
// Register Mycelium client functions
engine.register_fn("mycelium_get_node_info", mycelium_get_node_info);
engine.register_fn("mycelium_list_peers", mycelium_list_peers);
engine.register_fn("mycelium_add_peer", mycelium_add_peer);
engine.register_fn("mycelium_remove_peer", mycelium_remove_peer);
engine.register_fn("mycelium_list_selected_routes", mycelium_list_selected_routes);
engine.register_fn("mycelium_list_fallback_routes", mycelium_list_fallback_routes);
engine.register_fn("mycelium_send_message", mycelium_send_message);
engine.register_fn("mycelium_receive_messages", mycelium_receive_messages);
Ok(())
}
// Helper function to get a runtime
fn get_runtime() -> Result<Runtime, Box<EvalAltResult>> {
tokio::runtime::Runtime::new().map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to create Tokio runtime: {}", e).into(),
rhai::Position::NONE
))
})
}
// Helper function to convert serde_json::Value to rhai::Dynamic
fn value_to_dynamic(value: Value) -> Dynamic {
match value {
Value::Null => Dynamic::UNIT,
Value::Bool(b) => Dynamic::from(b),
Value::Number(n) => {
if let Some(i) = n.as_i64() {
Dynamic::from(i)
} else if let Some(f) = n.as_f64() {
Dynamic::from(f)
} else {
Dynamic::from(n.to_string())
}
},
Value::String(s) => Dynamic::from(s),
Value::Array(arr) => {
let mut rhai_arr = Array::new();
for item in arr {
rhai_arr.push(value_to_dynamic(item));
}
Dynamic::from(rhai_arr)
},
Value::Object(map) => {
let mut rhai_map = Map::new();
for (k, v) in map {
rhai_map.insert(k.into(), value_to_dynamic(v));
}
Dynamic::from_map(rhai_map)
}
}
}
// Helper trait to convert String errors to Rhai errors
impl<T> ToRhaiError<T> for Result<T, String> {
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
self.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
rhai::Position::NONE
))
})
}
}
//
// Mycelium Client Function Wrappers
//
/// Wrapper for mycelium::get_node_info
///
/// Gets information about the Mycelium node.
pub fn mycelium_get_node_info(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
let result = rt.block_on(async {
client::get_node_info(api_url).await
});
let node_info = result.to_rhai_error()?;
Ok(value_to_dynamic(node_info))
}
/// Wrapper for mycelium::list_peers
///
/// Lists all peers connected to the Mycelium node.
pub fn mycelium_list_peers(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
let result = rt.block_on(async {
client::list_peers(api_url).await
});
let peers = result.to_rhai_error()?;
Ok(value_to_dynamic(peers))
}
/// Wrapper for mycelium::add_peer
///
/// Adds a new peer to the Mycelium node.
pub fn mycelium_add_peer(api_url: &str, peer_address: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
let result = rt.block_on(async {
client::add_peer(api_url, peer_address).await
});
let response = result.to_rhai_error()?;
Ok(value_to_dynamic(response))
}
/// Wrapper for mycelium::remove_peer
///
/// Removes a peer from the Mycelium node.
pub fn mycelium_remove_peer(api_url: &str, peer_id: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
let result = rt.block_on(async {
client::remove_peer(api_url, peer_id).await
});
let response = result.to_rhai_error()?;
Ok(value_to_dynamic(response))
}
/// Wrapper for mycelium::list_selected_routes
///
/// Lists all selected routes in the Mycelium node.
pub fn mycelium_list_selected_routes(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
let result = rt.block_on(async {
client::list_selected_routes(api_url).await
});
let routes = result.to_rhai_error()?;
Ok(value_to_dynamic(routes))
}
/// Wrapper for mycelium::list_fallback_routes
///
/// Lists all fallback routes in the Mycelium node.
pub fn mycelium_list_fallback_routes(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
let result = rt.block_on(async {
client::list_fallback_routes(api_url).await
});
let routes = result.to_rhai_error()?;
Ok(value_to_dynamic(routes))
}
/// Wrapper for mycelium::send_message
///
/// Sends a message to a destination via the Mycelium node.
pub fn mycelium_send_message(api_url: &str, destination: &str, topic: &str, message: &str, deadline_secs: i64) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
// Convert deadline to u64
let deadline = if deadline_secs < 0 {
return Err(Box::new(EvalAltResult::ErrorRuntime(
"Deadline cannot be negative".into(),
rhai::Position::NONE
)));
} else {
deadline_secs as u64
};
let result = rt.block_on(async {
client::send_message(api_url, destination, topic, message, deadline).await
});
let response = result.to_rhai_error()?;
Ok(value_to_dynamic(response))
}
/// Wrapper for mycelium::receive_messages
///
/// Receives messages from a topic via the Mycelium node.
pub fn mycelium_receive_messages(api_url: &str, topic: &str, count: i64) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?;
// Convert count to u32
let count = if count < 0 {
return Err(Box::new(EvalAltResult::ErrorRuntime(
"Count cannot be negative".into(),
rhai::Position::NONE
)));
} else if count > u32::MAX as i64 {
return Err(Box::new(EvalAltResult::ErrorRuntime(
format!("Count too large, maximum is {}", u32::MAX).into(),
rhai::Position::NONE
)));
} else {
count as u32
};
let result = rt.block_on(async {
client::receive_messages(api_url, topic, count).await
});
let messages = result.to_rhai_error()?;
Ok(value_to_dynamic(messages))
}