1extern crate core;
2
3use std::ops::Deref;
4use std::sync::{Arc, RwLock};
5
6use lazy_static::lazy_static;
7use serde::de::DeserializeOwned;
8use serde_json::Value;
9
10use statsig::internal::StatsigDriver;
11use statsig::statsig_error::StatsigError;
12pub use statsig::statsig_datastore::StatsigDatastore;
15pub use statsig::statsig_event::StatsigEvent;
16pub use statsig::statsig_options::StatsigOptions;
17pub use statsig::statsig_user::StatsigUser;
18pub use statsig::internal::{DynamicConfig, FeatureGate, Layer};
19pub use crate::statsig::internal::{EvalDetails, EvaluationReason};
20use futures::future::Shared;
21use futures::FutureExt;
22use tokio::sync::futures::Notified;
23use tokio::sync::Notify;
24use tokio::task::spawn_blocking;
25
26use crate::statsig::internal::LayerLogData;
27
28mod statsig;
29
30lazy_static! {
31 static ref DRIVER: Arc<RwLock<Option<StatsigDriver>>> = Arc::from(RwLock::from(None));
32 static ref STATSIG_INIT_NOTIFY: Arc<Notify> = Arc::new(Notify::new());
33 static ref STATSIG_INIT_NOTIFIED_FUTURE: Shared<Notified<'static>> =
34 STATSIG_INIT_NOTIFY.notified().shared();
35}
36
37pub struct Statsig {}
38
39impl Statsig {
40 pub async fn initialize(secret: &str) -> Option<StatsigError> {
41 Self::initialize_with_options(secret, StatsigOptions::default()).await
42 }
43
44 pub async fn initialize_with_options(
45 secret: &str,
46 options: StatsigOptions,
47 ) -> Option<StatsigError> {
48 match DRIVER.read().ok() {
49 Some(read_guard) => {
50 if read_guard.is_some() {
51 return Some(StatsigError::AlreadyInitialized);
52 }
53 }
54 None => {
55 return Some(StatsigError::SingletonLockFailure);
56 }
57 }
58
59 let driver = unwrap_or_return!(
60 StatsigDriver::new(secret, options).ok(),
61 Some(StatsigError::InstantiationFailure)
62 );
63
64 driver.initialize().await;
65
66 let mut write_guard = unwrap_or_return!(
67 DRIVER.write().ok(),
68 Some(StatsigError::SingletonLockFailure)
69 );
70
71 *write_guard = Some(driver);
72
73 STATSIG_INIT_NOTIFY.notify_waiters();
74
75 None
76 }
77
78 pub fn is_initialized() -> bool {
79 DRIVER.read().map_or(false, |guard| guard.is_some())
80 }
81
82 pub fn wait_for_initialization() -> Shared<Notified<'static>> {
83 STATSIG_INIT_NOTIFIED_FUTURE.clone()
84 }
85
86 pub async fn shutdown() -> Option<StatsigError> {
87 let driver_clone = Arc::clone(&DRIVER);
88 match spawn_blocking(move || {
89 let mut write_guard = unwrap_or_return!(
90 driver_clone.write().ok(),
91 Err(StatsigError::SingletonLockFailure)
92 );
93
94 if let Some(driver) = write_guard.take() {
95 driver.shutdown();
96 }
97 Ok(())
98 })
99 .await
100 {
101 Ok(_t) => None,
102 Err(_e) => Some(StatsigError::ShutdownFailure),
103 }
104 }
105
106 pub fn check_gate(user: &StatsigUser, gate_name: &str) -> Result<bool, StatsigError> {
107 Self::use_driver(|driver| Ok(driver.check_gate(user, gate_name)))
108 }
109
110 pub fn get_feature_gate(user: &StatsigUser, gate_name: &str) -> Result<FeatureGate, StatsigError> {
111 Self::use_driver(|driver| Ok(driver.get_feature_gate(user, gate_name)))
112 }
113
114 pub fn get_config<T: DeserializeOwned>(
115 user: &StatsigUser,
116 config_name: &str,
117 ) -> Result<DynamicConfig<T>, StatsigError> {
118 Self::use_driver(|driver| Ok(driver.get_config(user, config_name)))
119 }
120
121 pub fn get_experiment<T: DeserializeOwned>(
122 user: &StatsigUser,
123 experiment_name: &str,
124 ) -> Result<DynamicConfig<T>, StatsigError> {
125 Self::get_config(user, experiment_name)
126 }
127
128 pub fn get_layer(user: &StatsigUser, layer_name: &str) -> Result<Layer, StatsigError> {
129 Self::use_driver(|driver| Ok(driver.get_layer(user, layer_name)))
130 }
131
132 pub fn log_event(user: &StatsigUser, event: StatsigEvent) -> Option<StatsigError> {
133 let res = Self::use_driver(move |driver| {
134 driver.log_event(user, event);
135 Ok(())
136 });
137
138 match res {
139 Err(e) => Some(e),
140 _ => None,
141 }
142 }
143
144 pub fn get_client_initialize_response(user: &StatsigUser) -> Result<Value, StatsigError> {
145 Self::use_driver(|driver| Ok(driver.get_client_initialize_response(user)))
146 }
147
148 pub(crate) fn log_layer_parameter_exposure(
149 layer: &Layer,
150 parameter_name: &str,
151 log_data: &LayerLogData,
152 ) {
153 let _ = Self::use_driver(|driver| {
154 driver.log_layer_parameter_exposure(layer, parameter_name, log_data);
155 Ok(())
156 });
157 }
158
159 fn use_driver<T>(
160 func: impl FnOnce(&StatsigDriver) -> Result<T, StatsigError>,
161 ) -> Result<T, StatsigError> {
162 if let Ok(guard) = DRIVER.read() {
163 if let Some(driver) = guard.deref() {
164 return func(driver);
165 }
166 return Err(StatsigError::Uninitialized);
167 }
168 Err(StatsigError::SingletonLockFailure)
169 }
170
171 #[doc(hidden)]
172 #[cfg(statsig_kong)]
173 pub async fn __unsafe_reset() {
174 if let Some(mut guard) = DRIVER.write().ok() {
175 if let Some(driver) = guard.take() {
176 let _ = spawn_blocking(move || {
177 driver.shutdown();
178 })
179 .await;
180 }
181 }
182 }
183}