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
28#[derive(Debug, Default, Clone)]
30pub struct MemoryStorage {
31 roles: Arc<DashMap<String, Role>>,
32}
33
34impl MemoryStorage {
35 pub fn new() -> Self {
37 Self {
38 roles: Arc::new(DashMap::new()),
39 }
40 }
41
42 pub fn role_count(&self) -> usize {
44 self.roles.len()
45 }
46
47 pub fn clear(&mut self) {
49 self.roles.clear();
50 }
51}
52
53impl Storage for MemoryStorage {
54 fn store_role(&mut self, role: Role) -> Result<()> {
55 let name = role.name().to_string();
56 self.roles.insert(name, role);
57 Ok(())
58 }
59
60 fn get_role(&self, name: &str) -> Result<Option<Role>> {
61 Ok(self.roles.get(name).map(|r| r.clone()))
62 }
63
64 fn role_exists(&self, name: &str) -> Result<bool> {
65 Ok(self.roles.contains_key(name))
66 }
67
68 fn delete_role(&mut self, name: &str) -> Result<bool> {
69 Ok(self.roles.remove(name).is_some())
70 }
71
72 fn list_roles(&self) -> Result<Vec<String>> {
73 Ok(self.roles.iter().map(|entry| entry.key().clone()).collect())
74 }
75
76 fn update_role(&mut self, role: Role) -> Result<()> {
77 let name = role.name().to_string();
78 self.roles.insert(name, role);
79 Ok(())
80 }
81}
82
83#[cfg(feature = "persistence")]
85pub mod file_storage {
86 use super::*;
87 use crate::error::Error;
88 use std::{
89 collections::HashMap,
90 fs::{File, OpenOptions},
91 io::{BufReader, BufWriter},
92 path::{Path, PathBuf},
93 sync::RwLock,
94 };
95
96 #[derive(Debug)]
98 pub struct FileStorage {
99 storage_path: PathBuf,
100 roles: Arc<RwLock<HashMap<String, Role>>>,
101 }
102
103 impl FileStorage {
104 pub fn new(storage_path: impl AsRef<Path>) -> Result<Self> {
106 let storage_path = storage_path.as_ref().to_path_buf();
107
108 if let Some(parent) = storage_path.parent() {
110 std::fs::create_dir_all(parent).map_err(|e| {
111 Error::Storage(format!("Failed to create storage directory: {}", e))
112 })?;
113 }
114
115 let mut storage = Self {
116 storage_path,
117 roles: Arc::new(RwLock::new(HashMap::new())),
118 };
119
120 storage.load_from_disk()?;
122
123 Ok(storage)
124 }
125
126 fn load_from_disk(&mut self) -> Result<()> {
128 if !self.storage_path.exists() {
129 return Ok(());
130 }
131
132 let file = File::open(&self.storage_path)
133 .map_err(|e| Error::Storage(format!("Failed to open storage file: {}", e)))?;
134
135 let reader = BufReader::new(file);
136 let roles: HashMap<String, Role> = serde_json::from_reader(reader)?;
137
138 *self.roles.write().unwrap() = roles;
139 Ok(())
140 }
141
142 fn save_to_disk(&self) -> Result<()> {
144 let file = OpenOptions::new()
145 .write(true)
146 .create(true)
147 .truncate(true)
148 .open(&self.storage_path)
149 .map_err(|e| Error::Storage(format!("Failed to create storage file: {}", e)))?;
150
151 let writer = BufWriter::new(file);
152 let roles = self.roles.read().unwrap();
153 serde_json::to_writer_pretty(writer, &*roles)?;
154 Ok(())
155 }
156
157 pub fn storage_path(&self) -> &Path {
159 &self.storage_path
160 }
161
162 pub fn role_count(&self) -> usize {
164 self.roles.read().unwrap().len()
165 }
166 }
167
168 impl Storage for FileStorage {
169 fn store_role(&mut self, role: Role) -> Result<()> {
170 let name = role.name().to_string();
171 self.roles.write().unwrap().insert(name, role);
172 self.save_to_disk()
173 }
174
175 fn get_role(&self, name: &str) -> Result<Option<Role>> {
176 Ok(self.roles.read().unwrap().get(name).cloned())
177 }
178
179 fn role_exists(&self, name: &str) -> Result<bool> {
180 Ok(self.roles.read().unwrap().contains_key(name))
181 }
182
183 fn delete_role(&mut self, name: &str) -> Result<bool> {
184 let removed = self.roles.write().unwrap().remove(name).is_some();
185 if removed {
186 self.save_to_disk()?;
187 }
188 Ok(removed)
189 }
190
191 fn list_roles(&self) -> Result<Vec<String>> {
192 Ok(self.roles.read().unwrap().keys().cloned().collect())
193 }
194
195 fn update_role(&mut self, role: Role) -> Result<()> {
196 let name = role.name().to_string();
197 self.roles.write().unwrap().insert(name, role);
198 self.save_to_disk()
199 }
200 }
201}
202
203#[cfg(feature = "persistence")]
204pub use file_storage::FileStorage;
205
206pub struct CompositeStorage {
208 primary: Box<dyn Storage>,
209 secondary: Option<Box<dyn Storage>>,
210}
211
212impl CompositeStorage {
213 pub fn new(primary: Box<dyn Storage>) -> Self {
215 Self {
216 primary,
217 secondary: None,
218 }
219 }
220
221 pub fn with_secondary(mut self, secondary: Box<dyn Storage>) -> Self {
223 self.secondary = Some(secondary);
224 self
225 }
226}
227
228impl Storage for CompositeStorage {
229 fn store_role(&mut self, role: Role) -> Result<()> {
230 self.primary.store_role(role.clone())?;
232
233 if let Some(secondary) = &mut self.secondary {
235 secondary.store_role(role)?;
236 }
237
238 Ok(())
239 }
240
241 fn get_role(&self, name: &str) -> Result<Option<Role>> {
242 match self.primary.get_role(name)? {
244 Some(role) => Ok(Some(role)),
245 None => {
246 if let Some(secondary) = &self.secondary {
248 secondary.get_role(name)
249 } else {
250 Ok(None)
251 }
252 }
253 }
254 }
255
256 fn role_exists(&self, name: &str) -> Result<bool> {
257 if self.primary.role_exists(name)? {
258 Ok(true)
259 } else if let Some(secondary) = &self.secondary {
260 secondary.role_exists(name)
261 } else {
262 Ok(false)
263 }
264 }
265
266 fn delete_role(&mut self, name: &str) -> Result<bool> {
267 let mut deleted = false;
268
269 if self.primary.delete_role(name)? {
270 deleted = true;
271 }
272
273 if let Some(secondary) = &mut self.secondary
274 && secondary.delete_role(name)?
275 {
276 deleted = true;
277 }
278
279 Ok(deleted)
280 }
281
282 fn list_roles(&self) -> Result<Vec<String>> {
283 let mut roles = self.primary.list_roles()?;
284
285 if let Some(secondary) = &self.secondary {
286 let secondary_roles = secondary.list_roles()?;
287 for role in secondary_roles {
288 if !roles.contains(&role) {
289 roles.push(role);
290 }
291 }
292 }
293
294 roles.sort();
295 Ok(roles)
296 }
297
298 fn update_role(&mut self, role: Role) -> Result<()> {
299 self.primary.update_role(role.clone())?;
300
301 if let Some(secondary) = &mut self.secondary {
302 secondary.update_role(role)?;
303 }
304
305 Ok(())
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312 use crate::{permission::Permission, role::Role};
313
314 #[test]
315 fn test_memory_storage() {
316 let mut storage = MemoryStorage::new();
317
318 let role = Role::new("test-role").add_permission(Permission::new("read", "documents"));
319
320 storage.store_role(role.clone()).unwrap();
322 assert_eq!(storage.role_count(), 1);
323
324 assert!(storage.role_exists("test-role").unwrap());
326 assert!(!storage.role_exists("non-existent").unwrap());
327
328 let retrieved = storage.get_role("test-role").unwrap().unwrap();
330 assert_eq!(retrieved.name(), "test-role");
331
332 let roles = storage.list_roles().unwrap();
334 assert_eq!(roles.len(), 1);
335 assert!(roles.contains(&"test-role".to_string()));
336
337 assert!(storage.delete_role("test-role").unwrap());
339 assert!(!storage.role_exists("test-role").unwrap());
340 assert_eq!(storage.role_count(), 0);
341 }
342
343 #[cfg(feature = "persistence")]
344 #[test]
345 fn test_file_storage() {
346 use std::env;
347
348 let temp_dir = env::temp_dir();
349 let storage_path = temp_dir.join("test_roles.json");
350
351 let _ = std::fs::remove_file(&storage_path);
353
354 {
355 let mut storage = FileStorage::new(&storage_path).unwrap();
356
357 let role =
358 Role::new("file-test-role").add_permission(Permission::new("read", "documents"));
359
360 storage.store_role(role.clone()).unwrap();
362 assert_eq!(storage.role_count(), 1);
363
364 assert!(storage_path.exists());
366 }
367
368 {
370 let storage = FileStorage::new(&storage_path).unwrap();
371 assert_eq!(storage.role_count(), 1);
372
373 let retrieved = storage.get_role("file-test-role").unwrap().unwrap();
374 assert_eq!(retrieved.name(), "file-test-role");
375 }
376
377 let _ = std::fs::remove_file(&storage_path);
379 }
380
381 #[test]
382 fn test_composite_storage() {
383 let primary = Box::new(MemoryStorage::new());
384 let secondary = Box::new(MemoryStorage::new());
385
386 let mut storage = CompositeStorage::new(primary).with_secondary(secondary);
387
388 let role = Role::new("composite-test").add_permission(Permission::new("read", "documents"));
389
390 storage.store_role(role.clone()).unwrap();
392
393 let retrieved = storage.get_role("composite-test").unwrap().unwrap();
395 assert_eq!(retrieved.name(), "composite-test");
396
397 let roles = storage.list_roles().unwrap();
399 assert!(roles.contains(&"composite-test".to_string()));
400 }
401}