diff options
| author | sneurlax <sneurlax@gmail.com> | 2024-10-10 21:26:30 -0500 |
|---|---|---|
| committer | sneurlax <sneurlax@gmail.com> | 2024-10-10 21:26:30 -0500 |
| commit | c2c2f2c00dba3b7253627ddfaec37b2d015ba36b (patch) | |
| tree | 9ec455da551e730e87ac573b929cf6f9244bb82d /impls/monero_rust/src | |
| parent | 4694bb913f7709c2b2fa568f065cc56f92f09555 (diff) | |
allow lib to be loaded by consumer crates
and document the required placement
Diffstat (limited to 'impls/monero_rust/src')
| -rw-r--r-- | impls/monero_rust/src/lib.rs | 147 | ||||
| -rw-r--r-- | impls/monero_rust/src/main.rs | 6 |
2 files changed, 102 insertions, 51 deletions
diff --git a/impls/monero_rust/src/lib.rs b/impls/monero_rust/src/lib.rs index d576ea6..2175083 100644 --- a/impls/monero_rust/src/lib.rs +++ b/impls/monero_rust/src/lib.rs @@ -1,62 +1,69 @@ use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_int, c_void}; use std::ptr::NonNull; +use std::sync::Arc; + +use libloading::{Library, Symbol}; pub const NETWORK_TYPE_MAINNET: c_int = 0; pub const NETWORK_TYPE_TESTNET: c_int = 1; pub const NETWORK_TYPE_STAGENET: c_int = 2; -extern "C" { - pub fn MONERO_WalletManagerFactory_getWalletManager() -> *mut c_void; - pub fn MONERO_WalletManager_createWallet( - wm_ptr: *mut c_void, - path: *const c_char, - password: *const c_char, - language: *const c_char, - networkType: c_int, - ) -> *mut c_void; - pub fn MONERO_Wallet_seed( - wallet_ptr: *mut c_void, - seed_offset: *const c_char, - ) -> *const c_char; - pub fn MONERO_WalletManager_closeWallet( - wm_ptr: *mut c_void, - wallet_ptr: *mut c_void, - store: bool, - ) -> bool; - pub fn MONERO_Wallet_errorString(wallet_ptr: *mut c_void) -> *const c_char; - pub fn MONERO_Wallet_status(wallet_ptr: *mut c_void) -> c_int; - pub fn MONERO_Wallet_address( - wallet_ptr: *mut c_void, - account_index: u64, - address_index: u64, - ) -> *const c_char; - pub fn MONERO_Wallet_isDeterministic(wallet_ptr: *mut c_void) -> bool; - pub fn MONERO_WalletManager_walletExists( - wm_ptr: *mut c_void, - path: *const c_char, - ) -> bool; -} - #[derive(Debug)] pub enum WalletError { NullPointer, FfiError(String), WalletErrorCode(c_int, String), + LibraryLoadError(String), } -type WalletResult<T> = Result<T, WalletError>; +pub type WalletResult<T> = Result<T, WalletError>; pub struct WalletManager { ptr: NonNull<c_void>, + library: Arc<Library>, } impl WalletManager { - pub fn new() -> WalletResult<Self> { + /// Create a new WalletManager, optionally specifying the path to the shared library. + pub fn new(lib_path: Option<&str>) -> WalletResult<Self> { + let lib = match lib_path { + Some(path) => { + unsafe { + Library::new(path).map_err(|e| WalletError::LibraryLoadError(e.to_string()))? + } + } + None => { + // Attempt to load from the same directory as the executable. + let exe_path = std::env::current_exe() + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))?; + let exe_dir = exe_path.parent().ok_or_else(|| { + WalletError::LibraryLoadError("Failed to get executable directory".to_string()) + })?; + let lib_path = exe_dir.join("libwallet2_api_c.so"); + + unsafe { + if lib_path.exists() { + Library::new(lib_path) + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))? + } else { + // Fallback to standard locations. + Library::new("libwallet2_api_c.so") + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))? + } + } + } + }; + + let library = Arc::new(lib); + unsafe { - let ptr = MONERO_WalletManagerFactory_getWalletManager(); + let func: Symbol<unsafe extern "C" fn() -> *mut c_void> = + library.get(b"MONERO_WalletManagerFactory_getWalletManager\0") + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))?; + let ptr = func(); NonNull::new(ptr) - .map(|nn_ptr| WalletManager { ptr: nn_ptr }) + .map(|nn_ptr| WalletManager { ptr: nn_ptr, library }) .ok_or(WalletError::NullPointer) } } @@ -73,7 +80,19 @@ impl WalletManager { let c_language = CString::new(language).expect("CString::new failed"); unsafe { - let wallet_ptr = MONERO_WalletManager_createWallet( + let func: Symbol< + unsafe extern "C" fn( + *mut c_void, + *const c_char, + *const c_char, + *const c_char, + c_int, + ) -> *mut c_void, + > = self + .library + .get(b"MONERO_WalletManager_createWallet\0") + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))?; + let wallet_ptr = func( self.ptr.as_ptr(), c_path.as_ptr(), c_password.as_ptr(), @@ -87,15 +106,24 @@ impl WalletManager { Ok(Wallet { ptr: NonNull::new_unchecked(wallet_ptr), manager_ptr: self.ptr, + library: Arc::clone(&self.library), // Keep the library alive. }) } } } } +impl Drop for WalletManager { + fn drop(&mut self) { + // The library will be dropped automatically when all references are gone. + } +} + +#[derive(Clone)] pub struct Wallet { ptr: NonNull<c_void>, manager_ptr: NonNull<c_void>, + library: Arc<Library>, } impl Wallet { @@ -103,7 +131,11 @@ impl Wallet { let c_seed_offset = CString::new(seed_offset).expect("CString::new failed"); unsafe { - let seed_ptr = MONERO_Wallet_seed(self.ptr.as_ptr(), c_seed_offset.as_ptr()); + let func: Symbol<unsafe extern "C" fn(*mut c_void, *const c_char) -> *const c_char> = + self.library + .get(b"MONERO_Wallet_seed\0") + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))?; + let seed_ptr = func(self.ptr.as_ptr(), c_seed_offset.as_ptr()); if seed_ptr.is_null() { Err(self.get_last_error()) @@ -122,11 +154,11 @@ impl Wallet { pub fn get_address(&self, account_index: u64, address_index: u64) -> WalletResult<String> { unsafe { - let address_ptr = MONERO_Wallet_address( - self.ptr.as_ptr(), - account_index, - address_index, - ); + let func: Symbol<unsafe extern "C" fn(*mut c_void, u64, u64) -> *const c_char> = + self.library + .get(b"MONERO_Wallet_address\0") + .map_err(|e| WalletError::LibraryLoadError(e.to_string()))?; + let address_ptr = func(self.ptr.as_ptr(), account_index, address_index); if address_ptr.is_null() { Err(self.get_last_error()) @@ -140,13 +172,28 @@ impl Wallet { } pub fn is_deterministic(&self) -> bool { - unsafe { MONERO_Wallet_isDeterministic(self.ptr.as_ptr()) } + unsafe { + let func: Symbol<unsafe extern "C" fn(*mut c_void) -> bool> = self + .library + .get(b"MONERO_Wallet_isDeterministic\0") + .expect("Failed to load MONERO_Wallet_isDeterministic"); + func(self.ptr.as_ptr()) + } } fn get_last_error(&self) -> WalletError { unsafe { - let error_ptr = MONERO_Wallet_errorString(self.ptr.as_ptr()); - let status = MONERO_Wallet_status(self.ptr.as_ptr()); + let error_func: Symbol<unsafe extern "C" fn(*mut c_void) -> *const c_char> = self + .library + .get(b"MONERO_Wallet_errorString\0") + .expect("Failed to load MONERO_Wallet_errorString"); + let status_func: Symbol<unsafe extern "C" fn(*mut c_void) -> c_int> = self + .library + .get(b"MONERO_Wallet_status\0") + .expect("Failed to load MONERO_Wallet_status"); + + let error_ptr = error_func(self.ptr.as_ptr()); + let status = status_func(self.ptr.as_ptr()); let error_msg = if error_ptr.is_null() { "Unknown error".to_string() @@ -164,7 +211,13 @@ impl Wallet { impl Drop for Wallet { fn drop(&mut self) { unsafe { - MONERO_WalletManager_closeWallet(self.manager_ptr.as_ptr(), self.ptr.as_ptr(), false); + let func: Symbol< + unsafe extern "C" fn(*mut c_void, *mut c_void, bool) -> bool, + > = self + .library + .get(b"MONERO_WalletManager_closeWallet\0") + .expect("Failed to load MONERO_WalletManager_closeWallet"); + func(self.manager_ptr.as_ptr(), self.ptr.as_ptr(), false); } } } diff --git a/impls/monero_rust/src/main.rs b/impls/monero_rust/src/main.rs index eb9e148..aae688b 100644 --- a/impls/monero_rust/src/main.rs +++ b/impls/monero_rust/src/main.rs @@ -1,9 +1,7 @@ -use monero_rust::{ - WalletError, WalletManager, NETWORK_TYPE_MAINNET, -}; +use monero_rust::{WalletError, WalletManager, NETWORK_TYPE_MAINNET}; fn main() -> Result<(), WalletError> { - let wallet_manager = WalletManager::new()?; + let wallet_manager = WalletManager::new(None)?; let wallet = wallet_manager.create_wallet( "wallet", |
