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
65impl dyn RecordedContext {
66 pub fn execute_queries(
67 &self,
68 nimbus_targeting_helper: &NimbusTargetingHelper,
69 ) -> Result<HashMap<String, f64>> {
70 let results: HashMap<String, f64> =
71 HashMap::from_iter(self.get_event_queries().iter().filter_map(|(key, query)| {
72 match nimbus_targeting_helper.evaluate_jexl_raw_value(query) {
73 Ok(result) => match result.as_f64() {
74 Some(v) => Some((key.clone(), v)),
75 None => {
76 warn!(
77 "Value '{}' for query '{}' was not a string",
78 result.to_string(),
79 query
80 );
81 None
82 }
83 },
84 Err(err) => {
85 let error_string = format!(
86 "error during jexl evaluation for query '{}' — {}",
87 query, err
88 );
89 warn!("{}", error_string);
90 None
91 }
92 }
93 }));
94 self.set_event_query_values(results.clone());
95 Ok(results)
96 }
97
98 pub fn validate_queries(&self) -> Result<()> {
99 for query in self.get_event_queries().values() {
100 match EventQueryType::validate_query(query) {
101 Ok(true) => continue,
102 Ok(false) => {
103 return Err(NimbusError::BehaviorError(
104 BehaviorError::EventQueryParseError(query.clone()),
105 ));
106 }
107 Err(err) => return Err(err),
108 }
109 }
110 Ok(())
111 }
112}
113
114pub fn validate_event_queries(recorded_context: Arc<dyn RecordedContext>) -> Result<()> {
115 recorded_context.validate_queries()
116}