use std::sync::Arc;
use tokio::sync::RwLock;
use super::{
config::TelemetryConfig, events::TelemetryEvent, privacy::PrivacyControl, TelemetryError,
};
pub struct TelemetryCollector {
config: Arc<RwLock<TelemetryConfig>>,
privacy: Arc<RwLock<PrivacyControl>>,
}
impl TelemetryCollector {
pub async fn new(config: Arc<RwLock<TelemetryConfig>>) -> Self {
let anonymization = config.read().await.anonymization;
let privacy = Arc::new(RwLock::new(PrivacyControl::new(anonymization)));
Self { config, privacy }
}
pub async fn apply_privacy(
&self,
event: TelemetryEvent,
) -> Result<TelemetryEvent, TelemetryError> {
let config = self.config.read().await;
if !config.enabled {
return Err(TelemetryError::Configuration(
"Telemetry is disabled".to_string(),
));
}
if !self.should_collect_event(&event, &config) {
return Err(TelemetryError::PrivacyViolation(
"Event type not allowed at current telemetry level".to_string(),
));
}
let privacy = self.privacy.read().await;
Ok(privacy.anonymize_event(event))
}
fn should_collect_event(&self, event: &TelemetryEvent, config: &TelemetryConfig) -> bool {
use super::events::EventType;
match event.event_type {
EventType::Error => config.level.includes_errors(),
EventType::CommandExecuted | EventType::FeatureUsed => config.level.includes_commands(),
EventType::Performance => config.level.includes_performance(),
EventType::Custom => config.level.includes_debug(),
_ => true, }
}
pub async fn update_privacy_level(&self, level: super::privacy::AnonymizationLevel) {
*self.privacy.write().await = PrivacyControl::new(level);
}
pub async fn privacy_level(&self) -> super::privacy::AnonymizationLevel {
self.privacy.read().await.level()
}
pub fn validate_event(&self, event: &TelemetryEvent) -> Result<(), TelemetryError> {
if event.id.is_empty() {
return Err(TelemetryError::Configuration(
"Event ID cannot be empty".to_string(),
));
}
if event.session_id.is_empty() {
return Err(TelemetryError::Configuration(
"Session ID cannot be empty".to_string(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::telemetry::{
config::{TelemetryConfig, TelemetryLevel},
events::{EventType, TelemetryEvent},
privacy::AnonymizationLevel,
};
#[tokio::test]
async fn test_collector_creation() {
let config = Arc::new(RwLock::new(TelemetryConfig::default()));
let collector = TelemetryCollector::new(config).await;
let level = collector.privacy_level().await;
assert_eq!(level, AnonymizationLevel::Medium);
}
#[tokio::test]
async fn test_apply_privacy() {
let config = Arc::new(RwLock::new(TelemetryConfig::enabled()));
let collector = TelemetryCollector::new(config).await;
let event =
TelemetryEvent::new(EventType::CommandExecuted).with_user_id("test_user".to_string());
let result = collector.apply_privacy(event).await;
assert!(result.is_ok());
let anonymized = result.unwrap();
assert_ne!(anonymized.user_id.as_ref().unwrap(), "test_user");
}
#[tokio::test]
async fn test_disabled_telemetry() {
let config = Arc::new(RwLock::new(TelemetryConfig::disabled()));
let collector = TelemetryCollector::new(config).await;
let event = TelemetryEvent::new(EventType::CommandExecuted);
let result = collector.apply_privacy(event).await;
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
TelemetryError::Configuration(_)
));
}
#[tokio::test]
async fn test_event_filtering_by_level() {
let mut config = TelemetryConfig::enabled();
config.level = TelemetryLevel::Minimal;
let config = Arc::new(RwLock::new(config));
let collector = TelemetryCollector::new(config).await;
let error_event = TelemetryEvent::new(EventType::Error);
assert!(collector.apply_privacy(error_event).await.is_ok());
let command_event = TelemetryEvent::new(EventType::CommandExecuted);
assert!(collector.apply_privacy(command_event).await.is_err());
}
#[tokio::test]
async fn test_update_privacy_level() {
let config = Arc::new(RwLock::new(TelemetryConfig::enabled()));
let collector = TelemetryCollector::new(config).await;
assert_eq!(collector.privacy_level().await, AnonymizationLevel::Medium);
collector
.update_privacy_level(AnonymizationLevel::High)
.await;
assert_eq!(collector.privacy_level().await, AnonymizationLevel::High);
}
#[tokio::test]
async fn test_validate_event() {
let config = Arc::new(RwLock::new(TelemetryConfig::enabled()));
let collector = TelemetryCollector::new(config).await;
let valid_event = TelemetryEvent::new(EventType::CommandExecuted);
assert!(collector.validate_event(&valid_event).is_ok());
let mut invalid_event = TelemetryEvent::new(EventType::CommandExecuted);
invalid_event.id = String::new();
assert!(collector.validate_event(&invalid_event).is_err());
let mut invalid_session = TelemetryEvent::new(EventType::CommandExecuted);
invalid_session.session_id = String::new();
assert!(collector.validate_event(&invalid_session).is_err());
}
#[tokio::test]
async fn test_telemetry_levels() {
let mut config = TelemetryConfig::enabled();
config.level = TelemetryLevel::Standard;
let config = Arc::new(RwLock::new(config));
let collector = TelemetryCollector::new(config).await;
assert!(collector
.apply_privacy(TelemetryEvent::new(EventType::CommandExecuted))
.await
.is_ok());
assert!(collector
.apply_privacy(TelemetryEvent::new(EventType::Performance))
.await
.is_ok());
assert!(collector
.apply_privacy(TelemetryEvent::new(EventType::Error))
.await
.is_ok());
}
}