From 7dfc8e3bc3cf254e74d8d53eac8ad9215a5fc044 Mon Sep 17 00:00:00 2001 From: Marc Espin Date: Wed, 10 Jan 2024 11:05:05 +0100 Subject: [PATCH] feat(2.0, nodejs): Silently request to stop background syncing when `WalletMethodHandler` is dropped (#1793) * feat(nodejs): Silently stop background syncing when Wallet is dropped * fmt * chore: Also call request_stop_background_syncing when destroyed manually --- bindings/nodejs/src/wallet.rs | 51 ++++++++++++++++--- .../core/operations/background_syncing.rs | 8 ++- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/bindings/nodejs/src/wallet.rs b/bindings/nodejs/src/wallet.rs index 6bc039b6fc..ae90b2131d 100644 --- a/bindings/nodejs/src/wallet.rs +++ b/bindings/nodejs/src/wallet.rs @@ -1,7 +1,10 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use std::sync::Arc; +use std::{ + ops::{Deref, DerefMut}, + sync::Arc, +}; use iota_sdk_bindings_core::{ call_wallet_method as rust_call_wallet_method, @@ -16,26 +19,58 @@ use crate::{ build_js_error, client::ClientMethodHandler, destroyed_err, secret_manager::SecretManagerMethodHandler, NodejsError, }; -pub type WalletMethodHandler = Arc>>; +pub struct WalletMethodHandlerInner(Option); + +impl Drop for WalletMethodHandlerInner { + fn drop(&mut self) { + log::debug!("drop WalletMethodHandlerInner"); + // Request to stop the background syncing silently if this wallet hasn't been destroyed yet + if let Some(wallet) = self.0.take() { + wallet.request_stop_background_syncing(); + } + } +} + +impl Deref for WalletMethodHandlerInner { + type Target = Option; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for WalletMethodHandlerInner { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub type WalletMethodHandler = Arc>; #[napi(js_name = "createWallet")] pub async fn create_wallet(options: String) -> Result> { let wallet_options = serde_json::from_str::(&options).map_err(NodejsError::new)?; let wallet = wallet_options.build().await.map_err(NodejsError::new)?; - Ok(External::new(Arc::new(RwLock::new(Some(wallet))))) + Ok(External::new(Arc::new(RwLock::new(WalletMethodHandlerInner(Some( + wallet, + )))))) } #[napi(js_name = "destroyWallet")] pub async fn destroy_wallet(wallet: External) { - *wallet.as_ref().write().await = None; + let mut wallet = wallet.as_ref().write().await; + if let Some(wallet) = &**wallet { + wallet.request_stop_background_syncing(); + } + **wallet = None; } #[napi(js_name = "callWalletMethod")] pub async fn call_wallet_method(wallet: External, method: String) -> Result { let method = serde_json::from_str::(&method).map_err(NodejsError::new)?; - match &*wallet.as_ref().read().await { + match &**wallet.as_ref().read().await { Some(wallet) => { let response = rust_call_wallet_method(wallet, method).await; match response { @@ -58,7 +93,7 @@ pub async fn listen_wallet( validated_event_types.push(WalletEventType::try_from(event_type).map_err(NodejsError::new)?); } - match &*wallet.as_ref().read().await { + match &**wallet.as_ref().read().await { Some(wallet) => { wallet .listen(validated_event_types, move |event_data| { @@ -78,7 +113,7 @@ pub async fn listen_wallet( #[napi(js_name = "getClient")] pub async fn get_client(wallet: External) -> Result> { - if let Some(wallet) = &*wallet.as_ref().read().await { + if let Some(wallet) = &**wallet.as_ref().read().await { Ok(External::new(Arc::new(RwLock::new(Some(wallet.client().clone()))))) } else { Err(destroyed_err("Wallet")) @@ -87,7 +122,7 @@ pub async fn get_client(wallet: External) -> Result) -> Result> { - if let Some(wallet) = &*wallet.as_ref().read().await { + if let Some(wallet) = &**wallet.as_ref().read().await { Ok(External::new(wallet.get_secret_manager().clone())) } else { Err(destroyed_err("Wallet")) diff --git a/sdk/src/wallet/core/operations/background_syncing.rs b/sdk/src/wallet/core/operations/background_syncing.rs index 9840b967b6..9bea901acc 100644 --- a/sdk/src/wallet/core/operations/background_syncing.rs +++ b/sdk/src/wallet/core/operations/background_syncing.rs @@ -72,6 +72,12 @@ where Ok(()) } + /// Request to stop the background syncing of the wallet + pub fn request_stop_background_syncing(&self) { + log::debug!("[request_stop_background_syncing]"); + self.background_syncing_status.store(2, Ordering::Relaxed); + } + /// Stop the background syncing of the wallet pub async fn stop_background_syncing(&self) -> crate::wallet::Result<()> { log::debug!("[stop_background_syncing]"); @@ -80,7 +86,7 @@ where return Ok(()); } // send stop request - self.background_syncing_status.store(2, Ordering::Relaxed); + self.request_stop_background_syncing(); // wait until it stopped while self.background_syncing_status.load(Ordering::Relaxed) != 0 { #[cfg(target_family = "wasm")]