Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 14be78d

Browse files
authored
Support for MSC3758: exact_event_match push condition (#14964)
This specifies to search for an exact value match, instead of string globbing. It only works across non-compound JSON values (null, boolean, integer, and strings).
1 parent cf5233b commit 14be78d

File tree

9 files changed

+356
-41
lines changed

9 files changed

+356
-41
lines changed

changelog.d/14964.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement the experimental `exact_event_match` push rule condition from [MSC3758](https://github.com/matrix-org/matrix-spec-proposals/pull/3758).

rust/benches/evaluator.rs

+53-12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use std::collections::BTreeSet;
1717
use synapse::push::{
1818
evaluator::PushRuleEvaluator, Condition, EventMatchCondition, FilteredPushRules, PushRules,
19+
SimpleJsonValue,
1920
};
2021
use test::Bencher;
2122

@@ -24,9 +25,18 @@ extern crate test;
2425
#[bench]
2526
fn bench_match_exact(b: &mut Bencher) {
2627
let flattened_keys = [
27-
("type".to_string(), "m.text".to_string()),
28-
("room_id".to_string(), "!room:server".to_string()),
29-
("content.body".to_string(), "test message".to_string()),
28+
(
29+
"type".to_string(),
30+
SimpleJsonValue::Str("m.text".to_string()),
31+
),
32+
(
33+
"room_id".to_string(),
34+
SimpleJsonValue::Str("!room:server".to_string()),
35+
),
36+
(
37+
"content.body".to_string(),
38+
SimpleJsonValue::Str("test message".to_string()),
39+
),
3040
]
3141
.into_iter()
3242
.collect();
@@ -43,6 +53,7 @@ fn bench_match_exact(b: &mut Bencher) {
4353
true,
4454
vec![],
4555
false,
56+
false,
4657
)
4758
.unwrap();
4859

@@ -63,9 +74,18 @@ fn bench_match_exact(b: &mut Bencher) {
6374
#[bench]
6475
fn bench_match_word(b: &mut Bencher) {
6576
let flattened_keys = [
66-
("type".to_string(), "m.text".to_string()),
67-
("room_id".to_string(), "!room:server".to_string()),
68-
("content.body".to_string(), "test message".to_string()),
77+
(
78+
"type".to_string(),
79+
SimpleJsonValue::Str("m.text".to_string()),
80+
),
81+
(
82+
"room_id".to_string(),
83+
SimpleJsonValue::Str("!room:server".to_string()),
84+
),
85+
(
86+
"content.body".to_string(),
87+
SimpleJsonValue::Str("test message".to_string()),
88+
),
6989
]
7090
.into_iter()
7191
.collect();
@@ -82,6 +102,7 @@ fn bench_match_word(b: &mut Bencher) {
82102
true,
83103
vec![],
84104
false,
105+
false,
85106
)
86107
.unwrap();
87108

@@ -102,9 +123,18 @@ fn bench_match_word(b: &mut Bencher) {
102123
#[bench]
103124
fn bench_match_word_miss(b: &mut Bencher) {
104125
let flattened_keys = [
105-
("type".to_string(), "m.text".to_string()),
106-
("room_id".to_string(), "!room:server".to_string()),
107-
("content.body".to_string(), "test message".to_string()),
126+
(
127+
"type".to_string(),
128+
SimpleJsonValue::Str("m.text".to_string()),
129+
),
130+
(
131+
"room_id".to_string(),
132+
SimpleJsonValue::Str("!room:server".to_string()),
133+
),
134+
(
135+
"content.body".to_string(),
136+
SimpleJsonValue::Str("test message".to_string()),
137+
),
108138
]
109139
.into_iter()
110140
.collect();
@@ -121,6 +151,7 @@ fn bench_match_word_miss(b: &mut Bencher) {
121151
true,
122152
vec![],
123153
false,
154+
false,
124155
)
125156
.unwrap();
126157

@@ -141,9 +172,18 @@ fn bench_match_word_miss(b: &mut Bencher) {
141172
#[bench]
142173
fn bench_eval_message(b: &mut Bencher) {
143174
let flattened_keys = [
144-
("type".to_string(), "m.text".to_string()),
145-
("room_id".to_string(), "!room:server".to_string()),
146-
("content.body".to_string(), "test message".to_string()),
175+
(
176+
"type".to_string(),
177+
SimpleJsonValue::Str("m.text".to_string()),
178+
),
179+
(
180+
"room_id".to_string(),
181+
SimpleJsonValue::Str("!room:server".to_string()),
182+
),
183+
(
184+
"content.body".to_string(),
185+
SimpleJsonValue::Str("test message".to_string()),
186+
),
147187
]
148188
.into_iter()
149189
.collect();
@@ -160,6 +200,7 @@ fn bench_eval_message(b: &mut Bencher) {
160200
true,
161201
vec![],
162202
false,
203+
false,
163204
)
164205
.unwrap();
165206

rust/src/push/evaluator.rs

+54-15
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use regex::Regex;
2222

2323
use super::{
2424
utils::{get_glob_matcher, get_localpart_from_id, GlobMatchType},
25-
Action, Condition, EventMatchCondition, FilteredPushRules, KnownCondition,
26-
RelatedEventMatchCondition,
25+
Action, Condition, EventMatchCondition, ExactEventMatchCondition, FilteredPushRules,
26+
KnownCondition, RelatedEventMatchCondition, SimpleJsonValue,
2727
};
2828

2929
lazy_static! {
@@ -61,9 +61,9 @@ impl RoomVersionFeatures {
6161
/// Allows running a set of push rules against a particular event.
6262
#[pyclass]
6363
pub struct PushRuleEvaluator {
64-
/// A mapping of "flattened" keys to string values in the event, e.g.
64+
/// A mapping of "flattened" keys to simple JSON values in the event, e.g.
6565
/// includes things like "type" and "content.msgtype".
66-
flattened_keys: BTreeMap<String, String>,
66+
flattened_keys: BTreeMap<String, SimpleJsonValue>,
6767

6868
/// The "content.body", if any.
6969
body: String,
@@ -87,7 +87,7 @@ pub struct PushRuleEvaluator {
8787

8888
/// The related events, indexed by relation type. Flattened in the same manner as
8989
/// `flattened_keys`.
90-
related_events_flattened: BTreeMap<String, BTreeMap<String, String>>,
90+
related_events_flattened: BTreeMap<String, BTreeMap<String, SimpleJsonValue>>,
9191

9292
/// If msc3664, push rules for related events, is enabled.
9393
related_event_match_enabled: bool,
@@ -98,6 +98,9 @@ pub struct PushRuleEvaluator {
9898
/// If MSC3931 (room version feature flags) is enabled. Usually controlled by the same
9999
/// flag as MSC1767 (extensible events core).
100100
msc3931_enabled: bool,
101+
102+
/// If MSC3758 (exact_event_match push rule condition) is enabled.
103+
msc3758_exact_event_match: bool,
101104
}
102105

103106
#[pymethods]
@@ -106,22 +109,23 @@ impl PushRuleEvaluator {
106109
#[allow(clippy::too_many_arguments)]
107110
#[new]
108111
pub fn py_new(
109-
flattened_keys: BTreeMap<String, String>,
112+
flattened_keys: BTreeMap<String, SimpleJsonValue>,
110113
has_mentions: bool,
111114
user_mentions: BTreeSet<String>,
112115
room_mention: bool,
113116
room_member_count: u64,
114117
sender_power_level: Option<i64>,
115118
notification_power_levels: BTreeMap<String, i64>,
116-
related_events_flattened: BTreeMap<String, BTreeMap<String, String>>,
119+
related_events_flattened: BTreeMap<String, BTreeMap<String, SimpleJsonValue>>,
117120
related_event_match_enabled: bool,
118121
room_version_feature_flags: Vec<String>,
119122
msc3931_enabled: bool,
123+
msc3758_exact_event_match: bool,
120124
) -> Result<Self, Error> {
121-
let body = flattened_keys
122-
.get("content.body")
123-
.cloned()
124-
.unwrap_or_default();
125+
let body = match flattened_keys.get("content.body") {
126+
Some(SimpleJsonValue::Str(s)) => s.clone(),
127+
_ => String::new(),
128+
};
125129

126130
Ok(PushRuleEvaluator {
127131
flattened_keys,
@@ -136,6 +140,7 @@ impl PushRuleEvaluator {
136140
related_event_match_enabled,
137141
room_version_feature_flags,
138142
msc3931_enabled,
143+
msc3758_exact_event_match,
139144
})
140145
}
141146

@@ -252,6 +257,9 @@ impl PushRuleEvaluator {
252257
KnownCondition::EventMatch(event_match) => {
253258
self.match_event_match(event_match, user_id)?
254259
}
260+
KnownCondition::ExactEventMatch(exact_event_match) => {
261+
self.match_exact_event_match(exact_event_match)?
262+
}
255263
KnownCondition::RelatedEventMatch(event_match) => {
256264
self.match_related_event_match(event_match, user_id)?
257265
}
@@ -337,7 +345,9 @@ impl PushRuleEvaluator {
337345
return Ok(false);
338346
};
339347

340-
let haystack = if let Some(haystack) = self.flattened_keys.get(&*event_match.key) {
348+
let haystack = if let Some(SimpleJsonValue::Str(haystack)) =
349+
self.flattened_keys.get(&*event_match.key)
350+
{
341351
haystack
342352
} else {
343353
return Ok(false);
@@ -355,6 +365,27 @@ impl PushRuleEvaluator {
355365
compiled_pattern.is_match(haystack)
356366
}
357367

368+
/// Evaluates a `exact_event_match` condition. (MSC3758)
369+
fn match_exact_event_match(
370+
&self,
371+
exact_event_match: &ExactEventMatchCondition,
372+
) -> Result<bool, Error> {
373+
// First check if the feature is enabled.
374+
if !self.msc3758_exact_event_match {
375+
return Ok(false);
376+
}
377+
378+
let value = &exact_event_match.value;
379+
380+
let haystack = if let Some(haystack) = self.flattened_keys.get(&*exact_event_match.key) {
381+
haystack
382+
} else {
383+
return Ok(false);
384+
};
385+
386+
Ok(haystack == &**value)
387+
}
388+
358389
/// Evaluates a `related_event_match` condition. (MSC3664)
359390
fn match_related_event_match(
360391
&self,
@@ -410,7 +441,7 @@ impl PushRuleEvaluator {
410441
return Ok(false);
411442
};
412443

413-
let haystack = if let Some(haystack) = event.get(&**key) {
444+
let haystack = if let Some(SimpleJsonValue::Str(haystack)) = event.get(&**key) {
414445
haystack
415446
} else {
416447
return Ok(false);
@@ -455,7 +486,10 @@ impl PushRuleEvaluator {
455486
#[test]
456487
fn push_rule_evaluator() {
457488
let mut flattened_keys = BTreeMap::new();
458-
flattened_keys.insert("content.body".to_string(), "foo bar bob hello".to_string());
489+
flattened_keys.insert(
490+
"content.body".to_string(),
491+
SimpleJsonValue::Str("foo bar bob hello".to_string()),
492+
);
459493
let evaluator = PushRuleEvaluator::py_new(
460494
flattened_keys,
461495
false,
@@ -468,6 +502,7 @@ fn push_rule_evaluator() {
468502
true,
469503
vec![],
470504
true,
505+
true,
471506
)
472507
.unwrap();
473508

@@ -482,7 +517,10 @@ fn test_requires_room_version_supports_condition() {
482517
use crate::push::{PushRule, PushRules};
483518

484519
let mut flattened_keys = BTreeMap::new();
485-
flattened_keys.insert("content.body".to_string(), "foo bar bob hello".to_string());
520+
flattened_keys.insert(
521+
"content.body".to_string(),
522+
SimpleJsonValue::Str("foo bar bob hello".to_string()),
523+
);
486524
let flags = vec![RoomVersionFeatures::ExtensibleEvents.as_str().to_string()];
487525
let evaluator = PushRuleEvaluator::py_new(
488526
flattened_keys,
@@ -496,6 +534,7 @@ fn test_requires_room_version_supports_condition() {
496534
false,
497535
flags,
498536
true,
537+
true,
499538
)
500539
.unwrap();
501540

0 commit comments

Comments
 (0)