gsm-core 0.4.17

Core types and platform abstractions for the Greentic messaging runtime.
Documentation
use crate::messaging_card::tier::Tier;

#[derive(Debug, Clone, PartialEq)]
pub enum TelemetryEvent {
    Rendered {
        platform: String,
        tier: Tier,
        warnings: usize,
        used_modal: bool,
        limit_exceeded: bool,
        sanitized_count: usize,
        url_blocked_count: usize,
        downgrade_count: usize,
        native_count: usize,
    },
    Downgraded {
        from: Tier,
        to: Tier,
    },
}

pub trait TelemetryHook: Send + Sync {
    fn emit(&self, event: TelemetryEvent);
}

#[derive(Default)]
pub struct NullTelemetry;

impl TelemetryHook for NullTelemetry {
    fn emit(&self, _event: TelemetryEvent) {}
}

pub struct CardTelemetry<'a> {
    hook: &'a dyn TelemetryHook,
}

impl<'a> CardTelemetry<'a> {
    pub fn new(hook: &'a dyn TelemetryHook) -> Self {
        Self { hook }
    }

    pub fn downgrading(&self, from: Tier, to: Tier) {
        self.hook.emit(TelemetryEvent::Downgraded { from, to });
    }

    #[allow(clippy::too_many_arguments)]
    pub fn rendered(
        &self,
        platform: &str,
        tier: Tier,
        warnings: usize,
        used_modal: bool,
        limit_exceeded: bool,
        sanitized_count: usize,
        url_blocked_count: usize,
        downgraded: bool,
    ) {
        let downgrade_count = if downgraded { 1 } else { 0 };
        let native_count = if downgraded { 0 } else { 1 };
        self.hook.emit(TelemetryEvent::Rendered {
            platform: platform.to_string(),
            tier,
            warnings,
            used_modal,
            limit_exceeded,
            sanitized_count,
            url_blocked_count,
            downgrade_count,
            native_count,
        });
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    struct TestTelemetry {
        pub events: std::sync::Mutex<Vec<TelemetryEvent>>,
    }

    impl TestTelemetry {
        fn new() -> Self {
            Self {
                events: std::sync::Mutex::new(Vec::new()),
            }
        }
    }

    impl TelemetryHook for TestTelemetry {
        fn emit(&self, event: TelemetryEvent) {
            self.events.lock().unwrap().push(event);
        }
    }

    #[test]
    fn telemetry_records_events() {
        let hook = TestTelemetry::new();
        let telemetry = CardTelemetry::new(&hook);
        telemetry.downgrading(Tier::Premium, Tier::Basic);
        telemetry.rendered("teams", Tier::Basic, 1, true, false, 0, 0, false);
        let events = hook.events.lock().unwrap();
        assert_eq!(events.len(), 2);
    }
}