nimbus/stateful/
targeting.rs
1use crate::stateful::gecko_prefs::GeckoPrefStore;
6use crate::{
7 enrollment::ExperimentEnrollment,
8 error::{warn, BehaviorError},
9 json::JsonObject,
10 stateful::behavior::{EventQueryType, EventStore},
11 NimbusError, NimbusTargetingHelper, Result, TargetingAttributes,
12};
13use std::collections::HashMap;
14use std::sync::{Arc, Mutex};
15
16impl NimbusTargetingHelper {
17 pub(crate) fn with_targeting_attributes(
18 targeting_attributes: &TargetingAttributes,
19 event_store: Arc<Mutex<EventStore>>,
20 pref_store: Option<Arc<GeckoPrefStore>>,
21 ) -> Self {
22 Self {
23 context: serde_json::to_value(targeting_attributes.clone()).unwrap(),
24 event_store,
25 gecko_pref_store: pref_store,
26 targeting_attributes: Some(targeting_attributes.clone()),
27 }
28 }
29
30 pub(crate) fn update_enrollment(&mut self, enrollment: &ExperimentEnrollment) -> bool {
31 if let Some(ref mut targeting_attributes) = self.targeting_attributes {
32 targeting_attributes.update_enrollment(enrollment);
33
34 self.context = serde_json::to_value(targeting_attributes.clone()).unwrap();
35 true
36 } else {
37 false
38 }
39 }
40}
41
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}