diff --git a/installers/base.rhai b/installers/base.rhai new file mode 100644 index 0000000..8f256a8 --- /dev/null +++ b/installers/base.rhai @@ -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" diff --git a/installers/install_all.rhai b/installers/install_all.rhai index debafdb..d9f86cf 100644 --- a/installers/install_all.rhai +++ b/installers/install_all.rhai @@ -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`); diff --git a/installers/nerctl.rhai b/installers/nerctl.rhai index 69951b0..cae25dc 100644 --- a/installers/nerctl.rhai +++ b/installers/nerctl.rhai @@ -27,13 +27,13 @@ fn ipfs_download(){ let name="ipfs"; 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); - copy(`/tmp/${name}/kubo/ipfs`,"/root/hero/bin/ipfs"); - // delete(`/tmp/${name}`); + copy_bin(`/tmp/${name}/kubo/ipfs`); + delete(`/tmp/${name}`); } - +platform_check_linux_x86(); nerdctl_download(); // ipfs_download(); diff --git a/src/os/mod.rs b/src/os/mod.rs index b1a48de..597497a 100644 --- a/src/os/mod.rs +++ b/src/os/mod.rs @@ -4,4 +4,5 @@ pub mod package; pub use fs::*; pub use download::*; -pub use package::*; \ No newline at end of file +pub use package::*; +pub mod platform; \ No newline at end of file diff --git a/src/os/platform.rs b/src/os/platform.rs new file mode 100644 index 0000000..bddc576 --- /dev/null +++ b/src/os/platform.rs @@ -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(), + )) + } +} \ No newline at end of file diff --git a/src/rhai/error.rs b/src/rhai/error.rs index c5e7037..e6ba5d4 100644 --- a/src/rhai/error.rs +++ b/src/rhai/error.rs @@ -1,80 +1,62 @@ -//! Error handling for Rhai integration -//! -//! This module provides utilities for converting SAL error types to Rhai error types. +use rhai::{Engine, EvalAltResult, Position}; +use thiserror::Error; -use rhai::{EvalAltResult, Position}; -use crate::os::{FsError, DownloadError}; -use crate::os::package::PackageError; - -/// Convert a FsError to a Rhai EvalAltResult -pub fn fs_error_to_rhai_error(err: FsError) -> Box { - let err_msg = err.to_string(); - Box::new(EvalAltResult::ErrorRuntime( - err_msg.into(), - Position::NONE - )) +#[derive(Debug, Error, Clone)] +pub enum SalError { + #[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 DownloadError to a Rhai EvalAltResult -pub fn download_error_to_rhai_error(err: DownloadError) -> Box { - let err_msg = err.to_string(); - Box::new(EvalAltResult::ErrorRuntime( - err_msg.into(), - Position::NONE - )) +impl SalError { + pub fn new(kind: &str, message: &str) -> Self { + SalError::Generic(kind.to_string(), message.to_string()) + } } -/// Convert a PackageError to a Rhai EvalAltResult -pub fn package_error_to_rhai_error(err: PackageError) -> Box { - let err_msg = err.to_string(); - Box::new(EvalAltResult::ErrorRuntime( - err_msg.into(), - Position::NONE - )) +impl From for Box { + fn from(err: SalError) -> Self { + 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> { - // 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 +/// A trait for converting a Result to a Rhai-compatible error pub trait ToRhaiError { - /// Convert the error to a Rhai EvalAltResult fn to_rhai_error(self) -> Result>; } -impl ToRhaiError for Result { +impl ToRhaiError for Result { fn to_rhai_error(self) -> Result> { - self.map_err(fs_error_to_rhai_error) + self.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + e.to_string().into(), + Position::NONE, + )) + }) } } -impl ToRhaiError for Result { - fn to_rhai_error(self) -> Result> { - self.map_err(download_error_to_rhai_error) - } -} -impl ToRhaiError for Result { - fn to_rhai_error(self) -> Result> { - self.map_err(package_error_to_rhai_error) - } +/// Register all the SalError variants with the Rhai engine +/// +/// # Arguments +/// +/// * `engine` - The Rhai engine to register the error types with +/// +/// # Returns +/// +/// * `Result<(), Box>` - Ok if registration was successful, Err otherwise +pub fn register_error_types(engine: &mut Engine) -> Result<(), Box> { + engine.register_type_with_name::("SalError") + .register_fn("to_string", |err: &mut SalError| err.to_string()); + Ok(()) } \ No newline at end of file diff --git a/src/rhai/mod.rs b/src/rhai/mod.rs index 7a172e3..105340c 100644 --- a/src/rhai/mod.rs +++ b/src/rhai/mod.rs @@ -5,10 +5,11 @@ mod buildah; mod core; -mod error; +pub mod error; mod git; mod nerdctl; mod os; +mod platform; mod postgresclient; mod process; mod redisclient; @@ -182,7 +183,10 @@ pub fn register(engine: &mut Engine) -> Result<(), Box> { // Register PostgreSQL client module functions postgresclient::register_postgresclient_module(engine)?; - // Register utility functions + // Register Platform module functions + platform::register(engine); + + // Register utility functions engine.register_fn("is_def_fn", |_name: &str| -> bool { // This is a utility function to check if a function is defined in the engine // For testing purposes, we'll just return true diff --git a/src/rhai/mycelium.rs b/src/rhai/mycelium.rs index 03cc68c..1222ec7 100644 --- a/src/rhai/mycelium.rs +++ b/src/rhai/mycelium.rs @@ -8,7 +8,7 @@ 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; +use rhai::Position; /// 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 ToRhaiError for Result { - fn to_rhai_error(self) -> Result> { - self.map_err(|e| { - Box::new(EvalAltResult::ErrorRuntime( - format!("Mycelium error: {}", e).into(), - rhai::Position::NONE - )) - }) - } -} // // Mycelium Client Function Wrappers @@ -96,13 +85,16 @@ impl ToRhaiError for Result { /// Gets information about the Mycelium node. pub fn mycelium_get_node_info(api_url: &str) -> Result> { let rt = get_runtime()?; - - let result = rt.block_on(async { - client::get_node_info(api_url).await - }); - - let node_info = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::get_node_info(api_url).await }); + + let node_info = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + Ok(value_to_dynamic(node_info)) } @@ -111,13 +103,16 @@ pub fn mycelium_get_node_info(api_url: &str) -> Result Result> { let rt = get_runtime()?; - - let result = rt.block_on(async { - client::list_peers(api_url).await - }); - - let peers = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::list_peers(api_url).await }); + + let peers = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + Ok(value_to_dynamic(peers)) } @@ -126,13 +121,16 @@ pub fn mycelium_list_peers(api_url: &str) -> Result> /// Adds a new peer to the Mycelium node. pub fn mycelium_add_peer(api_url: &str, peer_address: &str) -> Result> { let rt = get_runtime()?; - - let result = rt.block_on(async { - client::add_peer(api_url, peer_address).await - }); - - let response = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::add_peer(api_url, peer_address).await }); + + let response = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + Ok(value_to_dynamic(response)) } @@ -141,13 +139,16 @@ pub fn mycelium_add_peer(api_url: &str, peer_address: &str) -> Result Result> { let rt = get_runtime()?; - - let result = rt.block_on(async { - client::remove_peer(api_url, peer_id).await - }); - - let response = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::remove_peer(api_url, peer_id).await }); + + let response = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + Ok(value_to_dynamic(response)) } @@ -156,13 +157,16 @@ pub fn mycelium_remove_peer(api_url: &str, peer_id: &str) -> Result Result> { let rt = get_runtime()?; - - let result = rt.block_on(async { - client::list_selected_routes(api_url).await - }); - - let routes = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::list_selected_routes(api_url).await }); + + let routes = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + Ok(value_to_dynamic(routes)) } @@ -171,20 +175,29 @@ pub fn mycelium_list_selected_routes(api_url: &str) -> Result Result> { let rt = get_runtime()?; - - let result = rt.block_on(async { - client::list_fallback_routes(api_url).await - }); - - let routes = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::list_fallback_routes(api_url).await }); + + let routes = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + 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, reply_deadline_secs: i64) -> Result> { +pub fn mycelium_send_message( + api_url: &str, + destination: &str, + topic: &str, + message: &str, + reply_deadline_secs: i64, +) -> Result> { let rt = get_runtime()?; let deadline = if reply_deadline_secs < 0 { @@ -192,20 +205,28 @@ pub fn mycelium_send_message(api_url: &str, destination: &str, topic: &str, mess } else { Some(Duration::from_secs(reply_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()?; - + + let result = + rt.block_on(async { client::send_message(api_url, destination, topic, message, deadline).await }); + + let response = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + 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, wait_deadline_secs: i64) -> Result> { +pub fn mycelium_receive_messages( + api_url: &str, + topic: &str, + wait_deadline_secs: i64, +) -> Result> { let rt = get_runtime()?; let deadline = if wait_deadline_secs < 0 { @@ -213,12 +234,15 @@ pub fn mycelium_receive_messages(api_url: &str, topic: &str, wait_deadline_secs: } else { Some(Duration::from_secs(wait_deadline_secs as u64)) }; - - let result = rt.block_on(async { - client::receive_messages(api_url, topic, deadline).await - }); - - let messages = result.to_rhai_error()?; - + + let result = rt.block_on(async { client::receive_messages(api_url, topic, deadline).await }); + + let messages = result.map_err(|e| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Mycelium error: {}", e).into(), + Position::NONE, + )) + })?; + Ok(value_to_dynamic(messages)) } \ No newline at end of file diff --git a/src/rhai/platform.rs b/src/rhai/platform.rs new file mode 100644 index 0000000..5a9d5f7 --- /dev/null +++ b/src/rhai/platform.rs @@ -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()); +} \ No newline at end of file diff --git a/src/rhai/zinit.rs b/src/rhai/zinit.rs index 1ae35dd..2167281 100644 --- a/src/rhai/zinit.rs +++ b/src/rhai/zinit.rs @@ -36,16 +36,6 @@ pub fn register_zinit_module(engine: &mut Engine) -> Result<(), Box ToRhaiError for Result { - fn to_rhai_error(self) -> Result> { - self.map_err(|e| { - Box::new(EvalAltResult::ErrorRuntime( - format!("Zinit error: {}", e).into(), - rhai::Position::NONE, - )) - }) - } -} // Helper function to get a runtime fn get_runtime() -> Result> {