use super::{
async_trait, Arc, CorrelationState, DateTime, Duration, EventFilter, EventId, RateLimitKey,
RateLimitState, Result, SecurityEvent, SnapshotId, StorageProvider, StorageStats, Utc,
};
use std::collections::{HashMap, VecDeque};
use tokio::sync::RwLock;
use tracing::{debug, info};
use uuid::Uuid;
pub struct InMemoryStorage {
events: Arc<RwLock<HashMap<EventId, SecurityEvent>>>,
events_by_client: Arc<RwLock<HashMap<String, Vec<EventId>>>>,
rate_limits: Arc<RwLock<HashMap<String, RateLimitState>>>,
correlations: Arc<RwLock<HashMap<String, CorrelationState>>>,
snapshots: Arc<RwLock<HashMap<SnapshotId, Snapshot>>>,
event_order: Arc<RwLock<VecDeque<EventId>>>,
max_events: usize,
}
#[derive(Clone)]
struct Snapshot {
id: SnapshotId,
created_at: DateTime<Utc>,
events: HashMap<EventId, SecurityEvent>,
rate_limits: HashMap<String, RateLimitState>,
correlations: HashMap<String, CorrelationState>,
}
impl Default for InMemoryStorage {
fn default() -> Self {
Self::new()
}
}
impl InMemoryStorage {
pub fn new() -> Self {
Self::with_capacity(100_000) }
pub fn with_capacity(max_events: usize) -> Self {
info!(
"Initializing in-memory storage with capacity: {}",
max_events
);
Self {
events: Arc::new(RwLock::new(HashMap::new())),
events_by_client: Arc::new(RwLock::new(HashMap::new())),
rate_limits: Arc::new(RwLock::new(HashMap::new())),
correlations: Arc::new(RwLock::new(HashMap::new())),
snapshots: Arc::new(RwLock::new(HashMap::new())),
event_order: Arc::new(RwLock::new(VecDeque::new())),
max_events,
}
}
async fn evict_if_needed(&self) {
let mut order = self.event_order.write().await;
let mut events = self.events.write().await;
while order.len() >= self.max_events {
if let Some(old_id) = order.pop_front() {
if let Some(old_event) = events.remove(&old_id) {
let mut by_client = self.events_by_client.write().await;
if let Some(client_events) = by_client.get_mut(&old_event.client_id) {
client_events.retain(|id| id != &old_id);
}
}
}
}
}
}
#[async_trait]
impl StorageProvider for InMemoryStorage {
async fn store_event(&self, event: &SecurityEvent) -> Result<EventId> {
self.evict_if_needed().await;
let id = EventId(Uuid::new_v4().to_string());
{
let mut events = self.events.write().await;
events.insert(id.clone(), event.clone());
}
{
let mut by_client = self.events_by_client.write().await;
by_client
.entry(event.client_id.clone())
.or_insert_with(Vec::new)
.push(id.clone());
}
{
let mut order = self.event_order.write().await;
order.push_back(id.clone());
}
debug!("Stored event {} for client {}", id.0, event.client_id);
Ok(id)
}
async fn get_event(&self, id: &EventId) -> Result<Option<SecurityEvent>> {
let events = self.events.read().await;
Ok(events.get(id).cloned())
}
async fn query_events(&self, filter: EventFilter) -> Result<Vec<SecurityEvent>> {
let events = self.events.read().await;
let by_client = self.events_by_client.read().await;
let mut results = Vec::new();
if let Some(client_id) = &filter.client_id {
if let Some(event_ids) = by_client.get(client_id) {
for event_id in event_ids {
if let Some(event) = events.get(event_id) {
if Self::matches_filter(event, &filter) {
results.push(event.clone());
}
}
}
}
} else {
for event in events.values() {
if Self::matches_filter(event, &filter) {
results.push(event.clone());
}
}
}
results.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
if let Some(limit) = filter.limit {
results.truncate(limit);
}
Ok(results)
}
async fn store_rate_limit_state(
&self,
key: &RateLimitKey,
state: &RateLimitState,
) -> Result<()> {
let mut rate_limits = self.rate_limits.write().await;
let key_str = format!("{}:{}", key.client_id, key.method.as_deref().unwrap_or("*"));
rate_limits.insert(key_str, state.clone());
Ok(())
}
async fn get_rate_limit_state(&self, key: &RateLimitKey) -> Result<Option<RateLimitState>> {
let rate_limits = self.rate_limits.read().await;
let key_str = format!("{}:{}", key.client_id, key.method.as_deref().unwrap_or("*"));
Ok(rate_limits.get(&key_str).cloned())
}
async fn cleanup_rate_limit_states(&self, older_than: Duration) -> Result<u64> {
let mut rate_limits = self.rate_limits.write().await;
let cutoff = Utc::now() - chrono::Duration::from_std(older_than)?;
let initial_count = rate_limits.len();
rate_limits.retain(|_, state| state.last_refill > cutoff);
let removed = initial_count - rate_limits.len();
debug!("Cleaned up {} old rate limit states", removed);
Ok(removed as u64)
}
async fn store_correlation_state(
&self,
client_id: &str,
state: &CorrelationState,
) -> Result<()> {
let mut correlations = self.correlations.write().await;
correlations.insert(client_id.to_string(), state.clone());
Ok(())
}
async fn get_correlation_state(&self, client_id: &str) -> Result<Option<CorrelationState>> {
let correlations = self.correlations.read().await;
Ok(correlations.get(client_id).cloned())
}
async fn create_snapshot(&self) -> Result<SnapshotId> {
let id = SnapshotId(Uuid::new_v4().to_string());
let snapshot = Snapshot {
id: id.clone(),
created_at: Utc::now(),
events: self.events.read().await.clone(),
rate_limits: self.rate_limits.read().await.clone(),
correlations: self.correlations.read().await.clone(),
};
let mut snapshots = self.snapshots.write().await;
snapshots.insert(id.clone(), snapshot);
info!("Created snapshot {}", id.0);
Ok(id)
}
async fn list_snapshots(&self) -> Result<Vec<(SnapshotId, DateTime<Utc>)>> {
let snapshots = self.snapshots.read().await;
let mut list: Vec<_> = snapshots
.values()
.map(|s| (s.id.clone(), s.created_at))
.collect();
list.sort_by(|a, b| b.1.cmp(&a.1)); Ok(list)
}
async fn restore_snapshot(&self, id: &SnapshotId) -> Result<()> {
let snapshots = self.snapshots.read().await;
let snapshot = snapshots
.get(id)
.ok_or_else(|| anyhow::anyhow!("Snapshot not found"))?
.clone();
drop(snapshots);
*self.events.write().await = snapshot.events;
*self.rate_limits.write().await = snapshot.rate_limits;
*self.correlations.write().await = snapshot.correlations;
let mut order = self.event_order.write().await;
let mut by_client = self.events_by_client.write().await;
order.clear();
by_client.clear();
let events = self.events.read().await;
let mut event_list: Vec<_> = events.iter().collect();
event_list.sort_by_key(|(_, event)| event.timestamp);
for (id, event) in event_list {
order.push_back(id.clone());
by_client
.entry(event.client_id.clone())
.or_insert_with(Vec::new)
.push(id.clone());
}
info!("Restored from snapshot {}", id.0);
Ok(())
}
async fn delete_snapshot(&self, id: &SnapshotId) -> Result<()> {
let mut snapshots = self.snapshots.write().await;
snapshots
.remove(id)
.ok_or_else(|| anyhow::anyhow!("Snapshot not found"))?;
Ok(())
}
async fn get_stats(&self) -> Result<StorageStats> {
let events = self.events.read().await;
let rate_limits = self.rate_limits.read().await;
let correlations = self.correlations.read().await;
let event_size = events.len() * std::mem::size_of::<(EventId, SecurityEvent)>();
let rate_limit_size = rate_limits.len() * std::mem::size_of::<(String, RateLimitState)>();
let correlation_size =
correlations.len() * std::mem::size_of::<(String, CorrelationState)>();
Ok(StorageStats {
event_count: events.len() as u64,
total_size: (event_size + rate_limit_size + correlation_size) as u64,
rate_limit_entries: rate_limits.len() as u64,
correlation_states: correlations.len() as u64,
storage_type: "memory".to_string(),
metadata: serde_json::json!({
"max_events": self.max_events,
"snapshots": self.snapshots.read().await.len(),
}),
})
}
async fn compact(&self) -> Result<()> {
self.events.write().await.shrink_to_fit();
self.events_by_client.write().await.shrink_to_fit();
self.rate_limits.write().await.shrink_to_fit();
self.correlations.write().await.shrink_to_fit();
debug!("Compacted in-memory storage");
Ok(())
}
}
impl InMemoryStorage {
fn matches_filter(event: &SecurityEvent, filter: &EventFilter) -> bool {
if let Some(event_type) = &filter.event_type {
if &event.event_type != event_type {
return false;
}
}
let event_time =
DateTime::<Utc>::from_timestamp(event.timestamp as i64, 0).unwrap_or_else(Utc::now);
if let Some(from) = filter.from_time {
if event_time < from {
return false;
}
}
if let Some(to) = filter.to_time {
if event_time > to {
return false;
}
}
if let Some(min_severity) = &filter.min_severity {
if let Some(severity) = event.metadata.get("severity").and_then(|v| v.as_str()) {
let severity_rank = match severity {
"low" => 1,
"medium" => 2,
"high" => 3,
"critical" => 4,
_ => 0,
};
let min_rank = match min_severity.as_str() {
"low" => 1,
"medium" => 2,
"high" => 3,
"critical" => 4,
_ => 0,
};
if severity_rank < min_rank {
return false;
}
}
}
true
}
}