From 74a7aa6c1a0b78e1b34222a4af28ae4d8793c1c8 Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Fri, 24 Mar 2023 11:20:59 +0800 Subject: [PATCH] fix: transaction --- crates/loro-internal/src/transaction.rs | 15 ++++++++--- crates/loro-wasm/src/lib.rs | 36 ++++++++++--------------- loro-js/pnpm-lock.yaml | 10 +++++-- loro-js/src/index.ts | 16 ++++++++++- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/crates/loro-internal/src/transaction.rs b/crates/loro-internal/src/transaction.rs index 689ab939..12e0e5cf 100644 --- a/crates/loro-internal/src/transaction.rs +++ b/crates/loro-internal/src/transaction.rs @@ -78,6 +78,10 @@ impl TransactionWrap { let instance = txn.with_store(|s| s.get_container_by_idx(&idx)); instance.map(|i| Map::from_instance(i, txn.client_id)) } + + pub fn commit(&self) -> Result<(), LoroError> { + self.0.borrow_mut().commit() + } } // TODO: use String as Origin for now @@ -274,18 +278,23 @@ impl Transaction { Ok(()) } - pub fn commit(&mut self) { + pub fn commit(&mut self) -> Result<(), LoroError> { if self.committed { - return; + return Err(LoroError::TransactionError( + "Transaction already committed".into(), + )); } self.committed = true; self.emit_events(); + Ok(()) } } impl Drop for Transaction { fn drop(&mut self) { - self.commit() + if !self.committed { + self.commit(); + } } } diff --git a/crates/loro-wasm/src/lib.rs b/crates/loro-wasm/src/lib.rs index e48d71b6..f46471ee 100644 --- a/crates/loro-wasm/src/lib.rs +++ b/crates/loro-wasm/src/lib.rs @@ -46,7 +46,7 @@ extern "C" { pub type JsContainerID; #[wasm_bindgen(typescript_type = "Transaction | Loro")] pub type JsTransaction; - #[wasm_bindgen(typescript_type = "String")] + #[wasm_bindgen(typescript_type = "string | undefined")] pub type JsOrigin; } @@ -246,28 +246,14 @@ impl Loro { self.0.borrow_mut().unsubscribe_deep(subscription) } - fn transaction_impl(&self, txn: TransactionWrap, f: js_sys::Function) -> JsResult<()> { - let js_txn = JsValue::from(Transaction(txn)); - f.call1(&JsValue::NULL, &js_txn)?; - // TODO: what is the best way to drop txn - // Or Reference Y-crdt: https://github.com/y-crdt/y-crdt/blob/3e7450114ab3d5d4cba93eeb0710f92371e57c74/tests-wasm/testHelper.js#L6 - let ptr = Reflect::get(&js_txn, &JsValue::from_str("ptr"))?; - let ptr = ptr.as_f64().ok_or(JsValue::NULL).unwrap() as u32; - use wasm_bindgen::convert::FromWasmAbi; - drop(unsafe { Transaction::from_abi(ptr) }); - Ok(()) - } - - pub fn transaction(&self, f: js_sys::Function) -> JsResult<()> { - let txn = self.0.borrow().transact(); - self.transaction_impl(txn, f) - } - - #[wasm_bindgen(js_name = "transactionWithOrigin")] + /// It's the caller's responsibility to commit and free the transaction + #[wasm_bindgen(js_name = "__raw__transactionWithOrigin")] pub fn transaction_with_origin(&self, origin: &JsOrigin, f: js_sys::Function) -> JsResult<()> { let origin = origin.as_string().map(Origin::from); let txn = self.0.borrow().transact_with(origin); - self.transaction_impl(txn, f) + let js_txn = JsValue::from(Transaction(txn)); + f.call1(&JsValue::NULL, &js_txn)?; + Ok(()) } } @@ -296,6 +282,14 @@ impl Event { #[wasm_bindgen] pub struct Transaction(TransactionWrap); +#[wasm_bindgen] +impl Transaction { + pub fn commit(&self) -> JsResult<()> { + self.0.commit()?; + Ok(()) + } +} + fn get_transaction_mut(txn: &JsTransaction) -> TransactionWrap { use wasm_bindgen::convert::RefMutFromWasmAbi; let js: &JsValue = txn.as_ref(); @@ -524,7 +518,5 @@ export type ContainerID = { id: string; type: ContainerType } | { interface Loro { exportFrom(version?: Uint8Array): Uint8Array; getContainerById(id: ContainerID): LoroText | LoroMap | LoroList; - transaction(callback: (txn: Transaction)=>void): void; - transactionWithOrigin(origin: string, callback: (txn: Transaction)=>void): void; } "#; diff --git a/loro-js/pnpm-lock.yaml b/loro-js/pnpm-lock.yaml index a0220b9c..ca7845c0 100644 --- a/loro-js/pnpm-lock.yaml +++ b/loro-js/pnpm-lock.yaml @@ -3,14 +3,14 @@ lockfileVersion: 5.4 specifiers: '@rollup/plugin-node-resolve': ^15.0.1 esbuild: ^0.17.12 - loro-wasm: '*' + loro-wasm: ^0.2.1 rollup: ^3.20.1 rollup-plugin-dts: ^5.3.0 rollup-plugin-esbuild: ^5.0.0 typescript: ^5.0.2 dependencies: - loro-wasm: link:node_modules/loro-wasm + loro-wasm: registry.npmmirror.com/loro-wasm/0.2.1 devDependencies: '@rollup/plugin-node-resolve': registry.npmmirror.com/@rollup/plugin-node-resolve/15.0.1_rollup@3.20.1 @@ -546,6 +546,12 @@ packages: version: 3.2.0 dev: true + registry.npmmirror.com/loro-wasm/0.2.1: + resolution: {integrity: sha512-kswaRi9RUeMW3MAdZq1kBob2AkSrihPE18FaiOEOzjpvlNHN0X2GClR5dbtouGXccEMDWlASpgVdhQPu5kO5IA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/loro-wasm/-/loro-wasm-0.2.1.tgz} + name: loro-wasm + version: 0.2.1 + dev: false + registry.npmmirror.com/magic-string/0.30.0: resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz} name: magic-string diff --git a/loro-js/src/index.ts b/loro-js/src/index.ts index aafce8c5..be6f2137 100644 --- a/loro-js/src/index.ts +++ b/loro-js/src/index.ts @@ -1,5 +1,4 @@ export { - Loro, LoroList, LoroMap, LoroText, @@ -9,9 +8,21 @@ export { setPanicHook, Transaction, } from "loro-wasm"; +import { Loro, Transaction } from "loro-wasm"; export type { ContainerID, ContainerType } from "loro-wasm"; +Loro.prototype.transact = function (cb, origin) { + this.__raw__transactionWithOrigin(origin, (txn: Transaction) => { + try { + cb(txn); + } finally { + txn.commit(); + txn.free(); + } + }); +}; + interface Event { local: boolean; origin?: string; @@ -24,5 +35,8 @@ interface Listener { declare module "loro-wasm" { interface Loro { subscribe(listener: Listener): void; + transact(f: (tx: Transaction) => void, origin?: string): void; } } + +export { Loro };