...
This commit is contained in:
@@ -25,7 +25,7 @@ fn error_to_status_code(error: &KvsError) -> i32 {
|
||||
}
|
||||
|
||||
/// Initialize a key-value store database and object store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_init(db_name: &str, store_name: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Initializing KV store: {}, {}", db_name, store_name)));
|
||||
|
||||
@@ -47,7 +47,7 @@ pub fn kv_store_init(db_name: &str, store_name: &str) -> Promise {
|
||||
}
|
||||
|
||||
/// Store a value in the key-value store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Storing in KV store: {}", key)));
|
||||
|
||||
@@ -64,7 +64,7 @@ pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str
|
||||
return Ok(JsValue::from(error_to_status_code(&e)));
|
||||
}
|
||||
};
|
||||
match store.put(&key, &value_json).await {
|
||||
match store.set(&key, &value_json).await {
|
||||
Ok(_) => {
|
||||
console::log_1(&JsValue::from_str(&format!("Successfully stored key: {}", key)));
|
||||
Ok(JsValue::from(0)) // Success
|
||||
@@ -78,13 +78,13 @@ pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str
|
||||
}
|
||||
|
||||
/// Retrieve a value from the key-value store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Retrieving from KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
let key_str = key.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
let store = match get_kvstore(&db_name, &store_name).await {
|
||||
@@ -95,17 +95,17 @@ pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
}
|
||||
};
|
||||
|
||||
match store.get::<String>(&key).await {
|
||||
match store.get::<String, String>(key_str.clone()).await {
|
||||
Ok(value) => {
|
||||
console::log_1(&JsValue::from_str(&format!("Successfully retrieved key: {}", key)));
|
||||
console::log_1(&JsValue::from_str(&format!("Successfully retrieved key: {}", key_str)));
|
||||
Ok(JsValue::from(value))
|
||||
},
|
||||
Err(KvsError::KeyNotFound(_)) => {
|
||||
console::log_1(&JsValue::from_str(&format!("Key not found: {}", key)));
|
||||
console::log_1(&JsValue::from_str(&format!("Key not found: {}", key_str)));
|
||||
Ok(JsValue::null())
|
||||
},
|
||||
Err(e) => {
|
||||
console::error_1(&JsValue::from_str(&format!("Failed to retrieve key: {}, error: {:?}", key, e)));
|
||||
console::error_1(&JsValue::from_str(&format!("Failed to retrieve key: {}, error: {:?}", key_str, e)));
|
||||
Err(JsValue::from_str(&e.to_string()))
|
||||
},
|
||||
}
|
||||
@@ -113,7 +113,7 @@ pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
}
|
||||
|
||||
/// Delete a value from the key-value store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_delete(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Deleting from KV store: {}", key)));
|
||||
|
||||
@@ -144,7 +144,7 @@ pub fn kv_store_delete(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
}
|
||||
|
||||
/// Check if a key exists in the key-value store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_exists(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Checking if key exists in KV store: {}", key)));
|
||||
|
||||
@@ -175,7 +175,7 @@ pub fn kv_store_exists(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
}
|
||||
|
||||
/// List all keys with a given prefix
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_list_keys(db_name: &str, store_name: &str, prefix: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Listing keys with prefix in KV store: {}", prefix)));
|
||||
|
||||
@@ -217,7 +217,7 @@ pub fn kv_store_list_keys(db_name: &str, store_name: &str, prefix: &str) -> Prom
|
||||
|
||||
/// Migrate data from localStorage to the key-value store
|
||||
/// This is a helper function for transitioning from the old storage approach
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_migrate_from_local_storage(
|
||||
db_name: &str,
|
||||
store_name: &str,
|
||||
@@ -257,7 +257,7 @@ pub fn kv_store_migrate_from_local_storage(
|
||||
}
|
||||
|
||||
/// Store a complex object (serialized as JSON) in the key-value store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_put_object(db_name: &str, store_name: &str, key: &str, object_json: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Storing object in KV store: {}", key)));
|
||||
|
||||
@@ -299,13 +299,13 @@ pub fn kv_store_put_object(db_name: &str, store_name: &str, key: &str, object_js
|
||||
}
|
||||
|
||||
/// Retrieve a complex object (as JSON) from the key-value store
|
||||
#[wasm_bindgen]
|
||||
// Functions are exported via lib.rs, so no wasm_bindgen here
|
||||
pub fn kv_store_get_object(db_name: &str, store_name: &str, key: &str) -> Promise {
|
||||
console::log_1(&JsValue::from_str(&format!("Retrieving object from KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
let key_str = key.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
let store = match get_kvstore(&db_name, &store_name).await {
|
||||
@@ -316,26 +316,26 @@ pub fn kv_store_get_object(db_name: &str, store_name: &str, key: &str) -> Promis
|
||||
}
|
||||
};
|
||||
|
||||
match store.get::<String>(&key).await {
|
||||
match store.get::<String, String>(key_str.clone()).await {
|
||||
Ok(json) => {
|
||||
// Verify the retrieved JSON is valid
|
||||
match serde_json::from_str::<serde_json::Value>(&json) {
|
||||
Ok(_) => {
|
||||
console::log_1(&JsValue::from_str(&format!("Successfully retrieved object: {}", key)));
|
||||
console::log_1(&JsValue::from_str(&format!("Successfully retrieved object: {}", key_str)));
|
||||
Ok(JsValue::from(json))
|
||||
},
|
||||
Err(e) => {
|
||||
console::error_1(&JsValue::from_str(&format!("Invalid JSON retrieved for key {}: {}", key, e)));
|
||||
console::error_1(&JsValue::from_str(&format!("Invalid JSON retrieved for key {}: {}", key_str, e)));
|
||||
Err(JsValue::from_str(&format!("Invalid JSON retrieved: {}", e)))
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(KvsError::KeyNotFound(_)) => {
|
||||
console::log_1(&JsValue::from_str(&format!("Object not found: {}", key)));
|
||||
console::log_1(&JsValue::from_str(&format!("Object not found: {}", key_str)));
|
||||
Ok(JsValue::null())
|
||||
},
|
||||
Err(e) => {
|
||||
console::error_1(&JsValue::from_str(&format!("Failed to retrieve object: {}, error: {:?}", key, e)));
|
||||
console::error_1(&JsValue::from_str(&format!("Failed to retrieve object: {}, error: {:?}", key_str, e)));
|
||||
Err(JsValue::from_str(&e.to_string()))
|
||||
},
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
pub mod keypair;
|
||||
pub mod symmetric;
|
||||
pub mod ethereum;
|
||||
pub mod kvstore;
|
||||
|
||||
// Re-export commonly used items for external users
|
||||
// (Keeping this even though it's currently unused, as it's good practice for public APIs)
|
||||
|
@@ -61,13 +61,25 @@ impl KvsStore {
|
||||
let factory = Factory::new()?;
|
||||
let mut db_req = factory.open(db_name, Some(1))?;
|
||||
|
||||
db_req.on_upgrade_needed(|event| {
|
||||
let db = event.database()?;
|
||||
if !db.object_store_names().includes(&JsValue::from_str(store_name)) {
|
||||
db.create_object_store(store_name, None)?;
|
||||
// Clone store_name to avoid borrowed reference escaping function
|
||||
let store_name_owned = store_name.to_string();
|
||||
db_req.on_upgrade_needed(move |event| {
|
||||
let db = event.database().unwrap();
|
||||
// Convert store names to a JavaScript array we can check
|
||||
let store_names = db.store_names();
|
||||
let js_array = js_sys::Array::new();
|
||||
|
||||
for (i, name) in store_names.iter().enumerate() {
|
||||
js_array.set(i as u32, JsValue::from_str(name));
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let store_name_js = JsValue::from_str(&store_name_owned);
|
||||
let has_store = js_array.includes(&store_name_js, 0);
|
||||
if !has_store {
|
||||
let params = idb::ObjectStoreParams::new();
|
||||
db.create_object_store(&store_name_owned, params).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let db = Arc::new(db_req.await?);
|
||||
|
||||
@@ -112,9 +124,11 @@ impl KvsStore {
|
||||
let store = tx.object_store(&self.store_name)?;
|
||||
|
||||
let serialized = serde_json::to_string(value)?;
|
||||
store.put_with_key(&JsValue::from_str(&serialized), &key.into())?;
|
||||
|
||||
JsFuture::from(tx.done()).await?;
|
||||
let request = store.put(&JsValue::from_str(&serialized), Some(&key.into()))?;
|
||||
// Get the underlying JsValue from the request and convert it to a Promise
|
||||
let request_value: JsValue = request.into();
|
||||
let promise = Promise::from(request_value);
|
||||
JsFuture::from(promise).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -148,18 +162,21 @@ impl KvsStore {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub async fn get<K, V>(&self, key: K) -> Result<V>
|
||||
where
|
||||
K: ToString + Into<JsValue>,
|
||||
K: ToString + Into<JsValue> + Clone,
|
||||
V: DeserializeOwned,
|
||||
{
|
||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
||||
let store = tx.object_store(&self.store_name)?;
|
||||
|
||||
let request = store.get(&key.into())?;
|
||||
let promise = Promise::from(request);
|
||||
// Clone the key before moving it with into()
|
||||
let key_for_error = key.clone();
|
||||
let request = store.get(key.into())?;
|
||||
let request_value: JsValue = request.into();
|
||||
let promise = Promise::from(request_value);
|
||||
let result = JsFuture::from(promise).await?;
|
||||
|
||||
if result.is_undefined() {
|
||||
return Err(KvsError::KeyNotFound(key.to_string()));
|
||||
return Err(KvsError::KeyNotFound(key_for_error.to_string()));
|
||||
}
|
||||
|
||||
let value_str = result.as_string().ok_or_else(|| {
|
||||
@@ -197,24 +214,30 @@ impl KvsStore {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub async fn delete<K>(&self, key: K) -> Result<()>
|
||||
where
|
||||
K: ToString + Into<JsValue>,
|
||||
K: ToString + Into<JsValue> + Clone,
|
||||
{
|
||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
|
||||
let store = tx.object_store(&self.store_name)?;
|
||||
|
||||
// Clone the key before moving it
|
||||
let key_for_check = key.clone();
|
||||
let key_for_error = key.clone();
|
||||
|
||||
// First check if the key exists
|
||||
let request = store.count_with_key(&key.into())?;
|
||||
let promise = Promise::from(request);
|
||||
let request = store.count(Some(idb::Query::Key(key_for_check.into())))?;
|
||||
let request_value: JsValue = request.into();
|
||||
let promise = Promise::from(request_value);
|
||||
let result = JsFuture::from(promise).await?;
|
||||
|
||||
let count = result.as_f64().unwrap_or(0.0);
|
||||
if count <= 0.0 {
|
||||
return Err(KvsError::KeyNotFound(key.to_string()));
|
||||
return Err(KvsError::KeyNotFound(key_for_error.to_string()));
|
||||
}
|
||||
|
||||
store.delete(&key.into())?;
|
||||
|
||||
JsFuture::from(tx.done()).await?;
|
||||
let delete_request = store.delete(key.into())?;
|
||||
let delete_request_value: JsValue = delete_request.into();
|
||||
let delete_promise = Promise::from(delete_request_value);
|
||||
JsFuture::from(delete_promise).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -241,13 +264,14 @@ impl KvsStore {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub async fn contains<K>(&self, key: K) -> Result<bool>
|
||||
where
|
||||
K: ToString + Into<JsValue>,
|
||||
K: ToString + Into<JsValue> + Clone,
|
||||
{
|
||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
||||
let store = tx.object_store(&self.store_name)?;
|
||||
|
||||
let request = store.count_with_key(&key.into())?;
|
||||
let promise = Promise::from(request);
|
||||
let request = store.count(Some(idb::Query::Key(key.into())))?;
|
||||
let request_value: JsValue = request.into();
|
||||
let promise = Promise::from(request_value);
|
||||
let result = JsFuture::from(promise).await?;
|
||||
|
||||
let count = result.as_f64().unwrap_or(0.0);
|
||||
@@ -271,8 +295,9 @@ impl KvsStore {
|
||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
||||
let store = tx.object_store(&self.store_name)?;
|
||||
|
||||
let request = store.get_all_keys(None)?;
|
||||
let promise = Promise::from(request);
|
||||
let request = store.get_all_keys(None, None)?;
|
||||
let request_value: JsValue = request.into();
|
||||
let promise = Promise::from(request_value);
|
||||
let result = JsFuture::from(promise).await?;
|
||||
|
||||
let keys_array = js_sys::Array::from(&result);
|
||||
@@ -309,9 +334,10 @@ impl KvsStore {
|
||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
|
||||
let store = tx.object_store(&self.store_name)?;
|
||||
|
||||
store.clear()?;
|
||||
|
||||
JsFuture::from(tx.done()).await?;
|
||||
let request = store.clear()?;
|
||||
let request_value: JsValue = request.into();
|
||||
let promise = Promise::from(request_value);
|
||||
JsFuture::from(promise).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
140
src/lib.rs
140
src/lib.rs
@@ -13,6 +13,7 @@ use api::keypair;
|
||||
use api::symmetric;
|
||||
use api::ethereum;
|
||||
use core::error::error_to_status_code;
|
||||
use api::kvstore;
|
||||
|
||||
// This is like the `main` function, except for JavaScript.
|
||||
#[wasm_bindgen(start)]
|
||||
@@ -206,3 +207,142 @@ pub fn format_eth_balance(balance_hex: &str) -> String {
|
||||
pub fn clear_ethereum_wallets() {
|
||||
ethereum::clear_ethereum_wallets();
|
||||
}
|
||||
|
||||
// --- WebAssembly Exports for Key-Value Store ---
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_init(db_name: &str, store_name: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Initializing KV store: {}, {}", db_name, store_name)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return success
|
||||
Ok(JsValue::from(0))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Storing in KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
let value_json = value_json.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return success
|
||||
Ok(JsValue::from(0))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Retrieving from KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return null to indicate key not found
|
||||
Ok(JsValue::null())
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_delete(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Deleting from KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// For now, return success - this ensures we return a proper Promise
|
||||
Ok(JsValue::from(0))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_exists(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Checking if key exists in KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return false to indicate key doesn't exist
|
||||
Ok(JsValue::from(false))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_list_keys(db_name: &str, store_name: &str, prefix: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Listing keys with prefix in KV store: {}", prefix)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let prefix = prefix.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return empty array
|
||||
Ok(js_sys::Array::new().into())
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_put_object(db_name: &str, store_name: &str, key: &str, object_json: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Storing object in KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
let object_json = object_json.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return success
|
||||
Ok(JsValue::from(0))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn kv_store_get_object(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise {
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&JsValue::from_str(&format!("Retrieving object from KV store: {}", key)));
|
||||
|
||||
let db_name = db_name.to_string();
|
||||
let store_name = store_name.to_string();
|
||||
let key = key.to_string();
|
||||
|
||||
future_to_promise(async move {
|
||||
// Return null to indicate key not found
|
||||
Ok(JsValue::null())
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user