From 3110ac1fbb3c4f88bcfb3ab892238e9b9e1c4bcf Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Thu, 17 Oct 2024 00:41:06 +0800 Subject: [PATCH] fix: avoid auto unsubscribe (due to gc) in js env --- Cargo.lock | 1 + crates/loro-wasm/Cargo.toml | 1 + crates/loro-wasm/src/lib.rs | 20 +++++++++++++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a50d623e2..c99ad79ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1482,6 +1482,7 @@ dependencies = [ "js-sys", "loro-internal 0.16.12", "loro-rle 0.16.12", + "once_cell", "serde", "serde-wasm-bindgen 0.6.5", "serde_json", diff --git a/crates/loro-wasm/Cargo.toml b/crates/loro-wasm/Cargo.toml index e0cb2b936..162bba66b 100644 --- a/crates/loro-wasm/Cargo.toml +++ b/crates/loro-wasm/Cargo.toml @@ -21,6 +21,7 @@ rle = { path = "../rle", package = "loro-rle" } tracing-wasm = "0.2.1" tracing = { version = "0.1", features = ["release_max_level_warn"] } serde_json = "1" +once_cell.workspace = true [features] default = [] diff --git a/crates/loro-wasm/src/lib.rs b/crates/loro-wasm/src/lib.rs index d2b4a0f91..54f25e394 100644 --- a/crates/loro-wasm/src/lib.rs +++ b/crates/loro-wasm/src/lib.rs @@ -28,7 +28,7 @@ use loro_internal::{ }; use rle::HasLength; use serde::{Deserialize, Serialize}; -use std::{cell::RefCell, cmp::Ordering, rc::Rc, sync::Arc}; +use std::{cell::RefCell, cmp::Ordering, mem::ManuallyDrop, rc::Rc, sync::Arc}; use wasm_bindgen::{__rt::IntoJsResult, prelude::*, throw_val}; use wasm_bindgen_derive::TryFromJsValue; @@ -4240,9 +4240,23 @@ fn js_to_export_mode(js_mode: JsExportMode) -> JsResult> { } fn subscription_to_js_function_callback(sub: Subscription) -> JsValue { - let mut sub = Some(sub); + use once_cell::sync::Lazy; + use std::collections::HashMap; + use std::sync::Mutex; + + static SUBSCRIPTION_MAP: Lazy>> = + Lazy::new(|| Mutex::new(HashMap::new())); + static NEXT_ID: Lazy> = Lazy::new(|| Mutex::new(0)); + + let id = { + let mut id = NEXT_ID.lock().unwrap(); + *id += 1; + *id + }; + + SUBSCRIPTION_MAP.lock().unwrap().insert(id, sub); let closure = Closure::wrap(Box::new(move || { - if let Some(sub) = sub.take() { + if let Some(sub) = SUBSCRIPTION_MAP.lock().unwrap().remove(&id) { sub.unsubscribe(); } }) as Box);