statsig_rust/
global_configs.rs1use crate::{log_e, DynamicValue};
2use lazy_static::lazy_static;
3use parking_lot::RwLock;
4use std::{
5 collections::HashMap,
6 sync::{Arc, Weak},
7 time::Duration,
8};
9
10const TAG: &str = stringify!(GlobalConfigs);
11
12pub const MAX_SAMPLING_RATE: f64 = 10000.0;
13
14lazy_static! {
15 static ref GLOBAL_CONFIG_INSTANCES: RwLock<HashMap<String, Weak<GlobalConfigs>>> =
16 RwLock::new(HashMap::new());
17}
18
19struct Configs {
20 sdk_configs: HashMap<String, DynamicValue>,
21 sdk_flags: HashMap<String, bool>,
22 diagnostics_sampling_rates: HashMap<String, f64>,
23}
24
25pub struct GlobalConfigs {
26 configs: RwLock<Configs>,
27}
28
29impl GlobalConfigs {
30 pub fn get_instance(sdk_key: &str) -> Arc<GlobalConfigs> {
31 match GLOBAL_CONFIG_INSTANCES.try_read_for(Duration::from_secs(5)) {
32 Some(read_guard) => {
33 if let Some(instance) = read_guard.get(sdk_key) {
34 if let Some(instance) = instance.upgrade() {
35 return instance.clone();
36 }
37 }
38 }
39 None => {
40 log_e!(
41 TAG,
42 "Failed to get read guard: Failed to lock GLOBAL_CONFIG_INSTANCES"
43 );
44 }
45 }
46
47 let instance = Arc::new(GlobalConfigs {
48 configs: RwLock::new(Configs {
49 sdk_configs: HashMap::new(),
50 sdk_flags: HashMap::new(),
51 diagnostics_sampling_rates: HashMap::from([
52 ("initialize".to_string(), 10000.0),
53 ("config_sync".to_string(), 1000.0),
54 ("dcs".to_string(), 1000.0),
55 ("get_id_list".to_string(), 100.0), ]),
57 }),
58 });
59
60 match GLOBAL_CONFIG_INSTANCES.try_write_for(Duration::from_secs(5)) {
61 Some(mut write_guard) => {
62 write_guard.insert(sdk_key.into(), Arc::downgrade(&instance));
63 }
64 None => {
65 log_e!(
66 TAG,
67 "Failed to get write guard: Failed to lock GLOBAL_CONFIG_INSTANCES"
68 );
69 }
70 }
71
72 instance
73 }
74
75 pub fn set_sdk_configs(&self, new_configs: HashMap<String, DynamicValue>) {
76 match self.configs.try_write_for(Duration::from_secs(5)) {
77 Some(mut configs_guard) => {
78 for (key, value) in new_configs {
79 configs_guard.sdk_configs.insert(key, value);
80 }
81 }
82 None => {
83 log_e!(TAG, "Failed to get write guard: Failed to lock configs");
84 }
85 }
86 }
87
88 pub fn set_sdk_flags(&self, new_configs: HashMap<String, bool>) {
89 match self.configs.try_write_for(Duration::from_secs(5)) {
90 Some(mut configs_guard) => {
91 for (key, value) in new_configs {
92 configs_guard.sdk_flags.insert(key, value);
93 }
94 }
95 None => {
96 log_e!(TAG, "Failed to get write guard: Failed to lock configs");
97 }
98 }
99 }
100
101 pub fn set_diagnostics_sampling_rates(&self, new_sampling_rate: HashMap<String, f64>) {
102 match self.configs.try_write_for(Duration::from_secs(5)) {
103 Some(mut configs_guard) => {
104 for (key, rate) in new_sampling_rate {
105 let clamped_rate = rate.clamp(0.0, MAX_SAMPLING_RATE);
106 configs_guard
107 .diagnostics_sampling_rates
108 .insert(key, clamped_rate);
109 }
110 }
111 None => {
112 log_e!(TAG, "Failed to get write guard: Failed to lock configs");
113 }
114 }
115 }
116
117 pub fn use_sdk_config_value<T>(
118 &self,
119 key: &str,
120 f: impl FnOnce(Option<&DynamicValue>) -> T,
121 ) -> T {
122 match self.configs.try_read_for(Duration::from_secs(5)) {
123 Some(configs_guard) => f(configs_guard.sdk_configs.get(key)),
124 None => {
125 log_e!(TAG, "Failed to get read guard: Failed to lock configs");
126 f(None)
127 }
128 }
129 }
130
131 pub fn use_diagnostics_sampling_rate<T>(
132 &self,
133 key: &str,
134 f: impl FnOnce(Option<&f64>) -> T,
135 ) -> T {
136 match self.configs.try_read_for(Duration::from_secs(5)) {
137 Some(configs_guard) => f(configs_guard.diagnostics_sampling_rates.get(key)),
138 None => {
139 log_e!(TAG, "Failed to get read guard: Failed to lock configs");
140 f(None)
141 }
142 }
143 }
144
145 pub fn get_sdk_flag_value(&self, key: &str) -> bool {
146 match self.configs.try_read_for(Duration::from_secs(5)) {
147 Some(configs_guard) => *configs_guard.sdk_flags.get(key).unwrap_or(&false),
148 None => {
149 log_e!(TAG, "Failed to get read guard: Failed to lock configs");
150 false
151 }
152 }
153 }
154}