1use crate::audit::{AuditEvent, AuditEventType, AuditSeverity};
10use chrono::{DateTime, Utc};
11use std::path::PathBuf;
12use std::sync::{Arc, Mutex};
13use torsh_core::error::{Result, TorshError};
14
15pub trait AuditStorage: Send + Sync {
17 fn store(&mut self, event: &AuditEvent) -> Result<()>;
19
20 fn retrieve_by_time_range(
22 &self,
23 start: DateTime<Utc>,
24 end: DateTime<Utc>,
25 ) -> Result<Vec<AuditEvent>>;
26
27 fn retrieve_by_type(&self, event_type: &AuditEventType) -> Result<Vec<AuditEvent>>;
29
30 fn retrieve_by_severity(&self, severity: &AuditSeverity) -> Result<Vec<AuditEvent>>;
32
33 fn retrieve_by_user(&self, user_id: &str) -> Result<Vec<AuditEvent>>;
35
36 fn count(&self) -> Result<usize>;
38
39 fn clear(&mut self) -> Result<()>;
41
42 fn flush(&mut self) -> Result<()>;
44
45 fn get_statistics(&self) -> Result<StorageStatistics>;
47}
48
49#[derive(Debug, Clone)]
51pub struct StorageStatistics {
52 pub total_events: usize,
54 pub storage_size_bytes: u64,
56 pub last_write: Option<DateTime<Utc>>,
58 pub write_count: u64,
60 pub read_count: u64,
62 pub failed_operations: u64,
64}
65
66impl Default for StorageStatistics {
67 fn default() -> Self {
68 Self {
69 total_events: 0,
70 storage_size_bytes: 0,
71 last_write: None,
72 write_count: 0,
73 read_count: 0,
74 failed_operations: 0,
75 }
76 }
77}
78
79#[derive(Debug, Clone)]
81pub struct InMemoryStorage {
82 events: Arc<Mutex<Vec<AuditEvent>>>,
83 stats: Arc<Mutex<StorageStatistics>>,
84}
85
86impl InMemoryStorage {
87 pub fn new() -> Self {
89 Self {
90 events: Arc::new(Mutex::new(Vec::new())),
91 stats: Arc::new(Mutex::new(StorageStatistics::default())),
92 }
93 }
94
95 pub fn get_all_events(&self) -> Result<Vec<AuditEvent>> {
97 let events = self
98 .events
99 .lock()
100 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
101 Ok(events.clone())
102 }
103}
104
105impl Default for InMemoryStorage {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111impl AuditStorage for InMemoryStorage {
112 fn store(&mut self, event: &AuditEvent) -> Result<()> {
113 let mut events = self
114 .events
115 .lock()
116 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
117
118 let mut stats = self
119 .stats
120 .lock()
121 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
122
123 events.push(event.clone());
124 stats.total_events += 1;
125 stats.write_count += 1;
126 stats.last_write = Some(Utc::now());
127
128 Ok(())
129 }
130
131 fn retrieve_by_time_range(
132 &self,
133 start: DateTime<Utc>,
134 end: DateTime<Utc>,
135 ) -> Result<Vec<AuditEvent>> {
136 let events = self
137 .events
138 .lock()
139 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
140
141 let mut stats = self
142 .stats
143 .lock()
144 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
145 stats.read_count += 1;
146
147 Ok(events
148 .iter()
149 .filter(|e| e.timestamp >= start && e.timestamp <= end)
150 .cloned()
151 .collect())
152 }
153
154 fn retrieve_by_type(&self, event_type: &AuditEventType) -> Result<Vec<AuditEvent>> {
155 let events = self
156 .events
157 .lock()
158 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
159
160 let mut stats = self
161 .stats
162 .lock()
163 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
164 stats.read_count += 1;
165
166 Ok(events
167 .iter()
168 .filter(|e| &e.event_type == event_type)
169 .cloned()
170 .collect())
171 }
172
173 fn retrieve_by_severity(&self, severity: &AuditSeverity) -> Result<Vec<AuditEvent>> {
174 let events = self
175 .events
176 .lock()
177 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
178
179 let mut stats = self
180 .stats
181 .lock()
182 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
183 stats.read_count += 1;
184
185 Ok(events
186 .iter()
187 .filter(|e| &e.severity == severity)
188 .cloned()
189 .collect())
190 }
191
192 fn retrieve_by_user(&self, user_id: &str) -> Result<Vec<AuditEvent>> {
193 let events = self
194 .events
195 .lock()
196 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
197
198 let mut stats = self
199 .stats
200 .lock()
201 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
202 stats.read_count += 1;
203
204 Ok(events
205 .iter()
206 .filter(|e| e.user_id.as_deref() == Some(user_id))
207 .cloned()
208 .collect())
209 }
210
211 fn count(&self) -> Result<usize> {
212 let events = self
213 .events
214 .lock()
215 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
216 Ok(events.len())
217 }
218
219 fn clear(&mut self) -> Result<()> {
220 let mut events = self
221 .events
222 .lock()
223 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
224
225 let mut stats = self
226 .stats
227 .lock()
228 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
229
230 events.clear();
231 *stats = StorageStatistics::default();
232
233 Ok(())
234 }
235
236 fn flush(&mut self) -> Result<()> {
237 Ok(())
239 }
240
241 fn get_statistics(&self) -> Result<StorageStatistics> {
242 let stats = self
243 .stats
244 .lock()
245 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
246 Ok(stats.clone())
247 }
248}
249
250#[derive(Debug, Clone)]
252pub struct SqliteStorageConfig {
253 pub db_path: PathBuf,
255 pub max_connections: u32,
257 pub connection_timeout: u64,
259 pub wal_mode: bool,
261 pub auto_vacuum: bool,
263}
264
265impl SqliteStorageConfig {
266 pub fn new(db_path: PathBuf) -> Self {
268 Self {
269 db_path,
270 max_connections: 10,
271 connection_timeout: 30,
272 wal_mode: true,
273 auto_vacuum: true,
274 }
275 }
276
277 pub fn with_max_connections(mut self, max: u32) -> Self {
279 self.max_connections = max;
280 self
281 }
282
283 pub fn with_timeout(mut self, timeout: u64) -> Self {
285 self.connection_timeout = timeout;
286 self
287 }
288
289 pub fn with_wal_mode(mut self, enable: bool) -> Self {
291 self.wal_mode = enable;
292 self
293 }
294
295 pub fn with_auto_vacuum(mut self, enable: bool) -> Self {
297 self.auto_vacuum = enable;
298 self
299 }
300}
301
302#[derive(Debug)]
304pub struct SqliteStorage {
305 config: SqliteStorageConfig,
306 events: Arc<Mutex<Vec<AuditEvent>>>, stats: Arc<Mutex<StorageStatistics>>,
310}
311
312impl SqliteStorage {
313 pub fn new(config: SqliteStorageConfig) -> Result<Self> {
315 let storage = Self {
320 config,
321 events: Arc::new(Mutex::new(Vec::new())),
322 stats: Arc::new(Mutex::new(StorageStatistics::default())),
323 };
324
325 storage.initialize_schema()?;
327
328 Ok(storage)
329 }
330
331 fn initialize_schema(&self) -> Result<()> {
333 Ok(())
355 }
356
357 pub fn get_db_statistics(&self) -> Result<DatabaseStatistics> {
359 Ok(DatabaseStatistics {
360 database_size_bytes: 0,
361 table_count: 1,
362 index_count: 4,
363 page_size: 4096,
364 page_count: 0,
365 wal_enabled: self.config.wal_mode,
366 })
367 }
368}
369
370impl AuditStorage for SqliteStorage {
371 fn store(&mut self, event: &AuditEvent) -> Result<()> {
372 let mut events = self
377 .events
378 .lock()
379 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
380
381 let mut stats = self
382 .stats
383 .lock()
384 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
385
386 events.push(event.clone());
387 stats.total_events += 1;
388 stats.write_count += 1;
389 stats.last_write = Some(Utc::now());
390
391 Ok(())
392 }
393
394 fn retrieve_by_time_range(
395 &self,
396 start: DateTime<Utc>,
397 end: DateTime<Utc>,
398 ) -> Result<Vec<AuditEvent>> {
399 let events = self
401 .events
402 .lock()
403 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
404
405 let mut stats = self
406 .stats
407 .lock()
408 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
409 stats.read_count += 1;
410
411 Ok(events
412 .iter()
413 .filter(|e| e.timestamp >= start && e.timestamp <= end)
414 .cloned()
415 .collect())
416 }
417
418 fn retrieve_by_type(&self, event_type: &AuditEventType) -> Result<Vec<AuditEvent>> {
419 let events = self
421 .events
422 .lock()
423 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
424
425 let mut stats = self
426 .stats
427 .lock()
428 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
429 stats.read_count += 1;
430
431 Ok(events
432 .iter()
433 .filter(|e| &e.event_type == event_type)
434 .cloned()
435 .collect())
436 }
437
438 fn retrieve_by_severity(&self, severity: &AuditSeverity) -> Result<Vec<AuditEvent>> {
439 let events = self
440 .events
441 .lock()
442 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
443
444 let mut stats = self
445 .stats
446 .lock()
447 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
448 stats.read_count += 1;
449
450 Ok(events
451 .iter()
452 .filter(|e| &e.severity == severity)
453 .cloned()
454 .collect())
455 }
456
457 fn retrieve_by_user(&self, user_id: &str) -> Result<Vec<AuditEvent>> {
458 let events = self
459 .events
460 .lock()
461 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
462
463 let mut stats = self
464 .stats
465 .lock()
466 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
467 stats.read_count += 1;
468
469 Ok(events
470 .iter()
471 .filter(|e| e.user_id.as_deref() == Some(user_id))
472 .cloned()
473 .collect())
474 }
475
476 fn count(&self) -> Result<usize> {
477 let events = self
478 .events
479 .lock()
480 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
481 Ok(events.len())
482 }
483
484 fn clear(&mut self) -> Result<()> {
485 let mut events = self
487 .events
488 .lock()
489 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
490
491 let mut stats = self
492 .stats
493 .lock()
494 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
495
496 events.clear();
497 *stats = StorageStatistics::default();
498
499 Ok(())
500 }
501
502 fn flush(&mut self) -> Result<()> {
503 Ok(())
505 }
506
507 fn get_statistics(&self) -> Result<StorageStatistics> {
508 let stats = self
509 .stats
510 .lock()
511 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
512 Ok(stats.clone())
513 }
514}
515
516#[derive(Debug, Clone)]
518pub struct DatabaseStatistics {
519 pub database_size_bytes: u64,
521 pub table_count: usize,
523 pub index_count: usize,
525 pub page_size: u32,
527 pub page_count: u64,
529 pub wal_enabled: bool,
531}
532
533#[derive(Debug, Clone)]
535pub struct PostgresStorageConfig {
536 pub host: String,
538 pub port: u16,
540 pub database: String,
542 pub username: String,
544 pub password: String,
546 pub pool_size: u32,
548 pub connection_timeout: u64,
550 pub ssl_mode: SslMode,
552}
553
554#[derive(Debug, Clone, Copy, PartialEq, Eq)]
556pub enum SslMode {
557 Disable,
559 Prefer,
561 Require,
563}
564
565impl PostgresStorageConfig {
566 pub fn new(
568 host: String,
569 port: u16,
570 database: String,
571 username: String,
572 password: String,
573 ) -> Self {
574 Self {
575 host,
576 port,
577 database,
578 username,
579 password,
580 pool_size: 20,
581 connection_timeout: 30,
582 ssl_mode: SslMode::Prefer,
583 }
584 }
585
586 pub fn with_pool_size(mut self, size: u32) -> Self {
588 self.pool_size = size;
589 self
590 }
591
592 pub fn with_timeout(mut self, timeout: u64) -> Self {
594 self.connection_timeout = timeout;
595 self
596 }
597
598 pub fn with_ssl_mode(mut self, mode: SslMode) -> Self {
600 self.ssl_mode = mode;
601 self
602 }
603
604 pub fn connection_string(&self) -> String {
606 let ssl = match self.ssl_mode {
607 SslMode::Disable => "disable",
608 SslMode::Prefer => "prefer",
609 SslMode::Require => "require",
610 };
611
612 format!(
613 "postgresql://{}:{}@{}:{}/{}?sslmode={}",
614 self.username, self.password, self.host, self.port, self.database, ssl
615 )
616 }
617}
618
619#[derive(Debug)]
621pub struct PostgresStorage {
622 config: PostgresStorageConfig,
623 events: Arc<Mutex<Vec<AuditEvent>>>, stats: Arc<Mutex<StorageStatistics>>,
627}
628
629impl PostgresStorage {
630 pub fn new(config: PostgresStorageConfig) -> Result<Self> {
632 let storage = Self {
636 config,
637 events: Arc::new(Mutex::new(Vec::new())),
638 stats: Arc::new(Mutex::new(StorageStatistics::default())),
639 };
640
641 storage.initialize_schema()?;
642
643 Ok(storage)
644 }
645
646 fn initialize_schema(&self) -> Result<()> {
648 Ok(())
671 }
672
673 pub fn get_pool_statistics(&self) -> Result<PoolStatistics> {
675 Ok(PoolStatistics {
676 active_connections: 0,
677 idle_connections: 0,
678 max_connections: self.config.pool_size,
679 wait_count: 0,
680 wait_duration_ms: 0,
681 })
682 }
683}
684
685impl AuditStorage for PostgresStorage {
686 fn store(&mut self, event: &AuditEvent) -> Result<()> {
687 let mut events = self
692 .events
693 .lock()
694 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
695
696 let mut stats = self
697 .stats
698 .lock()
699 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
700
701 events.push(event.clone());
702 stats.total_events += 1;
703 stats.write_count += 1;
704 stats.last_write = Some(Utc::now());
705
706 Ok(())
707 }
708
709 fn retrieve_by_time_range(
710 &self,
711 start: DateTime<Utc>,
712 end: DateTime<Utc>,
713 ) -> Result<Vec<AuditEvent>> {
714 let events = self
716 .events
717 .lock()
718 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
719
720 let mut stats = self
721 .stats
722 .lock()
723 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
724 stats.read_count += 1;
725
726 Ok(events
727 .iter()
728 .filter(|e| e.timestamp >= start && e.timestamp <= end)
729 .cloned()
730 .collect())
731 }
732
733 fn retrieve_by_type(&self, event_type: &AuditEventType) -> Result<Vec<AuditEvent>> {
734 let events = self
735 .events
736 .lock()
737 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
738
739 let mut stats = self
740 .stats
741 .lock()
742 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
743 stats.read_count += 1;
744
745 Ok(events
746 .iter()
747 .filter(|e| &e.event_type == event_type)
748 .cloned()
749 .collect())
750 }
751
752 fn retrieve_by_severity(&self, severity: &AuditSeverity) -> Result<Vec<AuditEvent>> {
753 let events = self
754 .events
755 .lock()
756 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
757
758 let mut stats = self
759 .stats
760 .lock()
761 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
762 stats.read_count += 1;
763
764 Ok(events
765 .iter()
766 .filter(|e| &e.severity == severity)
767 .cloned()
768 .collect())
769 }
770
771 fn retrieve_by_user(&self, user_id: &str) -> Result<Vec<AuditEvent>> {
772 let events = self
773 .events
774 .lock()
775 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
776
777 let mut stats = self
778 .stats
779 .lock()
780 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
781 stats.read_count += 1;
782
783 Ok(events
784 .iter()
785 .filter(|e| e.user_id.as_deref() == Some(user_id))
786 .cloned()
787 .collect())
788 }
789
790 fn count(&self) -> Result<usize> {
791 let events = self
792 .events
793 .lock()
794 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
795 Ok(events.len())
796 }
797
798 fn clear(&mut self) -> Result<()> {
799 let mut events = self
801 .events
802 .lock()
803 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
804
805 let mut stats = self
806 .stats
807 .lock()
808 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
809
810 events.clear();
811 *stats = StorageStatistics::default();
812
813 Ok(())
814 }
815
816 fn flush(&mut self) -> Result<()> {
817 Ok(())
819 }
820
821 fn get_statistics(&self) -> Result<StorageStatistics> {
822 let stats = self
823 .stats
824 .lock()
825 .map_err(|e| TorshError::InvalidArgument(format!("Lock error: {}", e)))?;
826 Ok(stats.clone())
827 }
828}
829
830#[derive(Debug, Clone)]
832pub struct PoolStatistics {
833 pub active_connections: u32,
835 pub idle_connections: u32,
837 pub max_connections: u32,
839 pub wait_count: u64,
841 pub wait_duration_ms: u64,
843}
844
845#[cfg(test)]
846mod tests {
847 use super::*;
848
849 #[test]
850 fn test_in_memory_storage() {
851 let mut storage = InMemoryStorage::new();
852
853 let event = AuditEvent::new(AuditEventType::PackageDownload, "Test event".to_string());
854
855 assert!(storage.store(&event).is_ok());
856 assert_eq!(storage.count().unwrap(), 1);
857
858 let events = storage.get_all_events().unwrap();
859 assert_eq!(events.len(), 1);
860
861 assert!(storage.clear().is_ok());
862 assert_eq!(storage.count().unwrap(), 0);
863 }
864
865 #[test]
866 fn test_sqlite_storage_config() {
867 let config = SqliteStorageConfig::new(std::env::temp_dir().join("test.db"))
868 .with_max_connections(20)
869 .with_timeout(60)
870 .with_wal_mode(true)
871 .with_auto_vacuum(false);
872
873 assert_eq!(config.max_connections, 20);
874 assert_eq!(config.connection_timeout, 60);
875 assert!(config.wal_mode);
876 assert!(!config.auto_vacuum);
877 }
878
879 #[test]
880 fn test_postgres_storage_config() {
881 let config = PostgresStorageConfig::new(
882 "localhost".to_string(),
883 5432,
884 "audit_db".to_string(),
885 "user".to_string(),
886 "pass".to_string(),
887 )
888 .with_pool_size(30)
889 .with_ssl_mode(SslMode::Require);
890
891 assert_eq!(config.pool_size, 30);
892 assert_eq!(config.ssl_mode, SslMode::Require);
893
894 let conn_str = config.connection_string();
895 assert!(conn_str.contains("localhost:5432"));
896 assert!(conn_str.contains("sslmode=require"));
897 }
898
899 #[test]
900 fn test_storage_statistics() {
901 let stats = StorageStatistics::default();
902 assert_eq!(stats.total_events, 0);
903 assert_eq!(stats.write_count, 0);
904 assert_eq!(stats.read_count, 0);
905 }
906}