Skip to content

Commit 88d11e8

Browse files
authored
feat: add persistance for the storage (#65)
1 parent 789ccc8 commit 88d11e8

File tree

7 files changed

+100
-30
lines changed

7 files changed

+100
-30
lines changed

hoddor/src/file_system.rs

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,12 @@
1-
use crate::console::log;
21
use crate::errors::VaultError;
3-
use crate::global::get_global_scope;
2+
use crate::{console::log, global::get_storage_manager};
43
use wasm_bindgen::prelude::*;
54
use wasm_bindgen_futures::JsFuture;
65

7-
use web_sys::{
8-
self, FileSystemDirectoryHandle, FileSystemFileHandle, FileSystemGetFileOptions,
9-
WorkerGlobalScope,
10-
};
6+
use web_sys::{self, FileSystemDirectoryHandle, FileSystemFileHandle, FileSystemGetFileOptions};
117

128
pub async fn get_root_directory_handle() -> Result<FileSystemDirectoryHandle, VaultError> {
13-
let global = get_global_scope()?;
14-
15-
let storage = if let Ok(worker) = global.clone().dyn_into::<WorkerGlobalScope>() {
16-
worker.navigator().storage()
17-
} else if let Ok(window) = global.dyn_into::<web_sys::Window>() {
18-
window.navigator().storage()
19-
} else {
20-
return Err(VaultError::IoError {
21-
message: "Could not access navigator",
22-
});
23-
};
9+
let storage = get_storage_manager()?;
2410

2511
let dir_promise = storage.get_directory();
2612
let dir_handle = JsFuture::from(dir_promise)

hoddor/src/global.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::errors::VaultError;
22
use wasm_bindgen::prelude::JsValue;
33
use wasm_bindgen::prelude::*;
4-
use web_sys::{self, Window, WorkerGlobalScope};
4+
use web_sys::{self, StorageManager, Window, WorkerGlobalScope};
55

66
pub fn get_global_scope() -> Result<JsValue, VaultError> {
77
// Try worker scope first
@@ -22,3 +22,19 @@ pub fn window() -> Window {
2222
.dyn_into::<Window>()
2323
.expect("Unable to retrieve window")
2424
}
25+
26+
pub fn get_storage_manager() -> Result<StorageManager, VaultError> {
27+
let global = get_global_scope()?;
28+
29+
let storage = if let Ok(worker) = global.clone().dyn_into::<WorkerGlobalScope>() {
30+
worker.navigator().storage()
31+
} else if let Ok(window) = global.dyn_into::<web_sys::Window>() {
32+
window.navigator().storage()
33+
} else {
34+
return Err(VaultError::IoError {
35+
message: "Could not access navigator",
36+
});
37+
};
38+
39+
Ok(storage)
40+
}

hoddor/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod file_system;
77
pub mod global;
88
pub mod lock;
99
pub mod measure;
10+
pub mod persistence;
1011
pub mod signaling;
1112
pub mod sync;
1213
pub mod vault;

hoddor/src/persistence.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use std::sync::atomic::{AtomicBool, Ordering};
2+
3+
use wasm_bindgen_futures::JsFuture;
4+
5+
use crate::{errors::VaultError, global::get_storage_manager};
6+
7+
static PERSISTENCE_REQUESTED: AtomicBool = AtomicBool::new(false);
8+
9+
pub fn has_requested_persistence() -> bool {
10+
PERSISTENCE_REQUESTED.load(Ordering::Relaxed)
11+
}
12+
13+
pub fn mark_persistence_requested() {
14+
PERSISTENCE_REQUESTED.store(true, Ordering::Relaxed);
15+
}
16+
17+
pub async fn request_persistence_storage() -> Result<bool, VaultError> {
18+
mark_persistence_requested();
19+
20+
let storage = get_storage_manager()?;
21+
22+
let persist_promise = if let Ok(promise) = storage.persist() {
23+
promise
24+
} else {
25+
return Err(VaultError::JsError(
26+
"Unable to obtain a local storage shelf".to_string(),
27+
));
28+
};
29+
30+
let result = JsFuture::from(persist_promise).await?;
31+
32+
Ok(result.as_bool().unwrap_or(false))
33+
}
34+
35+
pub async fn check_storage_persistence() -> Result<bool, VaultError> {
36+
let storage = get_storage_manager()?;
37+
let persisted_promise = if let Ok(promise) = storage.persisted() {
38+
promise
39+
} else {
40+
return Err(VaultError::JsError(
41+
"Unable to obtain a local storage shelf".to_string(),
42+
));
43+
};
44+
let result = JsFuture::from(persisted_promise).await?;
45+
let is_persisted = result.as_bool().unwrap_or(false);
46+
47+
Ok(is_persisted)
48+
}

hoddor/src/vault.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ use crate::file_system::{
99
use crate::lock::acquire_vault_lock;
1010
use crate::measure::get_performance;
1111
use crate::measure::time_it;
12+
use crate::persistence::{
13+
check_storage_persistence, has_requested_persistence, request_persistence_storage,
14+
};
1215
use crate::sync::{get_sync_manager, OperationType, SyncMessage};
1316
use crate::webrtc::{AccessLevel, WebRtcPeer};
1417
use std::cell::RefCell;
@@ -289,7 +292,7 @@ pub async fn upsert_vault(
289292
operation,
290293
Some(vault.metadata.clone()),
291294
Some(vault.identity_salts.clone()),
292-
Some(vault.username_pk.clone())
295+
Some(vault.username_pk.clone()),
293296
);
294297

295298
let peers = sync_manager.get_peers_mut();
@@ -689,12 +692,9 @@ pub async fn import_vault(vault_name: &str, data: JsValue) -> Result<(), JsValue
689692

690693
pub async fn get_vault(vault_name: &str) -> Result<(FileSystemDirectoryHandle, Vault), JsValue> {
691694
let dirname = get_vault_dirname(vault_name);
692-
read_vault_with_name(&dirname).await.map_err(|_| {
693-
JsValue::from_str(&format!(
694-
"Vault '{}' does not exist",
695-
vault_name
696-
))
697-
})
695+
read_vault_with_name(&dirname)
696+
.await
697+
.map_err(|_| JsValue::from_str(&format!("Vault '{}' does not exist", vault_name)))
698698
}
699699

700700
pub async fn read_vault_with_name(
@@ -836,6 +836,24 @@ pub async fn save_vault(
836836
dir_handle: &FileSystemDirectoryHandle,
837837
vault: Vault,
838838
) -> Result<(), VaultError> {
839+
if !has_requested_persistence() {
840+
let is_persisted = check_storage_persistence().await.unwrap_or(false);
841+
842+
if !is_persisted {
843+
let result = request_persistence_storage().await;
844+
845+
match result {
846+
Ok(is_granted) => {
847+
console::log(&format!("persistence request granted: {}", is_granted));
848+
}
849+
Err(VaultError::JsError(message)) => {
850+
console::error(&message);
851+
}
852+
_ => {}
853+
}
854+
}
855+
}
856+
839857
let mut namespace_data = Vec::new();
840858
for (namespace, data) in &vault.namespaces {
841859
let namespace_json = serde_json::to_string(&data).map_err(|_| VaultError::IoError {
@@ -1316,7 +1334,7 @@ pub async fn update_vault_from_sync(vault_name: &str, vault_data: &[u8]) -> Resu
13161334
.unwrap_or_else(IdentitySalts::new),
13171335
username_pk: match sync_msg.username_pk {
13181336
Some(username_pk) => username_pk,
1319-
None => HashMap::new()
1337+
None => HashMap::new(),
13201338
},
13211339
namespaces: HashMap::new(),
13221340
sync_enabled: true,

playground/src/components/VaultsActions.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Upload, { RcFile } from 'antd/es/upload';
33
import { useState } from 'react';
44
import { useDispatch, useSelector } from 'react-redux';
55

6+
import { create_vault } from '../../../hoddor/pkg/hoddor';
67
import { actions } from './../store/app.actions';
78
import { appSelectors } from './../store/app.selectors';
89
import { VaultWorker } from './../vault';
@@ -21,7 +22,7 @@ export const VaultsActions = () => {
2122
const [isModalOpen, setIsModalOpen] = useState(false);
2223

2324
const handleCreation = async (value: FieldType) => {
24-
await vaultWorker.createVault(value.vaultName || 'default');
25+
await create_vault(value.vaultName || 'default');
2526
dispatch(actions.setVaults(await vaultWorker.listVaults()));
2627

2728
messageApi.success(`Vault ${value.vaultName} created.`);
@@ -61,7 +62,7 @@ export const VaultsActions = () => {
6162
);
6263

6364
dispatch(actions.setVaults(await vaultWorker.listVaults()));
64-
65+
6566
messageApi.success(`Vault ${vaultName} imported.`);
6667
} catch (error) {
6768
messageApi.error(`Failed to import vault ${vaultName}: ${error}`);

playground/src/components/VaultsMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Menu } from 'antd';
22
import { useEffect } from 'react';
33
import { useDispatch, useSelector } from 'react-redux';
44

5+
import { VaultWorker } from '../vault';
56
import { actions } from './../store/app.actions';
67
import { appSelectors } from './../store/app.selectors';
7-
import { VaultWorker } from '../vault';
88

99
const vaultWorker = new VaultWorker();
1010

@@ -20,7 +20,7 @@ export const VaultsMenu = () => {
2020
if (!vaults.length) {
2121
getVaultsList();
2222
}
23-
}, [vaults]);
23+
}, [vaults.length]);
2424

2525
return (
2626
!!vaults.length && (

0 commit comments

Comments
 (0)