nimbus/stateful/
targeting.rs1use std::collections::HashMap;
6use std::sync::{Arc, Mutex};
7
8use crate::enrollment::ExperimentEnrollment;
9use crate::error::{BehaviorError, warn};
10use crate::json::JsonObject;
11use crate::stateful::behavior::{EventQueryType, EventStore};
12use crate::stateful::gecko_prefs::GeckoPrefStore;
13use crate::{NimbusError, NimbusTargetingHelper, Result, TargetingAttributes};
14
15impl NimbusTargetingHelper {
16 pub(crate) fn with_targeting_attributes(
17 targeting_attributes: &TargetingAttributes,
18 event_store: Arc<Mutex<EventStore>>,
19 pref_store: Option<Arc<GeckoPrefStore>>,
20 ) -> Self {
21 Self {
22 context: serde_json::to_value(targeting_attributes.clone()).unwrap(),
23 event_store,
24 gecko_pref_store: pref_store,
25 targeting_attributes: Some(targeting_attributes.clone()),
26 }
27 }
28
29 pub(crate) fn update_enrollment(&mut self, enrollment: &ExperimentEnrollment) -> bool {
30 if let Some(ref mut targeting_attributes) = self.targeting_attributes {
31 targeting_attributes.update_enrollment(enrollment);
32
33 self.context = serde_json::to_value(targeting_attributes.clone()).unwrap();
34 true
35 } else {
36 false
37 }
38 }
39}
40
41#[uniffi::trait_interface]
42pub trait RecordedContext: Send + Sync {
43 fn to_json(&self) -> JsonObject;
47
48 fn get_event_queries(&self) -> HashMap<String, String>;
53
54 fn set_event_query_values(&self, event_query_values: HashMap<String, f64>);
58
59 fn record(&self);
63}
64
65pub fn execute_event_queries(
66 recorded_context: &dyn RecordedContext,
67 nimbus_targeting_helper: &NimbusTargetingHelper,
68) -> Result<HashMap<String, f64>> {
69 let results: HashMap<String, f64> =
70 HashMap::from_iter(recorded_context.get_event_queries().iter().filter_map(
71 |(key, query)| match nimbus_targeting_helper.evaluate_jexl_raw_value(query) {
72 Ok(result) => match result.as_f64() {
73 Some(v) => Some((key.clone(), v)),
74 None => {
75 warn!(
76 "Value '{}' for query '{}' was not a string",
77 result.to_string(),
78 query
79 );
80 None
81 }
82 },
83 Err(err) => {
84 let error_string = format!(
85 "error during jexl evaluation for query '{}' — {}",
86 query, err
87 );
88 warn!("{}", error_string);
89 None
90 }
91 },
92 ));
93 recorded_context.set_event_query_values(results.clone());
94 Ok(results)
95}
96
97pub fn validate_event_queries(recorded_context: Arc<dyn RecordedContext>) -> Result<()> {
98 for query in recorded_context.get_event_queries().values() {
99 match EventQueryType::validate_query(query) {
100 Ok(true) => continue,
101 Ok(false) => {
102 return Err(NimbusError::BehaviorError(
103 BehaviorError::EventQueryParseError(query.clone()),
104 ));
105 }
106 Err(err) => return Err(err),
107 }
108 }
109 Ok(())
110}