Mountain/Environment/
StorageProvider.rs1use std::{collections::HashMap, path::PathBuf};
39
40use CommonLibrary::{Error::CommonError::CommonError, Storage::StorageProvider::StorageProvider};
41use async_trait::async_trait;
42use serde_json::Value;
43use tokio::fs;
44
45use super::{MountainEnvironment::MountainEnvironment, Utility};
46use crate::dev_log;
47
48#[async_trait]
53impl StorageProvider for MountainEnvironment {
54 async fn GetStorageValue(&self, IsGlobalScope:bool, Key:&str) -> Result<Option<Value>, CommonError> {
57 let ScopeName = if IsGlobalScope { "Global" } else { "Workspace" };
58
59 dev_log!(
60 "storage",
61 "[StorageProvider] Getting value from {} scope for key: {}",
62 ScopeName,
63 Key
64 );
65
66 if Key.is_empty() {
68 return Ok(None);
69 }
70
71 if Key.len() > 1024 {
72 return Err(CommonError::InvalidArgument {
73 ArgumentName:"Key".into(),
74 Reason:"Key length exceeds maximum allowed length of 1024 characters".into(),
75 });
76 }
77
78 let StorageMapMutex = if IsGlobalScope {
79 &self.ApplicationState.Configuration.MementoGlobalStorage
80 } else {
81 &self.ApplicationState.Configuration.MementoWorkspaceStorage
82 };
83
84 let StorageMapGuard = StorageMapMutex
85 .lock()
86 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?;
87
88 Ok(StorageMapGuard.get(Key).cloned())
89 }
90
91 async fn UpdateStorageValue(
95 &self,
96
97 IsGlobalScope:bool,
98
99 Key:String,
100
101 ValueToSet:Option<Value>,
102 ) -> Result<(), CommonError> {
103 let ScopeName = if IsGlobalScope { "Global" } else { "Workspace" };
104
105 if crate::IPC::DevLog::IsShort::Fn() {
111 crate::dev_log!("storage-verbose", "update {} {}", ScopeName, Key);
112 } else {
113 dev_log!(
114 "storage-verbose",
115 "[StorageProvider] Updating value in {} scope for key: {}",
116 ScopeName,
117 Key
118 );
119 }
120
121 if Key.is_empty() {
123 return Err(CommonError::InvalidArgument {
124 ArgumentName:"Key".into(),
125 Reason:"Key cannot be empty".into(),
126 });
127 }
128
129 if Key.len() > 1024 {
130 return Err(CommonError::InvalidArgument {
131 ArgumentName:"Key".into(),
132 Reason:"Key length exceeds maximum allowed length of 1024 characters".into(),
133 });
134 }
135
136 if let Some(ref value) = ValueToSet {
138 if let Ok(json_string) = serde_json::to_string(value) {
139 if json_string.len() > 10 * 1024 * 1024 {
140 return Err(CommonError::InvalidArgument {
142 ArgumentName:"ValueToSet".into(),
143 Reason:"Value size exceeds maximum allowed size of 10MB".into(),
144 });
145 }
146 }
147 }
148
149 let (StorageMapMutex, StoragePathOption) = if IsGlobalScope {
150 (
151 self.ApplicationState.Configuration.MementoGlobalStorage.clone(),
152 Some(
153 self.ApplicationState
154 .GlobalMementoPath
155 .lock()
156 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?
157 .clone(),
158 ),
159 )
160 } else {
161 (
162 self.ApplicationState.Configuration.MementoWorkspaceStorage.clone(),
163 self.ApplicationState
164 .WorkspaceMementoPath
165 .lock()
166 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?
167 .clone(),
168 )
169 };
170
171 let DataToSave = {
173 let mut StorageMapGuard = StorageMapMutex
174 .lock()
175 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?;
176
177 if let Some(Value) = ValueToSet {
178 StorageMapGuard.insert(Key, Value);
179 } else {
180 StorageMapGuard.remove(&Key);
181 }
182
183 StorageMapGuard.clone()
184 };
185
186 if let Some(StoragePath) = StoragePathOption {
187 tokio::spawn(async move {
188 SaveStorageToDisk(StoragePath, DataToSave).await;
189 });
190 }
191
192 Ok(())
193 }
194
195 async fn GetAllStorage(&self, IsGlobalScope:bool) -> Result<Value, CommonError> {
197 let ScopeName = if IsGlobalScope { "Global" } else { "Workspace" };
198
199 dev_log!(
200 "storage-verbose",
201 "[StorageProvider] Getting all values from {} scope.",
202 ScopeName
203 );
204
205 let StorageMapMutex = if IsGlobalScope {
206 &self.ApplicationState.Configuration.MementoGlobalStorage
207 } else {
208 &self.ApplicationState.Configuration.MementoWorkspaceStorage
209 };
210
211 let StorageMapGuard = StorageMapMutex
212 .lock()
213 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?;
214
215 Ok(serde_json::to_value(&*StorageMapGuard)?)
216 }
217
218 async fn SetAllStorage(&self, IsGlobalScope:bool, FullState:Value) -> Result<(), CommonError> {
220 let ScopeName = if IsGlobalScope { "Global" } else { "Workspace" };
221
222 dev_log!(
223 "storage-verbose",
224 "[StorageProvider] Setting all values for {} scope.",
225 ScopeName
226 );
227
228 let DeserializedState:HashMap<String, Value> = serde_json::from_value(FullState)?;
229
230 let (StorageMapMutex, StoragePathOption) = if IsGlobalScope {
231 (
232 self.ApplicationState.Configuration.MementoGlobalStorage.clone(),
233 Some(
234 self.ApplicationState
235 .GlobalMementoPath
236 .lock()
237 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?
238 .clone(),
239 ),
240 )
241 } else {
242 (
243 self.ApplicationState.Configuration.MementoWorkspaceStorage.clone(),
244 self.ApplicationState
245 .WorkspaceMementoPath
246 .lock()
247 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?
248 .clone(),
249 )
250 };
251
252 *StorageMapMutex
254 .lock()
255 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)? = DeserializedState.clone();
256
257 if let Some(StoragePath) = StoragePathOption {
259 tokio::spawn(async move {
260 SaveStorageToDisk(StoragePath, DeserializedState).await;
261 });
262 }
263
264 Ok(())
265 }
266}
267
268async fn SaveStorageToDisk(Path:PathBuf, Data:HashMap<String, Value>) {
273 dev_log!(
277 "storage-verbose",
278 "[StorageProvider] Persisting storage to disk: {}",
279 Path.display()
280 );
281
282 match serde_json::to_string_pretty(&Data) {
283 Ok(JSONString) => {
284 if let Some(ParentDirectory) = Path.parent() {
285 if let Err(Error) = fs::create_dir_all(ParentDirectory).await {
286 dev_log!(
287 "storage",
288 "error: [StorageProvider] Failed to create parent directory for '{}': {}",
289 Path.display(),
290 Error
291 );
292
293 return;
294 }
295 }
296
297 if let Err(Error) = fs::write(&Path, JSONString).await {
298 dev_log!(
299 "storage",
300 "error: [StorageProvider] Failed to write storage file to '{}': {}",
301 Path.display(),
302 Error
303 );
304 }
305 },
306
307 Err(Error) => {
308 dev_log!(
309 "storage",
310 "error: [StorageProvider] Failed to serialize storage data for '{}': {}",
311 Path.display(),
312 Error
313 );
314 },
315 }
316}