sigstat 0.0.4

Statsig Rust SDK for usage in multi-user server environments.
Documentation
use async_trait::async_trait;
use serde_json::Value;
use sigstat::log_event_payload::{LogEventPayload, LogEventRequest};
use sigstat::{EventLoggingAdapter, StatsigErr, StatsigRuntime};
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use tokio::sync::Mutex;

pub struct MockEventLoggingAdapter {
    pub logged_event_count: AtomicU64,
    pub logged_payloads: Mutex<Vec<LogEventPayload>>,
}

impl Default for MockEventLoggingAdapter {
    fn default() -> Self {
        Self::new()
    }
}

impl MockEventLoggingAdapter {
    pub fn new() -> Self {
        Self {
            logged_event_count: AtomicU64::new(0),
            logged_payloads: Mutex::new(Vec::new()),
        }
    }

    pub async fn force_get_first_event(&self) -> HashMap<String, Value> {
        let first_payload = self.force_get_received_payloads().await;
        let non_diagnostic_events = self.filter_non_diagnostic_events(&first_payload);
        let first_event = non_diagnostic_events
            .first()
            .expect("No non-diagnostic events found!");

        let event_obj = first_event.as_object().unwrap();

        event_obj
            .iter()
            .map(|(k, v)| (k.clone(), v.clone()))
            .collect()
    }

    pub async fn force_get_received_payloads(&self) -> LogEventPayload {
        self.logged_payloads.lock().await.first().unwrap().clone()
    }

    fn filter_non_diagnostic_events(&self, payload: &LogEventPayload) -> Vec<Value> {
        let empty_vec = Vec::new();
        let events = payload.events.as_array().unwrap_or(&empty_vec);
        events
            .iter()
            .filter(|event| {
                if let Some(obj) = event.as_object() {
                    if let Some(event_name) = obj.get("eventName") {
                        return event_name != &Value::String("statsig::diagnostics".to_string());
                    }
                }
                false
            })
            .cloned()
            .collect()
    }
}

#[async_trait]
impl EventLoggingAdapter for MockEventLoggingAdapter {
    async fn start(&self, _statsig_runtime: &Arc<StatsigRuntime>) -> Result<(), StatsigErr> {
        Ok(())
    }

    async fn log_events(&self, request: LogEventRequest) -> Result<bool, StatsigErr> {
        let mut payloads = self.logged_payloads.lock().await;

        self.logged_event_count
            .fetch_add(request.event_count, Ordering::SeqCst);
        payloads.push(request.payload);

        Ok(true)
    }

    async fn shutdown(&self) -> Result<(), StatsigErr> {
        Ok(())
    }

    fn should_schedule_background_flush(&self) -> bool {
        true
    }
}