ic_auth_client/storage/
async_storage.rs1use super::{StorageError, StoredKey};
6use futures::future::BoxFuture;
7use web_sys::Storage;
8
9const LOCAL_STORAGE_PREFIX: &str = "ic-";
10
11#[derive(Debug, Default, Clone, Copy)]
13pub struct LocalStorage;
14
15impl LocalStorage {
16 pub fn new() -> Self {
18 Self
19 }
20
21 fn get_local_storage(&self) -> Option<Storage> {
22 match gloo_utils::window().local_storage() {
23 Ok(storage) => storage,
24 Err(_e) => {
25 #[cfg(feature = "tracing")]
26 error!("Could not find local storage: {_e:?}");
27 None
28 }
29 }
30 }
31}
32
33impl AuthClientStorage for LocalStorage {
34 fn get<'a>(
35 &'a mut self,
36 key: &'a str,
37 ) -> BoxFuture<'a, Result<Option<StoredKey>, StorageError>> {
38 Box::pin(async move {
39 let local_storage = self
40 .get_local_storage()
41 .ok_or_else(|| StorageError::WebSys("LocalStorage not available".to_string()))?;
42 let key = format!("{}{}", LOCAL_STORAGE_PREFIX, key);
43 let value = local_storage.get_item(&key)?;
44 Ok(value.map(StoredKey::String))
45 })
46 }
47
48 fn set<'a>(
49 &'a mut self,
50 key: &'a str,
51 value: StoredKey,
52 ) -> BoxFuture<'a, Result<(), StorageError>> {
53 Box::pin(async move {
54 let local_storage = self
55 .get_local_storage()
56 .ok_or_else(|| StorageError::WebSys("LocalStorage not available".to_string()))?;
57 let key = format!("{}{}", LOCAL_STORAGE_PREFIX, key);
58 let value = value.encode();
59 local_storage.set_item(&key, value.as_ref())?;
60 Ok(())
61 })
62 }
63
64 fn remove<'a>(&'a mut self, key: &'a str) -> BoxFuture<'a, Result<(), StorageError>> {
65 Box::pin(async move {
66 let local_storage = self
67 .get_local_storage()
68 .ok_or_else(|| StorageError::WebSys("LocalStorage not available".to_string()))?;
69 let key = format!("{}{}", LOCAL_STORAGE_PREFIX, key);
70 local_storage.remove_item(&key)?;
71 Ok(())
72 })
73 }
74}
75
76impl From<LocalStorage> for Box<dyn AuthClientStorage> {
77 fn from(storage: LocalStorage) -> Self {
78 Box::new(storage)
79 }
80}
81
82pub trait AuthClientStorage: Send {
84 fn get<'a>(
93 &'a mut self,
94 key: &'a str,
95 ) -> BoxFuture<'a, Result<Option<StoredKey>, StorageError>>;
96
97 fn set<'a>(
107 &'a mut self,
108 key: &'a str,
109 value: StoredKey,
110 ) -> BoxFuture<'a, Result<(), StorageError>>;
111
112 fn remove<'a>(&'a mut self, key: &'a str) -> BoxFuture<'a, Result<(), StorageError>>;
121}
122
123#[allow(dead_code)]
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use wasm_bindgen_test::*;
128
129 #[wasm_bindgen_test]
130 async fn test_local_storage() {
131 let mut storage = LocalStorage;
132 let value = StoredKey::String("value".to_string());
133 storage.set("test", value).await.unwrap();
134 let value = storage.get("test").await.unwrap();
135 assert_eq!(value, Some(StoredKey::String("value".to_string())));
136 storage.remove("test").await.unwrap();
137 let value = storage.get("test").await.unwrap();
138 assert_eq!(value, None);
139 }
140}