...
This commit is contained in:
parent
3e49f48f60
commit
bae1fb93cb
@ -25,7 +25,7 @@ fn error_to_status_code(error: &KvsError) -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a key-value store database and object store
|
/// 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 {
|
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)));
|
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
|
/// 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 {
|
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)));
|
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)));
|
return Ok(JsValue::from(error_to_status_code(&e)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match store.put(&key, &value_json).await {
|
match store.set(&key, &value_json).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
console::log_1(&JsValue::from_str(&format!("Successfully stored key: {}", key)));
|
console::log_1(&JsValue::from_str(&format!("Successfully stored key: {}", key)));
|
||||||
Ok(JsValue::from(0)) // Success
|
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
|
/// 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 {
|
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)));
|
console::log_1(&JsValue::from_str(&format!("Retrieving from KV store: {}", key)));
|
||||||
|
|
||||||
let db_name = db_name.to_string();
|
let db_name = db_name.to_string();
|
||||||
let store_name = store_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 {
|
future_to_promise(async move {
|
||||||
let store = match get_kvstore(&db_name, &store_name).await {
|
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) => {
|
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))
|
Ok(JsValue::from(value))
|
||||||
},
|
},
|
||||||
Err(KvsError::KeyNotFound(_)) => {
|
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())
|
Ok(JsValue::null())
|
||||||
},
|
},
|
||||||
Err(e) => {
|
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()))
|
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
|
/// 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 {
|
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)));
|
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
|
/// 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 {
|
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)));
|
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
|
/// 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 {
|
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)));
|
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
|
/// Migrate data from localStorage to the key-value store
|
||||||
/// This is a helper function for transitioning from the old storage approach
|
/// 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(
|
pub fn kv_store_migrate_from_local_storage(
|
||||||
db_name: &str,
|
db_name: &str,
|
||||||
store_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
|
/// 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 {
|
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)));
|
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
|
/// 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 {
|
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)));
|
console::log_1(&JsValue::from_str(&format!("Retrieving object from KV store: {}", key)));
|
||||||
|
|
||||||
let db_name = db_name.to_string();
|
let db_name = db_name.to_string();
|
||||||
let store_name = store_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 {
|
future_to_promise(async move {
|
||||||
let store = match get_kvstore(&db_name, &store_name).await {
|
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) => {
|
Ok(json) => {
|
||||||
// Verify the retrieved JSON is valid
|
// Verify the retrieved JSON is valid
|
||||||
match serde_json::from_str::<serde_json::Value>(&json) {
|
match serde_json::from_str::<serde_json::Value>(&json) {
|
||||||
Ok(_) => {
|
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))
|
Ok(JsValue::from(json))
|
||||||
},
|
},
|
||||||
Err(e) => {
|
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(JsValue::from_str(&format!("Invalid JSON retrieved: {}", e)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(KvsError::KeyNotFound(_)) => {
|
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())
|
Ok(JsValue::null())
|
||||||
},
|
},
|
||||||
Err(e) => {
|
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()))
|
Err(JsValue::from_str(&e.to_string()))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
pub mod keypair;
|
pub mod keypair;
|
||||||
pub mod symmetric;
|
pub mod symmetric;
|
||||||
pub mod ethereum;
|
pub mod ethereum;
|
||||||
|
pub mod kvstore;
|
||||||
|
|
||||||
// Re-export commonly used items for external users
|
// Re-export commonly used items for external users
|
||||||
// (Keeping this even though it's currently unused, as it's good practice for public APIs)
|
// (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 factory = Factory::new()?;
|
||||||
let mut db_req = factory.open(db_name, Some(1))?;
|
let mut db_req = factory.open(db_name, Some(1))?;
|
||||||
|
|
||||||
db_req.on_upgrade_needed(|event| {
|
// Clone store_name to avoid borrowed reference escaping function
|
||||||
let db = event.database()?;
|
let store_name_owned = store_name.to_string();
|
||||||
if !db.object_store_names().includes(&JsValue::from_str(store_name)) {
|
db_req.on_upgrade_needed(move |event| {
|
||||||
db.create_object_store(store_name, None)?;
|
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?);
|
let db = Arc::new(db_req.await?);
|
||||||
|
|
||||||
@ -112,9 +124,11 @@ impl KvsStore {
|
|||||||
let store = tx.object_store(&self.store_name)?;
|
let store = tx.object_store(&self.store_name)?;
|
||||||
|
|
||||||
let serialized = serde_json::to_string(value)?;
|
let serialized = serde_json::to_string(value)?;
|
||||||
store.put_with_key(&JsValue::from_str(&serialized), &key.into())?;
|
let request = store.put(&JsValue::from_str(&serialized), Some(&key.into()))?;
|
||||||
|
// Get the underlying JsValue from the request and convert it to a Promise
|
||||||
JsFuture::from(tx.done()).await?;
|
let request_value: JsValue = request.into();
|
||||||
|
let promise = Promise::from(request_value);
|
||||||
|
JsFuture::from(promise).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,18 +162,21 @@ impl KvsStore {
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub async fn get<K, V>(&self, key: K) -> Result<V>
|
pub async fn get<K, V>(&self, key: K) -> Result<V>
|
||||||
where
|
where
|
||||||
K: ToString + Into<JsValue>,
|
K: ToString + Into<JsValue> + Clone,
|
||||||
V: DeserializeOwned,
|
V: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
||||||
let store = tx.object_store(&self.store_name)?;
|
let store = tx.object_store(&self.store_name)?;
|
||||||
|
|
||||||
let request = store.get(&key.into())?;
|
// Clone the key before moving it with into()
|
||||||
let promise = Promise::from(request);
|
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?;
|
let result = JsFuture::from(promise).await?;
|
||||||
|
|
||||||
if result.is_undefined() {
|
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(|| {
|
let value_str = result.as_string().ok_or_else(|| {
|
||||||
@ -197,24 +214,30 @@ impl KvsStore {
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub async fn delete<K>(&self, key: K) -> Result<()>
|
pub async fn delete<K>(&self, key: K) -> Result<()>
|
||||||
where
|
where
|
||||||
K: ToString + Into<JsValue>,
|
K: ToString + Into<JsValue> + Clone,
|
||||||
{
|
{
|
||||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
|
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
|
||||||
let store = tx.object_store(&self.store_name)?;
|
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
|
// First check if the key exists
|
||||||
let request = store.count_with_key(&key.into())?;
|
let request = store.count(Some(idb::Query::Key(key_for_check.into())))?;
|
||||||
let promise = Promise::from(request);
|
let request_value: JsValue = request.into();
|
||||||
|
let promise = Promise::from(request_value);
|
||||||
let result = JsFuture::from(promise).await?;
|
let result = JsFuture::from(promise).await?;
|
||||||
|
|
||||||
let count = result.as_f64().unwrap_or(0.0);
|
let count = result.as_f64().unwrap_or(0.0);
|
||||||
if count <= 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())?;
|
let delete_request = store.delete(key.into())?;
|
||||||
|
let delete_request_value: JsValue = delete_request.into();
|
||||||
JsFuture::from(tx.done()).await?;
|
let delete_promise = Promise::from(delete_request_value);
|
||||||
|
JsFuture::from(delete_promise).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,13 +264,14 @@ impl KvsStore {
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub async fn contains<K>(&self, key: K) -> Result<bool>
|
pub async fn contains<K>(&self, key: K) -> Result<bool>
|
||||||
where
|
where
|
||||||
K: ToString + Into<JsValue>,
|
K: ToString + Into<JsValue> + Clone,
|
||||||
{
|
{
|
||||||
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
||||||
let store = tx.object_store(&self.store_name)?;
|
let store = tx.object_store(&self.store_name)?;
|
||||||
|
|
||||||
let request = store.count_with_key(&key.into())?;
|
let request = store.count(Some(idb::Query::Key(key.into())))?;
|
||||||
let promise = Promise::from(request);
|
let request_value: JsValue = request.into();
|
||||||
|
let promise = Promise::from(request_value);
|
||||||
let result = JsFuture::from(promise).await?;
|
let result = JsFuture::from(promise).await?;
|
||||||
|
|
||||||
let count = result.as_f64().unwrap_or(0.0);
|
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 tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
|
||||||
let store = tx.object_store(&self.store_name)?;
|
let store = tx.object_store(&self.store_name)?;
|
||||||
|
|
||||||
let request = store.get_all_keys(None)?;
|
let request = store.get_all_keys(None, None)?;
|
||||||
let promise = Promise::from(request);
|
let request_value: JsValue = request.into();
|
||||||
|
let promise = Promise::from(request_value);
|
||||||
let result = JsFuture::from(promise).await?;
|
let result = JsFuture::from(promise).await?;
|
||||||
|
|
||||||
let keys_array = js_sys::Array::from(&result);
|
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 tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
|
||||||
let store = tx.object_store(&self.store_name)?;
|
let store = tx.object_store(&self.store_name)?;
|
||||||
|
|
||||||
store.clear()?;
|
let request = store.clear()?;
|
||||||
|
let request_value: JsValue = request.into();
|
||||||
JsFuture::from(tx.done()).await?;
|
let promise = Promise::from(request_value);
|
||||||
|
JsFuture::from(promise).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
140
src/lib.rs
140
src/lib.rs
@ -13,6 +13,7 @@ use api::keypair;
|
|||||||
use api::symmetric;
|
use api::symmetric;
|
||||||
use api::ethereum;
|
use api::ethereum;
|
||||||
use core::error::error_to_status_code;
|
use core::error::error_to_status_code;
|
||||||
|
use api::kvstore;
|
||||||
|
|
||||||
// This is like the `main` function, except for JavaScript.
|
// This is like the `main` function, except for JavaScript.
|
||||||
#[wasm_bindgen(start)]
|
#[wasm_bindgen(start)]
|
||||||
@ -206,3 +207,142 @@ pub fn format_eth_balance(balance_hex: &str) -> String {
|
|||||||
pub fn clear_ethereum_wallets() {
|
pub fn clear_ethereum_wallets() {
|
||||||
ethereum::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())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
311
www/debug.html
Normal file
311
www/debug.html
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>IndexedDB Inspector</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
h1, h2, h3 {
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px;
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 15px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 4px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: #e74c3c;
|
||||||
|
background-color: #fceaea;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
tr:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>IndexedDB Inspector</h1>
|
||||||
|
|
||||||
|
<h2>Database Information</h2>
|
||||||
|
<div>
|
||||||
|
<p>Database Name: <strong>CryptoSpaceDB</strong></p>
|
||||||
|
<p>Store Name: <strong>keySpaces</strong></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Actions</h2>
|
||||||
|
<div>
|
||||||
|
<button id="list-dbs">List All Databases</button>
|
||||||
|
<button id="open-db">Open CryptoSpaceDB</button>
|
||||||
|
<button id="list-stores">List Object Stores</button>
|
||||||
|
<button id="list-keys">List All Keys</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Result</h2>
|
||||||
|
<div id="result-area">
|
||||||
|
<pre id="result">Results will appear here...</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Key-Value Viewer</h2>
|
||||||
|
<div id="kv-viewer">
|
||||||
|
<table id="kv-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Key</th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="kv-body">
|
||||||
|
<!-- Data will be populated here -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Utility function to display results
|
||||||
|
function displayResult(data) {
|
||||||
|
const resultElement = document.getElementById('result');
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
resultElement.textContent = JSON.stringify(data, null, 2);
|
||||||
|
} else {
|
||||||
|
resultElement.textContent = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to display error
|
||||||
|
function displayError(error) {
|
||||||
|
const resultElement = document.getElementById('result');
|
||||||
|
resultElement.textContent = `ERROR: ${error.message || error}`;
|
||||||
|
resultElement.classList.add('error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all available databases
|
||||||
|
document.getElementById('list-dbs').addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
if (!window.indexedDB) {
|
||||||
|
throw new Error("Your browser doesn't support IndexedDB");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!indexedDB.databases) {
|
||||||
|
displayResult("Your browser doesn't support indexedDB.databases() method. Try opening the database directly.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const databases = await indexedDB.databases();
|
||||||
|
displayResult(databases);
|
||||||
|
} catch (error) {
|
||||||
|
displayError(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open the CryptoSpaceDB database
|
||||||
|
let db = null;
|
||||||
|
document.getElementById('open-db').addEventListener('click', () => {
|
||||||
|
try {
|
||||||
|
if (!window.indexedDB) {
|
||||||
|
throw new Error("Your browser doesn't support IndexedDB");
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbName = "CryptoSpaceDB";
|
||||||
|
const request = indexedDB.open(dbName);
|
||||||
|
|
||||||
|
request.onerror = (event) => {
|
||||||
|
displayError(`Failed to open database: ${event.target.error}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onsuccess = (event) => {
|
||||||
|
db = event.target.result;
|
||||||
|
displayResult(`Successfully opened database: ${db.name}, version ${db.version}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onupgradeneeded = (event) => {
|
||||||
|
db = event.target.result;
|
||||||
|
displayResult(`Database ${db.name} upgrade needed, creating object store: keySpaces`);
|
||||||
|
|
||||||
|
// Create object store if it doesn't exist (shouldn't happen for existing DBs)
|
||||||
|
if (!db.objectStoreNames.contains("keySpaces")) {
|
||||||
|
db.createObjectStore("keySpaces");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
displayError(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// List all object stores in the database
|
||||||
|
document.getElementById('list-stores').addEventListener('click', () => {
|
||||||
|
try {
|
||||||
|
if (!db) {
|
||||||
|
throw new Error("Database not opened. Click 'Open CryptoSpaceDB' first.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeNames = Array.from(db.objectStoreNames);
|
||||||
|
displayResult(storeNames);
|
||||||
|
} catch (error) {
|
||||||
|
displayError(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// List all keys in the keySpaces store
|
||||||
|
document.getElementById('list-keys').addEventListener('click', () => {
|
||||||
|
try {
|
||||||
|
if (!db) {
|
||||||
|
throw new Error("Database not opened. Click 'Open CryptoSpaceDB' first.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!db.objectStoreNames.contains("keySpaces")) {
|
||||||
|
throw new Error("Object store 'keySpaces' doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
const transaction = db.transaction(["keySpaces"], "readonly");
|
||||||
|
const store = transaction.objectStore("keySpaces");
|
||||||
|
const request = store.getAllKeys();
|
||||||
|
|
||||||
|
request.onerror = (event) => {
|
||||||
|
displayError(`Failed to get keys: ${event.target.error}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onsuccess = (event) => {
|
||||||
|
const keys = event.target.result;
|
||||||
|
displayResult(keys);
|
||||||
|
|
||||||
|
// Now get all the values for these keys
|
||||||
|
const transaction = db.transaction(["keySpaces"], "readonly");
|
||||||
|
const store = transaction.objectStore("keySpaces");
|
||||||
|
const keyValuePairs = [];
|
||||||
|
|
||||||
|
// Clear the table
|
||||||
|
const tableBody = document.getElementById('kv-body');
|
||||||
|
tableBody.innerHTML = '';
|
||||||
|
|
||||||
|
// For each key, get its value
|
||||||
|
let pendingRequests = keys.length;
|
||||||
|
|
||||||
|
if (keys.length === 0) {
|
||||||
|
const row = tableBody.insertRow();
|
||||||
|
const cell = row.insertCell(0);
|
||||||
|
cell.colSpan = 3;
|
||||||
|
cell.textContent = "No data found in the database";
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.forEach(key => {
|
||||||
|
const request = store.get(key);
|
||||||
|
|
||||||
|
request.onerror = (event) => {
|
||||||
|
displayError(`Failed to get value for key ${key}: ${event.target.error}`);
|
||||||
|
pendingRequests--;
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onsuccess = (event) => {
|
||||||
|
const value = event.target.result;
|
||||||
|
keyValuePairs.push({ key, value });
|
||||||
|
|
||||||
|
// Add a row to the table
|
||||||
|
const row = tableBody.insertRow();
|
||||||
|
|
||||||
|
// Key cell
|
||||||
|
const keyCell = row.insertCell(0);
|
||||||
|
keyCell.textContent = key;
|
||||||
|
|
||||||
|
// Value cell (truncated for display)
|
||||||
|
const valueCell = row.insertCell(1);
|
||||||
|
try {
|
||||||
|
// Try to parse JSON for better display
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
const parsedValue = JSON.parse(value);
|
||||||
|
valueCell.innerHTML = `<pre>${JSON.stringify(parsedValue, null, 2).substring(0, 100)}${parsedValue.length > 100 ? '...' : ''}</pre>`;
|
||||||
|
} else {
|
||||||
|
valueCell.innerHTML = `<pre>${JSON.stringify(value, null, 2).substring(0, 100)}${value.length > 100 ? '...' : ''}</pre>`;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// If not JSON, display as string with truncation
|
||||||
|
valueCell.textContent = typeof value === 'string' ?
|
||||||
|
`${value.substring(0, 100)}${value.length > 100 ? '...' : ''}` :
|
||||||
|
String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions cell
|
||||||
|
const actionsCell = row.insertCell(2);
|
||||||
|
const viewButton = document.createElement('button');
|
||||||
|
viewButton.textContent = 'View Full';
|
||||||
|
viewButton.addEventListener('click', () => {
|
||||||
|
const valueStr = typeof value === 'object' ?
|
||||||
|
JSON.stringify(value, null, 2) : String(value);
|
||||||
|
displayResult({ key, value: valueStr });
|
||||||
|
});
|
||||||
|
actionsCell.appendChild(viewButton);
|
||||||
|
|
||||||
|
pendingRequests--;
|
||||||
|
if (pendingRequests === 0) {
|
||||||
|
// All requests completed
|
||||||
|
console.log("All key-value pairs retrieved:", keyValuePairs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
displayError(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize by checking if IndexedDB is available
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
if (!window.indexedDB) {
|
||||||
|
displayError("Your browser doesn't support IndexedDB");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user