Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(2.0, nodejs): Silently request to stop background syncing when WalletMethodHandler is dropped #1793

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions bindings/nodejs/src/wallet.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -16,26 +19,58 @@ use crate::{
build_js_error, client::ClientMethodHandler, destroyed_err, secret_manager::SecretManagerMethodHandler, NodejsError,
};

pub type WalletMethodHandler = Arc<RwLock<Option<Wallet>>>;
pub struct WalletMethodHandlerInner(Option<Wallet>);

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() {
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
wallet.request_stop_background_syncing();
Thoralf-M marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

impl Deref for WalletMethodHandlerInner {
type Target = Option<Wallet>;

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<RwLock<WalletMethodHandlerInner>>;

#[napi(js_name = "createWallet")]
pub async fn create_wallet(options: String) -> Result<External<WalletMethodHandler>> {
let wallet_options = serde_json::from_str::<WalletOptions>(&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<WalletMethodHandler>) {
*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<WalletMethodHandler>, method: String) -> Result<String> {
let method = serde_json::from_str::<WalletMethod>(&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 {
Expand All @@ -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| {
Expand All @@ -78,7 +113,7 @@ pub async fn listen_wallet(

#[napi(js_name = "getClient")]
pub async fn get_client(wallet: External<WalletMethodHandler>) -> Result<External<ClientMethodHandler>> {
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"))
Expand All @@ -87,7 +122,7 @@ pub async fn get_client(wallet: External<WalletMethodHandler>) -> Result<Externa

#[napi(js_name = "getSecretManager")]
pub async fn get_secret_manager(wallet: External<WalletMethodHandler>) -> Result<External<SecretManagerMethodHandler>> {
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"))
Expand Down
8 changes: 7 additions & 1 deletion sdk/src/wallet/core/operations/background_syncing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]");
Expand All @@ -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 {
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(target_family = "wasm")]
Expand Down