...
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run

This commit is contained in:
kristof 2025-06-15 22:12:15 +02:00
parent 3a6bde02d5
commit f0d7636cda
10 changed files with 287 additions and 149 deletions

31
installers/base.rhai Normal file
View File

@ -0,0 +1,31 @@
fn mycelium(){
let name="mycelium";
let url="https://github.com/threefoldtech/mycelium/releases/download/v0.6.1/mycelium-x86_64-unknown-linux-musl.tar.gz";
download(url,`/tmp/${name}`,5000);
copy_bin(`/tmp/${name}/*`);
delete(`/tmp/${name}`);
let name="containerd";
}
fn zinit(){
let name="zinit";
let url="https://github.com/threefoldtech/zinit/releases/download/v0.2.25/zinit-linux-x86_64";
download_file(url,`/tmp/${name}`,5000);
copy_bin(`/tmp/${name}`);
delete(`/tmp/${name}`);
let name="containerd";
}
platform_check_linux_x86();
// mycelium();
zinit();
"done"

View File

@ -1,4 +1,7 @@
platform_check_linux_x86();
exec(`https://git.threefold.info/herocode/sal/raw/branch/main/installers/base.rhai`);
//install all we need for nerdctl
exec(`https://git.threefold.info/herocode/sal/raw/branch/main/installers/nerctl.rhai`); exec(`https://git.threefold.info/herocode/sal/raw/branch/main/installers/nerctl.rhai`);

View File

@ -27,13 +27,13 @@ fn ipfs_download(){
let name="ipfs"; let name="ipfs";
let url="https://github.com/ipfs/kubo/releases/download/v0.34.1/kubo_v0.34.1_linux-amd64.tar.gz"; let url="https://github.com/ipfs/kubo/releases/download/v0.34.1/kubo_v0.34.1_linux-amd64.tar.gz";
download(url,`/tmp/${name}`,20); download(url,`/tmp/${name}`,20);
copy(`/tmp/${name}/kubo/ipfs`,"/root/hero/bin/ipfs"); copy_bin(`/tmp/${name}/kubo/ipfs`);
// delete(`/tmp/${name}`); delete(`/tmp/${name}`);
} }
platform_check_linux_x86();
nerdctl_download(); nerdctl_download();
// ipfs_download(); // ipfs_download();

View File

@ -5,3 +5,4 @@ pub mod package;
pub use fs::*; pub use fs::*;
pub use download::*; pub use download::*;
pub use package::*; pub use package::*;
pub mod platform;

63
src/os/platform.rs Normal file
View File

@ -0,0 +1,63 @@
use crate::rhai::error::SalError;
#[cfg(target_os = "macos")]
pub fn is_osx() -> bool {
true
}
#[cfg(not(target_os = "macos"))]
pub fn is_osx() -> bool {
false
}
#[cfg(target_os = "linux")]
pub fn is_linux() -> bool {
true
}
#[cfg(not(target_os = "linux"))]
pub fn is_linux() -> bool {
false
}
#[cfg(target_arch = "aarch64")]
pub fn is_arm() -> bool {
true
}
#[cfg(not(target_arch = "aarch64"))]
pub fn is_arm() -> bool {
false
}
#[cfg(target_arch = "x86_64")]
pub fn is_x86() -> bool {
true
}
#[cfg(not(target_arch = "x86_64"))]
pub fn is_x86() -> bool {
false
}
pub fn check_linux_x86() -> Result<(), SalError> {
if is_linux() && is_x86() {
Ok(())
} else {
Err(SalError::Generic(
"Platform Check Error".to_string(),
"This operation is only supported on Linux x86_64.".to_string(),
))
}
}
pub fn check_macos_arm() -> Result<(), SalError> {
if is_osx() && is_arm() {
Ok(())
} else {
Err(SalError::Generic(
"Platform Check Error".to_string(),
"This operation is only supported on macOS ARM.".to_string(),
))
}
}

View File

@ -1,80 +1,62 @@
//! Error handling for Rhai integration use rhai::{Engine, EvalAltResult, Position};
//! use thiserror::Error;
//! This module provides utilities for converting SAL error types to Rhai error types.
use rhai::{EvalAltResult, Position}; #[derive(Debug, Error, Clone)]
use crate::os::{FsError, DownloadError}; pub enum SalError {
use crate::os::package::PackageError; #[error("File system error: {0}")]
FsError(String),
#[error("Download error: {0}")]
DownloadError(String),
#[error("Package error: {0}")]
PackageError(String),
#[error("{0}: {1}")]
Generic(String, String),
}
/// Convert a FsError to a Rhai EvalAltResult impl SalError {
pub fn fs_error_to_rhai_error(err: FsError) -> Box<EvalAltResult> { pub fn new(kind: &str, message: &str) -> Self {
SalError::Generic(kind.to_string(), message.to_string())
}
}
impl From<SalError> for Box<EvalAltResult> {
fn from(err: SalError) -> Self {
let err_msg = err.to_string(); let err_msg = err.to_string();
Box::new(EvalAltResult::ErrorRuntime( Box::new(EvalAltResult::ErrorRuntime(
err_msg.into(), err_msg.into(),
Position::NONE Position::NONE,
)) ))
} }
/// Convert a DownloadError to a Rhai EvalAltResult
pub fn download_error_to_rhai_error(err: DownloadError) -> Box<EvalAltResult> {
let err_msg = err.to_string();
Box::new(EvalAltResult::ErrorRuntime(
err_msg.into(),
Position::NONE
))
} }
/// Convert a PackageError to a Rhai EvalAltResult /// A trait for converting a Result to a Rhai-compatible error
pub fn package_error_to_rhai_error(err: PackageError) -> Box<EvalAltResult> {
let err_msg = err.to_string();
Box::new(EvalAltResult::ErrorRuntime(
err_msg.into(),
Position::NONE
))
}
/// Register error types with the Rhai engine
pub fn register_error_types(engine: &mut rhai::Engine) -> Result<(), Box<EvalAltResult>> {
// Register helper functions for error handling
// Note: We don't register the error types directly since they don't implement Clone
// Instead, we'll convert them to strings in the wrappers
// Register functions to get error messages
engine.register_fn("fs_error_message", |err_msg: &str| -> String {
format!("File system error: {}", err_msg)
});
engine.register_fn("download_error_message", |err_msg: &str| -> String {
format!("Download error: {}", err_msg)
});
engine.register_fn("package_error_message", |err_msg: &str| -> String {
format!("Package management error: {}", err_msg)
});
Ok(())
}
/// Trait for converting SAL errors to Rhai errors
pub trait ToRhaiError<T> { pub trait ToRhaiError<T> {
/// Convert the error to a Rhai EvalAltResult
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>>; fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>>;
} }
impl<T> ToRhaiError<T> for Result<T, FsError> { impl<T, E: std::error::Error> ToRhaiError<T> for Result<T, E> {
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> { fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
self.map_err(fs_error_to_rhai_error) self.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
e.to_string().into(),
Position::NONE,
))
})
} }
} }
impl<T> ToRhaiError<T> for Result<T, DownloadError> {
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
self.map_err(download_error_to_rhai_error)
}
}
impl<T> ToRhaiError<T> for Result<T, PackageError> { /// Register all the SalError variants with the Rhai engine
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> { ///
self.map_err(package_error_to_rhai_error) /// # Arguments
} ///
/// * `engine` - The Rhai engine to register the error types with
///
/// # Returns
///
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
pub fn register_error_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
engine.register_type_with_name::<SalError>("SalError")
.register_fn("to_string", |err: &mut SalError| err.to_string());
Ok(())
} }

View File

@ -5,10 +5,11 @@
mod buildah; mod buildah;
mod core; mod core;
mod error; pub mod error;
mod git; mod git;
mod nerdctl; mod nerdctl;
mod os; mod os;
mod platform;
mod postgresclient; mod postgresclient;
mod process; mod process;
mod redisclient; mod redisclient;
@ -182,6 +183,9 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
// Register PostgreSQL client module functions // Register PostgreSQL client module functions
postgresclient::register_postgresclient_module(engine)?; postgresclient::register_postgresclient_module(engine)?;
// Register Platform module functions
platform::register(engine);
// Register utility functions // Register utility functions
engine.register_fn("is_def_fn", |_name: &str| -> bool { engine.register_fn("is_def_fn", |_name: &str| -> bool {
// This is a utility function to check if a function is defined in the engine // This is a utility function to check if a function is defined in the engine

View File

@ -8,7 +8,7 @@ use rhai::{Engine, EvalAltResult, Array, Dynamic, Map};
use crate::mycelium as client; use crate::mycelium as client;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use serde_json::Value; use serde_json::Value;
use crate::rhai::error::ToRhaiError; use rhai::Position;
/// Register Mycelium module functions with the Rhai engine /// Register Mycelium module functions with the Rhai engine
/// ///
@ -75,17 +75,6 @@ fn value_to_dynamic(value: Value) -> Dynamic {
} }
} }
// 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 // Mycelium Client Function Wrappers
@ -97,11 +86,14 @@ impl<T> ToRhaiError<T> for Result<T, String> {
pub fn mycelium_get_node_info(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_get_node_info(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let result = rt.block_on(async { let result = rt.block_on(async { client::get_node_info(api_url).await });
client::get_node_info(api_url).await
});
let node_info = result.to_rhai_error()?; let node_info = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(node_info)) Ok(value_to_dynamic(node_info))
} }
@ -112,11 +104,14 @@ pub fn mycelium_get_node_info(api_url: &str) -> Result<Dynamic, Box<EvalAltResul
pub fn mycelium_list_peers(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_list_peers(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let result = rt.block_on(async { let result = rt.block_on(async { client::list_peers(api_url).await });
client::list_peers(api_url).await
});
let peers = result.to_rhai_error()?; let peers = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(peers)) Ok(value_to_dynamic(peers))
} }
@ -127,11 +122,14 @@ pub fn mycelium_list_peers(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>>
pub fn mycelium_add_peer(api_url: &str, peer_address: &str) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_add_peer(api_url: &str, peer_address: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let result = rt.block_on(async { let result = rt.block_on(async { client::add_peer(api_url, peer_address).await });
client::add_peer(api_url, peer_address).await
});
let response = result.to_rhai_error()?; let response = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(response)) Ok(value_to_dynamic(response))
} }
@ -142,11 +140,14 @@ pub fn mycelium_add_peer(api_url: &str, peer_address: &str) -> Result<Dynamic, B
pub fn mycelium_remove_peer(api_url: &str, peer_id: &str) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_remove_peer(api_url: &str, peer_id: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let result = rt.block_on(async { let result = rt.block_on(async { client::remove_peer(api_url, peer_id).await });
client::remove_peer(api_url, peer_id).await
});
let response = result.to_rhai_error()?; let response = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(response)) Ok(value_to_dynamic(response))
} }
@ -157,11 +158,14 @@ pub fn mycelium_remove_peer(api_url: &str, peer_id: &str) -> Result<Dynamic, Box
pub fn mycelium_list_selected_routes(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_list_selected_routes(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let result = rt.block_on(async { let result = rt.block_on(async { client::list_selected_routes(api_url).await });
client::list_selected_routes(api_url).await
});
let routes = result.to_rhai_error()?; let routes = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(routes)) Ok(value_to_dynamic(routes))
} }
@ -172,11 +176,14 @@ pub fn mycelium_list_selected_routes(api_url: &str) -> Result<Dynamic, Box<EvalA
pub fn mycelium_list_fallback_routes(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_list_fallback_routes(api_url: &str) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let result = rt.block_on(async { let result = rt.block_on(async { client::list_fallback_routes(api_url).await });
client::list_fallback_routes(api_url).await
});
let routes = result.to_rhai_error()?; let routes = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(routes)) Ok(value_to_dynamic(routes))
} }
@ -184,7 +191,13 @@ pub fn mycelium_list_fallback_routes(api_url: &str) -> Result<Dynamic, Box<EvalA
/// Wrapper for mycelium::send_message /// Wrapper for mycelium::send_message
/// ///
/// Sends a message to a destination via the Mycelium node. /// Sends a message to a destination via the Mycelium node.
pub fn mycelium_send_message(api_url: &str, destination: &str, topic: &str, message: &str, reply_deadline_secs: i64) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_send_message(
api_url: &str,
destination: &str,
topic: &str,
message: &str,
reply_deadline_secs: i64,
) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let deadline = if reply_deadline_secs < 0 { let deadline = if reply_deadline_secs < 0 {
@ -193,11 +206,15 @@ pub fn mycelium_send_message(api_url: &str, destination: &str, topic: &str, mess
Some(Duration::from_secs(reply_deadline_secs as u64)) Some(Duration::from_secs(reply_deadline_secs as u64))
}; };
let result = rt.block_on(async { let result =
client::send_message(api_url, destination, topic, message, deadline).await rt.block_on(async { client::send_message(api_url, destination, topic, message, deadline).await });
});
let response = result.to_rhai_error()?; let response = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(response)) Ok(value_to_dynamic(response))
} }
@ -205,7 +222,11 @@ pub fn mycelium_send_message(api_url: &str, destination: &str, topic: &str, mess
/// Wrapper for mycelium::receive_messages /// Wrapper for mycelium::receive_messages
/// ///
/// Receives messages from a topic via the Mycelium node. /// Receives messages from a topic via the Mycelium node.
pub fn mycelium_receive_messages(api_url: &str, topic: &str, wait_deadline_secs: i64) -> Result<Dynamic, Box<EvalAltResult>> { pub fn mycelium_receive_messages(
api_url: &str,
topic: &str,
wait_deadline_secs: i64,
) -> Result<Dynamic, Box<EvalAltResult>> {
let rt = get_runtime()?; let rt = get_runtime()?;
let deadline = if wait_deadline_secs < 0 { let deadline = if wait_deadline_secs < 0 {
@ -214,11 +235,14 @@ pub fn mycelium_receive_messages(api_url: &str, topic: &str, wait_deadline_secs:
Some(Duration::from_secs(wait_deadline_secs as u64)) Some(Duration::from_secs(wait_deadline_secs as u64))
}; };
let result = rt.block_on(async { let result = rt.block_on(async { client::receive_messages(api_url, topic, deadline).await });
client::receive_messages(api_url, topic, deadline).await
});
let messages = result.to_rhai_error()?; let messages = result.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Mycelium error: {}", e).into(),
Position::NONE,
))
})?;
Ok(value_to_dynamic(messages)) Ok(value_to_dynamic(messages))
} }

40
src/rhai/platform.rs Normal file
View File

@ -0,0 +1,40 @@
use crate::os::platform;
use rhai::{plugin::*, Engine};
#[export_module]
pub mod platform_functions {
#[rhai_fn(name = "platform_is_osx")]
pub fn is_osx() -> bool {
platform::is_osx()
}
#[rhai_fn(name = "platform_is_linux")]
pub fn is_linux() -> bool {
platform::is_linux()
}
#[rhai_fn(name = "platform_is_arm")]
pub fn is_arm() -> bool {
platform::is_arm()
}
#[rhai_fn(name = "platform_is_x86")]
pub fn is_x86() -> bool {
platform::is_x86()
}
#[rhai_fn(name = "platform_check_linux_x86")]
pub fn check_linux_x86() -> Result<(), crate::rhai::error::SalError> {
platform::check_linux_x86()
}
#[rhai_fn(name = "platform_check_macos_arm")]
pub fn check_macos_arm() -> Result<(), crate::rhai::error::SalError> {
platform::check_macos_arm()
}
}
pub fn register(engine: &mut Engine) {
let platform_module = exported_module!(platform_functions);
engine.register_global_module(platform_module.into());
}

View File

@ -36,16 +36,6 @@ pub fn register_zinit_module(engine: &mut Engine) -> Result<(), Box<EvalAltResul
Ok(()) Ok(())
} }
impl<T> ToRhaiError<T> for Result<T, zinit_client::ZinitError> {
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
self.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Zinit error: {}", e).into(),
rhai::Position::NONE,
))
})
}
}
// Helper function to get a runtime // Helper function to get a runtime
fn get_runtime() -> Result<Runtime, Box<EvalAltResult>> { fn get_runtime() -> Result<Runtime, Box<EvalAltResult>> {