use galaxyui_core::{AppContext, Entity, SingletonEntity}; #[doc(hidden)] #[cfg(not(target_family = "wasm"))] pub use inventory::submit; use serde_json::Value; use strum::IntoEnumIterator; use crate::features::FeatureFlag; pub trait TelemetryEvent: RegisteredTelemetryEvent { fn name(&self) -> &'static str; fn payload(&self) -> Option; fn description(&self) -> &'static str; fn enablement_state(&self) -> EnablementState; fn contains_ugc(&self) -> bool; fn event_descs() -> impl Iterator>; } #[macro_export] macro_rules! register_telemetry_event { ($event:ty) => { impl $crate::telemetry::RegisteredTelemetryEvent for $event {} #[cfg(not(target_family = "wasm"))] $crate::telemetry::submit! { $crate::telemetry::TelemetryEventRegistration::<$event>::adapt() } }; } pub trait RegisteredTelemetryEvent {} pub trait TelemetryEventDesc: std::fmt::Debug { fn name(&self) -> &'static str; fn description(&self) -> &'static str; fn enablement_state(&self) -> EnablementState; } #[doc(hidden)] pub trait AnyTelemetryEventRegistration: Sync { fn events(&self) -> Box>>; } #[doc(hidden)] pub struct TelemetryEventRegistration { _marker: std::marker::PhantomData T>, } impl TelemetryEventRegistration { pub const fn adapt() -> &'static dyn AnyTelemetryEventRegistration { &Self { _marker: std::marker::PhantomData, } } } impl AnyTelemetryEventRegistration for TelemetryEventRegistration { fn events(&self) -> Box>> { Box::new(T::event_descs()) } } pub fn enum_events() -> impl Iterator> where T: strum::IntoDiscriminant, T::Discriminant: strum::IntoEnumIterator + TelemetryEventDesc + 'static, { T::Discriminant::iter() .map(|discriminant| Box::new(discriminant) as Box) } #[cfg(not(target_family = "wasm"))] inventory::collect!(&'static dyn AnyTelemetryEventRegistration); #[cfg(not(target_family = "wasm"))] pub fn all_events() -> impl Iterator> { inventory::iter::<&'static dyn AnyTelemetryEventRegistration>().flat_map(|meta| meta.events()) } /// No-op: telemetry has been removed from Galaxy. #[macro_export] macro_rules! send_telemetry_from_ctx { ($event:expr, $ctx:expr) => { let _ = &$event; let _ = &$ctx; }; } /// No-op: telemetry has been removed from Galaxy. #[macro_export] macro_rules! send_telemetry_from_app_ctx { ($event:expr, $app_ctx:expr) => { let _ = &$event; let _ = &$app_ctx; }; } #[derive(Debug)] pub enum EnablementState { Always, Flag(FeatureFlag), ChannelSpecific { channels: Vec, }, } impl EnablementState { pub fn is_enabled(&self) -> bool { false } } pub trait TelemetryContextProvider { fn user_id(&self, ctx: &AppContext) -> Option; fn anonymous_id(&self, ctx: &AppContext) -> String; } pub type TelemetryContextModel = Box; impl Entity for TelemetryContextModel { type Event = (); } impl SingletonEntity for TelemetryContextModel {} #[cfg(any(test, feature = "test-util"))] pub mod testing { use galaxyui_core::AppContext; use crate::telemetry::{TelemetryContextModel, TelemetryContextProvider}; pub struct MockTelemetryContextProvider { anonymous_id: String, } impl MockTelemetryContextProvider { pub fn register(ctx: &mut AppContext) { ctx.add_singleton_model(|_ctx| { let anonymous_id = "mock-anonymous-id".to_string(); let provider: TelemetryContextModel = Box::new(Self { anonymous_id }); provider }); } } impl TelemetryContextProvider for MockTelemetryContextProvider { fn user_id(&self, _ctx: &AppContext) -> Option { None } fn anonymous_id(&self, _ctx: &AppContext) -> String { self.anonymous_id.clone() } } }