From 6b7301a963c5ce3c7f0200864492972110988303 Mon Sep 17 00:00:00 2001 From: Brandon Vandegrift <798832-bmv437@users.noreply.gitlab.com> Date: Mon, 4 Sep 2023 17:34:49 -0400 Subject: [PATCH] (wasm) Improved memory management, track by struct so drop works, use --weak-ref for wasm-bindgen --- veilid-wasm/src/veilid_routing_context_js.rs | 49 ++++++++-------- veilid-wasm/src/veilid_table_db_js.rs | 59 +++++++------------- veilid-wasm/wasm_build.sh | 4 +- 3 files changed, 46 insertions(+), 66 deletions(-) diff --git a/veilid-wasm/src/veilid_routing_context_js.rs b/veilid-wasm/src/veilid_routing_context_js.rs index 76f4ed20..50db6fe7 100644 --- a/veilid-wasm/src/veilid_routing_context_js.rs +++ b/veilid-wasm/src/veilid_routing_context_js.rs @@ -3,7 +3,7 @@ use super::*; #[wasm_bindgen()] pub struct VeilidRoutingContext { - id: u32, + inner_routing_context: Option, } #[wasm_bindgen()] @@ -12,8 +12,10 @@ impl VeilidRoutingContext { /// Use one of the `VeilidRoutingContext.create___()` factory methods instead. /// @deprecated #[wasm_bindgen(constructor)] - pub fn new(id: u32) -> Self { - Self { id } + pub fn new() -> Self { + Self { + inner_routing_context: None, + } } // -------------------------------- @@ -24,8 +26,9 @@ impl VeilidRoutingContext { pub fn createWithoutPrivacy() -> APIResult { let veilid_api = get_veilid_api()?; let routing_context = veilid_api.routing_context(); - let id = add_routing_context(routing_context); - Ok(VeilidRoutingContext { id }) + Ok(VeilidRoutingContext { + inner_routing_context: Some(routing_context), + }) } /// Turn on sender privacy, enabling the use of safety routes. @@ -39,8 +42,9 @@ impl VeilidRoutingContext { pub fn createWithPrivacy() -> APIResult { let veilid_api = get_veilid_api()?; let routing_context = veilid_api.routing_context().with_privacy()?; - let id = add_routing_context(routing_context); - Ok(VeilidRoutingContext { id }) + Ok(VeilidRoutingContext { + inner_routing_context: Some(routing_context), + }) } /// Turn on privacy using a custom `SafetySelection` @@ -51,16 +55,18 @@ impl VeilidRoutingContext { let routing_context = veilid_api .routing_context() .with_custom_privacy(safety_selection)?; - let id = add_routing_context(routing_context); - Ok(VeilidRoutingContext { id }) + Ok(VeilidRoutingContext { + inner_routing_context: Some(routing_context), + }) } /// Use a specified `Sequencing` preference, with or without privacy. pub fn createWithSequencing(sequencing: Sequencing) -> APIResult { let veilid_api = get_veilid_api()?; let routing_context = veilid_api.routing_context().with_sequencing(sequencing); - let id = add_routing_context(routing_context); - Ok(VeilidRoutingContext { id }) + Ok(VeilidRoutingContext { + inner_routing_context: Some(routing_context), + }) } // -------------------------------- @@ -115,6 +121,7 @@ impl VeilidRoutingContext { /// * `call_id` - specifies which call to reply to, and it comes from a VeilidUpdate::AppCall, specifically the VeilidAppCall::id() value. /// * `message` - is an answer blob to be returned by the remote node's RoutingContext::app_call() function, and may be up to 32768 bytes pub async fn appCallReply(call_id: String, message: String) -> APIResult<()> { + let message = unmarshall(message); let call_id = match call_id.parse() { Ok(v) => v, Err(e) => { @@ -124,9 +131,7 @@ impl VeilidRoutingContext { } }; let veilid_api = get_veilid_api()?; - veilid_api - .app_call_reply(call_id, message.into_bytes()) - .await?; + veilid_api.app_call_reply(call_id, message).await?; APIRESULT_UNDEFINED } @@ -134,9 +139,8 @@ impl VeilidRoutingContext { // Instance methods // -------------------------------- fn getRoutingContext(&self) -> APIResult { - let rc = (*ROUTING_CONTEXTS).borrow(); - let Some(routing_context) = rc.get(&self.id) else { - return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("getRoutingContext", "id", self.id)); + let Some(routing_context) = &self.inner_routing_context else { + return APIResult::Err(veilid_core::VeilidAPIError::generic("Unable to getRoutingContext instance. inner_routing_context is None.")); }; APIResult::Ok(routing_context.clone()) } @@ -150,12 +154,11 @@ impl VeilidRoutingContext { #[wasm_bindgen(skip_jsdoc)] pub async fn appMessage(&self, target_string: String, message: String) -> APIResult<()> { let routing_context = self.getRoutingContext()?; + let message = unmarshall(message); let veilid_api = get_veilid_api()?; let target = veilid_api.parse_as_target(target_string).await?; - routing_context - .app_message(target, message.into_bytes()) - .await?; + routing_context.app_message(target, message).await?; APIRESULT_UNDEFINED } @@ -168,15 +171,13 @@ impl VeilidRoutingContext { /// @returns an answer blob of up to `32768` bytes, base64Url encoded. #[wasm_bindgen(skip_jsdoc)] pub async fn appCall(&self, target_string: String, request: String) -> APIResult { - let request: Vec = data_encoding::BASE64URL_NOPAD - .decode(&request.as_bytes()) - .unwrap(); + let request: Vec = unmarshall(request); let routing_context = self.getRoutingContext()?; let veilid_api = get_veilid_api()?; let target = veilid_api.parse_as_target(target_string).await?; let answer = routing_context.app_call(target, request).await?; - let answer = data_encoding::BASE64URL_NOPAD.encode(&answer); + let answer = marshall(&answer); APIResult::Ok(answer) } diff --git a/veilid-wasm/src/veilid_table_db_js.rs b/veilid-wasm/src/veilid_table_db_js.rs index 87cf9ccf..2a8c235a 100644 --- a/veilid-wasm/src/veilid_table_db_js.rs +++ b/veilid-wasm/src/veilid_table_db_js.rs @@ -3,7 +3,7 @@ use super::*; #[wasm_bindgen()] pub struct VeilidTableDB { - id: u32, + inner_table_db: Option, tableName: String, columnCount: u32, } @@ -15,48 +15,35 @@ impl VeilidTableDB { #[wasm_bindgen(constructor)] pub fn new(tableName: String, columnCount: u32) -> Self { Self { - id: 0, + inner_table_db: None, tableName, columnCount, } } fn getTableDB(&self) -> APIResult { - let table_dbs = (*TABLE_DBS).borrow(); - let Some(table_db) = table_dbs.get(&self.id) else { - return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("getTableDB", "id", self.id)); + let Some(table_db) = &self.inner_table_db else { + return APIResult::Err(veilid_core::VeilidAPIError::generic("Unable to getTableDB instance. Ensure you've called openTable().")); }; APIResult::Ok(table_db.clone()) } /// Get or create the TableDB database table. /// This is called automatically when performing actions on the TableDB. - pub async fn openTable(&mut self) -> APIResult { + pub async fn openTable(&mut self) -> APIResult<()> { let veilid_api = get_veilid_api()?; let tstore = veilid_api.table_store()?; let table_db = tstore .open(&self.tableName, self.columnCount) .await .map_err(veilid_core::VeilidAPIError::generic)?; - let new_id = add_table_db(table_db); - self.id = new_id; - APIResult::Ok(new_id) - } - - /// Release the TableDB instance from memory. - pub fn releaseTable(&mut self) -> bool { - let mut tdbs = (*TABLE_DBS).borrow_mut(); - let status = tdbs.remove(&self.id); - self.id = 0; - if status.is_none() { - return false; - } - return true; + self.inner_table_db = Some(table_db); + APIRESULT_UNDEFINED } /// Delete this TableDB. pub async fn deleteTable(&mut self) -> APIResult { - self.releaseTable(); + self.inner_table_db = None; let veilid_api = get_veilid_api()?; let tstore = veilid_api.table_store()?; @@ -68,7 +55,7 @@ impl VeilidTableDB { } async fn ensureOpen(&mut self) { - if self.id == 0 { + if self.inner_table_db.is_none() { let _ = self.openTable().await; } } @@ -128,14 +115,15 @@ impl VeilidTableDB { let table_db = self.getTableDB()?; let transaction = table_db.transact(); - let transaction_id = add_table_db_transaction(transaction); - APIResult::Ok(VeilidTableDBTransaction { id: transaction_id }) + APIResult::Ok(VeilidTableDBTransaction { + inner_transaction: Some(transaction), + }) } } #[wasm_bindgen] pub struct VeilidTableDBTransaction { - id: u32, + inner_transaction: Option, } #[wasm_bindgen] @@ -144,28 +132,19 @@ impl VeilidTableDBTransaction { /// Use `.createTransaction()` on an instance of `VeilidTableDB` instead. /// @deprecated #[wasm_bindgen(constructor)] - pub fn new(id: u32) -> Self { - Self { id } + pub fn new() -> Self { + Self { + inner_transaction: None, + } } fn getTransaction(&self) -> APIResult { - let transactions = (*TABLE_DB_TRANSACTIONS).borrow(); - let Some(transaction) = transactions.get(&self.id) else { - return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("getTransaction", "id", &self.id)); + let Some(transaction) = &self.inner_transaction else { + return APIResult::Err(veilid_core::VeilidAPIError::generic("Unable to getTransaction instance. inner_transaction is None.")); }; APIResult::Ok(transaction.clone()) } - /// Releases the transaction from memory. - pub fn releaseTransaction(&mut self) -> bool { - let mut transactions = (*TABLE_DB_TRANSACTIONS).borrow_mut(); - self.id = 0; - if transactions.remove(&self.id).is_none() { - return false; - } - return true; - } - /// Commit the transaction. Performs all actions atomically. pub async fn commit(&self) -> APIResult<()> { let transaction = self.getTransaction()?; diff --git a/veilid-wasm/wasm_build.sh b/veilid-wasm/wasm_build.sh index 7a6bb0f5..5cf70dc6 100755 --- a/veilid-wasm/wasm_build.sh +++ b/veilid-wasm/wasm_build.sh @@ -37,7 +37,7 @@ if [[ "$1" == "release" ]]; then cargo build --target wasm32-unknown-unknown --release mkdir -p $OUTPUTDIR - wasm-bindgen --out-dir $OUTPUTDIR --target web $INPUTDIR/veilid_wasm.wasm + wasm-bindgen --out-dir $OUTPUTDIR --target web --weak-refs $INPUTDIR/veilid_wasm.wasm wasm-strip $OUTPUTDIR/veilid_wasm_bg.wasm else OUTPUTDIR=../target/wasm32-unknown-unknown/debug/pkg @@ -45,7 +45,7 @@ else RUSTFLAGS="-O -g $RUSTFLAGS" cargo build --target wasm32-unknown-unknown mkdir -p $OUTPUTDIR - wasm-bindgen --out-dir $OUTPUTDIR --target web --keep-debug --debug $INPUTDIR/veilid_wasm.wasm + wasm-bindgen --out-dir $OUTPUTDIR --target web --weak-refs --keep-debug --debug $INPUTDIR/veilid_wasm.wasm ./wasm-sourcemap.py $OUTPUTDIR/veilid_wasm_bg.wasm -o $OUTPUTDIR/veilid_wasm_bg.wasm.map --dwarfdump $DWARFDUMP # wasm-strip $OUTPUTDIR/veilid_wasm_bg.wasm fi