1use crate::{error::Result, role::Role};
4use dashmap::DashMap;
5use std::sync::Arc;
6
7pub trait Storage: Send + Sync {
9 fn store_role(&mut self, role: Role) -> Result<()>;
11
12 fn get_role(&self, name: &str) -> Result<Option<Role>>;
14
15 fn role_exists(&self, name: &str) -> Result<bool>;
17
18 fn delete_role(&mut self, name: &str) -> Result<bool>;
20
21 fn list_roles(&self) -> Result<Vec<String>>;
23
24 fn update_role(&mut self, role: Role) -> Result<()>;
26
27 fn role_count(&self) -> usize {
29 self.list_roles().map(|roles| roles.len()).unwrap_or(0)
31 }
32}
33
34#[derive(Debug, Default, Clone)]
36pub struct MemoryStorage {
37 roles: Arc<DashMap<String, Role>>,
38}
39
40impl MemoryStorage {
41 pub fn new() -> Self {
43 Self {
44 roles: Arc::new(DashMap::new()),
45 }
46 }
47
48 pub fn role_count(&self) -> usize {
50 self.roles.len()
51 }
52
53 pub fn clear(&mut self) {
55 self.roles.clear();
56 }
57}
58
59impl Storage for MemoryStorage {
60 fn store_role(&mut self, role: Role) -> Result<()> {
61 let name = role.name().to_string();
62 self.roles.insert(name, role);
63 Ok(())
64 }
65
66 fn get_role(&self, name: &str) -> Result<Option<Role>> {
67 Ok(self.roles.get(name).map(|r| r.clone()))
68 }
69
70 fn role_exists(&self, name: &str) -> Result<bool> {
71 Ok(self.roles.contains_key(name))
72 }
73
74 fn delete_role(&mut self, name: &str) -> Result<bool> {
75 Ok(self.roles.remove(name).is_some())
76 }
77
78 fn list_roles(&self) -> Result<Vec<String>> {
79 Ok(self.roles.iter().map(|entry| entry.key().clone()).collect())
80 }
81
82 fn update_role(&mut self, role: Role) -> Result<()> {
83 let name = role.name().to_string();
84 self.roles.insert(name, role);
85 Ok(())
86 }
87}
88
89#[cfg(feature = "persistence")]
91pub mod file_storage {
92 use super::*;
93 use crate::error::Error;
94 use std::{
95 collections::HashMap,
96 fs::{File, OpenOptions},
97 io::{BufReader, BufWriter},
98 path::{Path, PathBuf},
99 sync::RwLock,
100 };
101
102 #[derive(Debug)]
104 pub struct FileStorage {
105 storage_path: PathBuf,
106 roles: Arc<RwLock<HashMap<String, Role>>>,
107 }
108
109 impl FileStorage {
110 pub fn new(storage_path: impl AsRef<Path>) -> Result<Self> {
112 let storage_path = storage_path.as_ref().to_path_buf();
113
114 if let Some(parent) = storage_path.parent() {
116 std::fs::create_dir_all(parent).map_err(|e| {
117 Error::Storage(format!("Failed to create storage directory: {}", e))
118 })?;
119 }
120
121 let mut storage = Self {
122 storage_path,
123 roles: Arc::new(RwLock::new(HashMap::new())),
124 };
125
126 storage.load_from_disk()?;
128
129 Ok(storage)
130 }
131
132 fn load_from_disk(&mut self) -> Result<()> {
134 if !self.storage_path.exists() {
135 return Ok(());
136 }
137
138 let file = File::open(&self.storage_path)
139 .map_err(|e| Error::Storage(format!("Failed to open storage file: {}", e)))?;
140
141 let reader = BufReader::new(file);
142 let roles: HashMap<String, Role> = serde_json::from_reader(reader)?;
143
144 *self
145 .roles
146 .write()
147 .map_err(|e| Error::Storage(format!("Failed to acquire write lock: {}", e)))? =
148 roles;
149 Ok(())
150 }
151
152 fn save_to_disk(&self) -> Result<()> {
154 let file = OpenOptions::new()
155 .write(true)
156 .create(true)
157 .truncate(true)
158 .open(&self.storage_path)
159 .map_err(|e| Error::Storage(format!("Failed to create storage file: {}", e)))?;
160
161 let writer = BufWriter::new(file);
162 let roles = self
163 .roles
164 .read()
165 .map_err(|e| Error::Storage(format!("Failed to acquire read lock: {}", e)))?;
166 serde_json::to_writer_pretty(writer, &*roles)?;
167 Ok(())
168 }
169
170 pub fn storage_path(&self) -> &Path {
172 &self.storage_path
173 }
174
175 pub fn role_count(&self) -> usize {
177 self.roles.read().map(|roles| roles.len()).unwrap_or(0)
178 }
179 }
180
181 impl Storage for FileStorage {
182 fn store_role(&mut self, role: Role) -> Result<()> {
183 let name = role.name().to_string();
184 self.roles
185 .write()
186 .map_err(|e| Error::Storage(format!("Failed to acquire write lock: {}", e)))?
187 .insert(name, role);
188 self.save_to_disk()
189 }
190
191 fn get_role(&self, name: &str) -> Result<Option<Role>> {
192 let roles = self
193 .roles
194 .read()
195 .map_err(|e| Error::Storage(format!("Failed to acquire read lock: {}", e)))?;
196 Ok(roles.get(name).cloned())
197 }
198
199 fn role_exists(&self, name: &str) -> Result<bool> {
200 let roles = self
201 .roles
202 .read()
203 .map_err(|e| Error::Storage(format!("Failed to acquire read lock: {}", e)))?;
204 Ok(roles.contains_key(name))
205 }
206
207 fn delete_role(&mut self, name: &str) -> Result<bool> {
208 let removed = self
209 .roles
210 .write()
211 .map_err(|e| Error::Storage(format!("Failed to acquire write lock: {}", e)))?
212 .remove(name)
213 .is_some();
214 if removed {
215 self.save_to_disk()?;
216 }
217 Ok(removed)
218 }
219
220 fn list_roles(&self) -> Result<Vec<String>> {
221 let roles = self
222 .roles
223 .read()
224 .map_err(|e| Error::Storage(format!("Failed to acquire read lock: {}", e)))?;
225 Ok(roles.keys().cloned().collect())
226 }
227
228 fn update_role(&mut self, role: Role) -> Result<()> {
229 let name = role.name().to_string();
230 self.roles
231 .write()
232 .map_err(|e| Error::Storage(format!("Failed to acquire write lock: {}", e)))?
233 .insert(name, role);
234 self.save_to_disk()
235 }
236 }
237}
238
239#[cfg(feature = "persistence")]
240pub use file_storage::FileStorage;
241
242pub struct CompositeStorage {
244 primary: Box<dyn Storage>,
245 secondary: Option<Box<dyn Storage>>,
246}
247
248impl CompositeStorage {
249 pub fn new(primary: Box<dyn Storage>) -> Self {
251 Self {
252 primary,
253 secondary: None,
254 }
255 }
256
257 pub fn with_secondary(mut self, secondary: Box<dyn Storage>) -> Self {
259 self.secondary = Some(secondary);
260 self
261 }
262}
263
264impl Storage for CompositeStorage {
265 fn store_role(&mut self, role: Role) -> Result<()> {
266 self.primary.store_role(role.clone())?;
268
269 if let Some(secondary) = &mut self.secondary {
271 secondary.store_role(role)?;
272 }
273
274 Ok(())
275 }
276
277 fn get_role(&self, name: &str) -> Result<Option<Role>> {
278 match self.primary.get_role(name)? {
280 Some(role) => Ok(Some(role)),
281 None => {
282 if let Some(secondary) = &self.secondary {
284 secondary.get_role(name)
285 } else {
286 Ok(None)
287 }
288 }
289 }
290 }
291
292 fn role_exists(&self, name: &str) -> Result<bool> {
293 if self.primary.role_exists(name)? {
294 Ok(true)
295 } else if let Some(secondary) = &self.secondary {
296 secondary.role_exists(name)
297 } else {
298 Ok(false)
299 }
300 }
301
302 fn delete_role(&mut self, name: &str) -> Result<bool> {
303 let mut deleted = false;
304
305 if self.primary.delete_role(name)? {
306 deleted = true;
307 }
308
309 if let Some(secondary) = &mut self.secondary
310 && secondary.delete_role(name)?
311 {
312 deleted = true;
313 }
314
315 Ok(deleted)
316 }
317
318 fn list_roles(&self) -> Result<Vec<String>> {
319 let mut roles = self.primary.list_roles()?;
320
321 if let Some(secondary) = &self.secondary {
322 let secondary_roles = secondary.list_roles()?;
323 for role in secondary_roles {
324 if !roles.contains(&role) {
325 roles.push(role);
326 }
327 }
328 }
329
330 roles.sort();
331 Ok(roles)
332 }
333
334 fn update_role(&mut self, role: Role) -> Result<()> {
335 self.primary.update_role(role.clone())?;
336
337 if let Some(secondary) = &mut self.secondary {
338 secondary.update_role(role)?;
339 }
340
341 Ok(())
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348 use crate::{permission::Permission, role::Role};
349
350 #[test]
351 fn test_memory_storage() {
352 let mut storage = MemoryStorage::new();
353
354 let role = Role::new("test-role").add_permission(Permission::new("read", "documents"));
355
356 storage
358 .store_role(role.clone())
359 .expect("Failed to store role");
360 assert_eq!(storage.role_count(), 1);
361
362 assert!(
364 storage
365 .role_exists("test-role")
366 .expect("Failed to check role existence")
367 );
368 assert!(
369 !storage
370 .role_exists("non-existent")
371 .expect("Failed to check role existence")
372 );
373
374 let retrieved = storage
376 .get_role("test-role")
377 .expect("Failed to get role")
378 .expect("Role should exist");
379 assert_eq!(retrieved.name(), "test-role");
380
381 let roles = storage.list_roles().expect("Failed to list roles");
383 assert_eq!(roles.len(), 1);
384 assert!(roles.contains(&"test-role".to_string()));
385
386 assert!(
388 storage
389 .delete_role("test-role")
390 .expect("Failed to delete role")
391 );
392 assert!(
393 !storage
394 .role_exists("test-role")
395 .expect("Failed to check role existence")
396 );
397 assert_eq!(storage.role_count(), 0);
398 }
399
400 #[cfg(feature = "persistence")]
401 #[test]
402 fn test_file_storage() {
403 use std::env;
404
405 let temp_dir = env::temp_dir();
406 let storage_path = temp_dir.join("test_roles.json");
407
408 let _ = std::fs::remove_file(&storage_path);
410
411 {
412 let mut storage =
413 FileStorage::new(&storage_path).expect("Failed to create file storage");
414
415 let role =
416 Role::new("file-test-role").add_permission(Permission::new("read", "documents"));
417
418 storage
420 .store_role(role.clone())
421 .expect("Failed to store role");
422 assert_eq!(storage.role_count(), 1);
423
424 assert!(storage_path.exists());
426 }
427
428 {
430 let storage = FileStorage::new(&storage_path).expect("Failed to create file storage");
431 assert_eq!(storage.role_count(), 1);
432
433 let retrieved = storage
434 .get_role("file-test-role")
435 .expect("Failed to get role")
436 .expect("Role should exist");
437 assert_eq!(retrieved.name(), "file-test-role");
438 }
439
440 let _ = std::fs::remove_file(&storage_path);
442 }
443
444 #[test]
445 fn test_composite_storage() {
446 let primary = Box::new(MemoryStorage::new());
447 let secondary = Box::new(MemoryStorage::new());
448
449 let mut storage = CompositeStorage::new(primary).with_secondary(secondary);
450
451 let role = Role::new("composite-test").add_permission(Permission::new("read", "documents"));
452
453 storage
455 .store_role(role.clone())
456 .expect("Failed to store role");
457
458 let retrieved = storage
460 .get_role("composite-test")
461 .expect("Failed to get role")
462 .expect("Role should exist");
463 assert_eq!(retrieved.name(), "composite-test");
464
465 let roles = storage.list_roles().expect("Failed to list roles");
467 assert!(roles.contains(&"composite-test".to_string()));
468 }
469}