rave_engine 0.8.0

A secure and efficient JSON Schema validation and Rhai script execution engine
Documentation
use std::str::FromStr;

use crate::rhai_engine::RhaiEngine;
use hdi::prelude::AgentPubKeyB64;
use hdi::prelude::{AgentPubKey, Record, Signature};
use hdk::prelude::SerializedBytes;
use hdk::prelude::UnsafeBytes;
use rhai::Array;
use rhai::{EvalAltResult, Map, Position};
use rmp_serde;

/// Utility functions for type conversion and data handling in the RAVE engine.
/// This module provides functions for converting between Rhai and Holochain data types.
///
/// Attempts to convert a Rhai Map into a Holochain Record.
///
/// # Arguments
///
/// * `record` - A Rhai Map containing the record data
///
/// # Returns
///
/// * `Result<Record, Box<EvalAltResult>>` - The converted Record on success,
///   or an error if conversion fails
///
/// # Details
///
/// This function performs the following steps:
/// 1. Converts the Rhai Map to JSON
/// 2. Serializes the JSON to MessagePack format
/// 3. Converts the bytes to a Holochain Record
///
/// # Errors
///
/// Returns an error if:
/// * JSON serialization fails
/// * Record conversion fails
pub fn try_into_record(record: Map) -> Result<Record, Box<EvalAltResult>> {
    // Convert Rhai Map to JSON
    let json = RhaiEngine::rhai_map_to_json(record);

    // Serialize to MessagePack format
    let bytes = rmp_serde::to_vec(&json).map_err(|e| {
        Box::new(EvalAltResult::ErrorRuntime(
            format!("Failed to serialize record: {e}").into(),
            Position::NONE,
        ))
    })?;

    // Convert to Holochain Record
    let bytes = SerializedBytes::from(UnsafeBytes::from(bytes));
    Record::try_from(bytes).map_err(|e| {
        Box::new(EvalAltResult::ErrorRuntime(
            format!("Failed to convert to Record: {e}").into(),
            Position::NONE,
        ))
    })
}

/// Attempts to convert a byte array into an AgentPubKey.
///
/// # Arguments
///
/// * `bytes` - A Rhai Array containing the raw bytes of the public key
///
/// # Returns
///
/// * `Result<AgentPubKey, Box<EvalAltResult>>` - The converted AgentPubKey on success,
///   or an error if conversion fails
///
/// # Errors
///
/// Returns an error if:
/// * The byte array cannot be converted to a valid AgentPubKey
pub fn _try_into_agent_pubkey(bytes: Array) -> Result<AgentPubKey, Box<EvalAltResult>> {
    // Convert Rhai Array to bytes and create AgentPubKey
    AgentPubKey::try_from_raw_39(
        bytes
            .iter()
            .map(|b| b.as_int().unwrap_or(0) as u8)
            .collect::<Vec<u8>>(),
    )
    .map_err(|e| {
        Box::new(EvalAltResult::ErrorRuntime(
            format!("Invalid agent key: {e}").into(),
            Position::NONE,
        ))
    })
}

pub fn try_from_string_to_agent_pubkey(string: String) -> Result<AgentPubKey, Box<EvalAltResult>> {
    AgentPubKeyB64::from_str(&string)
        .map_err(|e| {
            Box::new(EvalAltResult::ErrorRuntime(
                format!("Invalid agent key: {e}").into(),
                Position::NONE,
            ))
        })
        .map(|hash| hash.into())
}

/// Attempts to convert a byte array into a Signature.
///
/// # Arguments
///
/// * `bytes` - A Rhai Array containing the raw bytes of the signature
///
/// # Returns
///
/// * `Result<Signature, Box<EvalAltResult>>` - The converted Signature on success,
///   or an error if conversion fails
///
/// # Details
///
/// This function expects exactly 64 bytes for the signature.
///
/// # Errors
///
/// Returns an error if:
/// * The input array does not contain exactly 64 bytes
pub fn try_into_signature(bytes: Array) -> Result<Signature, Box<EvalAltResult>> {
    // Convert Rhai Array to fixed-size signature array
    let signature_bytes: [u8; 64] = bytes
        .iter()
        .map(|b| b.as_int().unwrap_or(0) as u8)
        .collect::<Vec<u8>>()
        .try_into()
        .map_err(|_| {
            Box::new(EvalAltResult::ErrorRuntime(
                "Invalid signature length".into(),
                Position::NONE,
            ))
        })?;

    Ok(Signature::from(signature_bytes))
}