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 diagnostics_sampling_rates: HashMap<String, f64>,
22}
23
24pub struct GlobalConfigs {
25 configs: RwLock<Configs>,
26}
27
28impl GlobalConfigs {
29 pub fn get_instance(sdk_key: &str) -> Arc<GlobalConfigs> {
30 match GLOBAL_CONFIG_INSTANCES.try_read_for(Duration::from_secs(5)) {
31 Some(read_guard) => {
32 if let Some(instance) = read_guard.get(sdk_key) {
33 if let Some(instance) = instance.upgrade() {
34 return instance.clone();
35 }
36 }
37 }
38 None => {
39 log_e!(
40 TAG,
41 "Failed to get read guard: Failed to lock GLOBAL_CONFIG_INSTANCES"
42 );
43 }
44 }
45
46 let instance = Arc::new(GlobalConfigs {
47 configs: RwLock::new(Configs {
48 sdk_configs: HashMap::new(),
49 diagnostics_sampling_rates: HashMap::from([
50 ("initialize".to_string(), 10000.0),
51 ("config_sync".to_string(), 1000.0),
52 ("dcs".to_string(), 1000.0),
53 ("get_id_list".to_string(), 100.0), ]),
55 }),
56 });
57
58 match GLOBAL_CONFIG_INSTANCES.try_write_for(Duration::from_secs(5)) {
59 Some(mut write_guard) => {
60 write_guard.insert(sdk_key.into(), Arc::downgrade(&instance));
61 }
62 None => {
63 log_e!(
64 TAG,
65 "Failed to get write guard: Failed to lock GLOBAL_CONFIG_INSTANCES"
66 );
67 }
68 }
69
70 instance
71 }
72
73 pub fn set_sdk_configs(&self, new_configs: HashMap<String, DynamicValue>) {
74 match self.configs.try_write_for(Duration::from_secs(5)) {
75 Some(mut configs_guard) => {
76 for (key, value) in new_configs {
77 configs_guard.sdk_configs.insert(key, value);
78 }
79 }
80 None => {
81 log_e!(TAG, "Failed to get write guard: Failed to lock configs");
82 }
83 }
84 }
85
86 pub fn set_diagnostics_sampling_rates(&self, new_sampling_rate: HashMap<String, f64>) {
87 match self.configs.try_write_for(Duration::from_secs(5)) {
88 Some(mut configs_guard) => {
89 for (key, rate) in new_sampling_rate {
90 let clamped_rate = rate.clamp(0.0, MAX_SAMPLING_RATE);
91 configs_guard
92 .diagnostics_sampling_rates
93 .insert(key, clamped_rate);
94 }
95 }
96 None => {
97 log_e!(TAG, "Failed to get write guard: Failed to lock configs");
98 }
99 }
100 }
101
102 pub fn use_sdk_config_value<T>(
103 &self,
104 key: &str,
105 f: impl FnOnce(Option<&DynamicValue>) -> T,
106 ) -> T {
107 match self.configs.try_read_for(Duration::from_secs(5)) {
108 Some(configs_guard) => f(configs_guard.sdk_configs.get(key)),
109 None => {
110 log_e!(TAG, "Failed to get read guard: Failed to lock configs");
111 f(None)
112 }
113 }
114 }
115
116 pub fn use_diagnostics_sampling_rate<T>(
117 &self,
118 key: &str,
119 f: impl FnOnce(Option<&f64>) -> T,
120 ) -> T {
121 match self.configs.try_read_for(Duration::from_secs(5)) {
122 Some(configs_guard) => f(configs_guard.diagnostics_sampling_rates.get(key)),
123 None => {
124 log_e!(TAG, "Failed to get read guard: Failed to lock configs");
125 f(None)
126 }
127 }
128 }
129}