//! Rhai bindings for Vault and EVM Client modules //! Provides a single source of truth for scripting integration. use rhai::Engine; use crate::session::SessionManager; /// Register core Vault and EVM Client APIs with the Rhai scripting engine. #[cfg(not(target_arch = "wasm32"))] pub fn register_rhai_api( engine: &mut Engine, _session_manager: std::sync::Arc>>, ) { engine.register_type::>(); engine.register_fn("select_keypair", RhaiSessionManager::::select_keypair); engine.register_fn("select_default_keypair", RhaiSessionManager::::select_default_keypair); engine.register_fn("sign", RhaiSessionManager::::sign); // No global constant registration: Rhai does not support this directly. // Scripts should receive the session manager as a parameter or via module scope. } #[cfg(not(target_arch = "wasm32"))] #[derive(Clone)] struct RhaiSessionManager { inner: std::sync::Arc>>, } #[cfg(target_arch = "wasm32")] #[derive(Clone)] struct RhaiSessionManager { inner: S, } #[cfg(not(target_arch = "wasm32"))] impl RhaiSessionManager { pub fn select_keypair(&self, key_id: String) -> Result<(), String> { // Use Mutex for interior mutability, &self is sufficient self.inner.lock().unwrap().select_keypair(&key_id).map_err(|e| format!("select_keypair error: {e}")) } pub fn select_default_keypair(&self) -> Result<(), String> { self.inner.lock().unwrap().select_default_keypair() .map_err(|e| format!("select_default_keypair error: {e}")) } pub fn sign(&self, message: rhai::Blob) -> Result { let sm = self.inner.lock().unwrap(); // Try to get the current keyspace name from session state if possible let _keypair = sm.current_keypair().ok_or("No keypair selected")?; // Sign using the session manager; password and keyspace are not needed (already unlocked) crate::rhai_sync_helpers::sign_sync::( &sm, &message, ).map_err(|e| format!("sign error: {e}")) } } #[cfg(target_arch = "wasm32")] impl RhaiSessionManager { pub fn select_keypair(&self, key_id: String) -> Result<(), String> { // Use the global singleton for session management crate::session_singleton::SESSION_MANAGER.with(|cell| { let mut opt = cell.borrow_mut(); if let Some(session) = opt.as_mut() { session.select_keypair(&key_id).map_err(|e| format!("select_keypair error: {e}")) } else { Err("Session not initialized".to_string()) } }) } pub fn current_keypair(&self) -> Option { crate::session_singleton::SESSION_MANAGER.with(|cell| { let opt = cell.borrow(); opt.as_ref() .and_then(|session| session.current_keypair().map(|k| k.id.clone())) }) } pub fn logout(&self) { crate::session_singleton::SESSION_MANAGER.with(|cell| { let mut opt = cell.borrow_mut(); if let Some(session) = opt.as_mut() { session.logout(); } }); } pub fn sign(&self, _message: rhai::Blob) -> Result { // Signing is async in WASM; must be called from JS/wasm-bindgen, not Rhai Err("sign is async in WASM; use the WASM sign() API from JS instead".to_string()) } } // WASM-specific API: no Arc/Mutex, just a reference #[cfg(target_arch = "wasm32")] pub fn register_rhai_api( engine: &mut Engine, // session_manager: &SessionManager, ) { // WASM registration logic (adapt as needed) // Example: engine.register_type::>(); // engine.register_fn(...); // In WASM, register global functions that operate on the singleton engine.register_fn("select_keypair", |key_id: String| { crate::wasm_helpers::select_keypair_global(&key_id) }); // Calls the shared WASM session singleton engine.register_fn("sign", |_message: rhai::Blob| -> Result { Err("sign is async in WASM; use the WASM sign() API from JS instead".to_string()) }); // No global session object in WASM; use JS/WASM API for session ops } // --- Sync wrappers for async Rust APIs (to be implemented with block_on or similar) --- // These should be implemented in a separate module (rhai_sync_helpers.rs) // and use block_on or spawn_local for WASM compatibility.