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

Commit

Permalink
Support for MSC3758: exact_event_match push condition (#14964)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
clokep authored Feb 10, 2023
1 parent cf5233b commit 14be78d
Show file tree
Hide file tree
Showing 9 changed files with 356 additions and 41 deletions.
1 change: 1 addition & 0 deletions changelog.d/14964.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement the experimental `exact_event_match` push rule condition from [MSC3758](https://github.com/matrix-org/matrix-spec-proposals/pull/3758).
65 changes: 53 additions & 12 deletions rust/benches/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use std::collections::BTreeSet;
use synapse::push::{
evaluator::PushRuleEvaluator, Condition, EventMatchCondition, FilteredPushRules, PushRules,
SimpleJsonValue,
};
use test::Bencher;

Expand All @@ -24,9 +25,18 @@ extern crate test;
#[bench]
fn bench_match_exact(b: &mut Bencher) {
let flattened_keys = [
("type".to_string(), "m.text".to_string()),
("room_id".to_string(), "!room:server".to_string()),
("content.body".to_string(), "test message".to_string()),
(
"type".to_string(),
SimpleJsonValue::Str("m.text".to_string()),
),
(
"room_id".to_string(),
SimpleJsonValue::Str("!room:server".to_string()),
),
(
"content.body".to_string(),
SimpleJsonValue::Str("test message".to_string()),
),
]
.into_iter()
.collect();
Expand All @@ -43,6 +53,7 @@ fn bench_match_exact(b: &mut Bencher) {
true,
vec![],
false,
false,
)
.unwrap();

Expand All @@ -63,9 +74,18 @@ fn bench_match_exact(b: &mut Bencher) {
#[bench]
fn bench_match_word(b: &mut Bencher) {
let flattened_keys = [
("type".to_string(), "m.text".to_string()),
("room_id".to_string(), "!room:server".to_string()),
("content.body".to_string(), "test message".to_string()),
(
"type".to_string(),
SimpleJsonValue::Str("m.text".to_string()),
),
(
"room_id".to_string(),
SimpleJsonValue::Str("!room:server".to_string()),
),
(
"content.body".to_string(),
SimpleJsonValue::Str("test message".to_string()),
),
]
.into_iter()
.collect();
Expand All @@ -82,6 +102,7 @@ fn bench_match_word(b: &mut Bencher) {
true,
vec![],
false,
false,
)
.unwrap();

Expand All @@ -102,9 +123,18 @@ fn bench_match_word(b: &mut Bencher) {
#[bench]
fn bench_match_word_miss(b: &mut Bencher) {
let flattened_keys = [
("type".to_string(), "m.text".to_string()),
("room_id".to_string(), "!room:server".to_string()),
("content.body".to_string(), "test message".to_string()),
(
"type".to_string(),
SimpleJsonValue::Str("m.text".to_string()),
),
(
"room_id".to_string(),
SimpleJsonValue::Str("!room:server".to_string()),
),
(
"content.body".to_string(),
SimpleJsonValue::Str("test message".to_string()),
),
]
.into_iter()
.collect();
Expand All @@ -121,6 +151,7 @@ fn bench_match_word_miss(b: &mut Bencher) {
true,
vec![],
false,
false,
)
.unwrap();

Expand All @@ -141,9 +172,18 @@ fn bench_match_word_miss(b: &mut Bencher) {
#[bench]
fn bench_eval_message(b: &mut Bencher) {
let flattened_keys = [
("type".to_string(), "m.text".to_string()),
("room_id".to_string(), "!room:server".to_string()),
("content.body".to_string(), "test message".to_string()),
(
"type".to_string(),
SimpleJsonValue::Str("m.text".to_string()),
),
(
"room_id".to_string(),
SimpleJsonValue::Str("!room:server".to_string()),
),
(
"content.body".to_string(),
SimpleJsonValue::Str("test message".to_string()),
),
]
.into_iter()
.collect();
Expand All @@ -160,6 +200,7 @@ fn bench_eval_message(b: &mut Bencher) {
true,
vec![],
false,
false,
)
.unwrap();

Expand Down
69 changes: 54 additions & 15 deletions rust/src/push/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use regex::Regex;

use super::{
utils::{get_glob_matcher, get_localpart_from_id, GlobMatchType},
Action, Condition, EventMatchCondition, FilteredPushRules, KnownCondition,
RelatedEventMatchCondition,
Action, Condition, EventMatchCondition, ExactEventMatchCondition, FilteredPushRules,
KnownCondition, RelatedEventMatchCondition, SimpleJsonValue,
};

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

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

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

/// If msc3664, push rules for related events, is enabled.
related_event_match_enabled: bool,
Expand All @@ -98,6 +98,9 @@ pub struct PushRuleEvaluator {
/// If MSC3931 (room version feature flags) is enabled. Usually controlled by the same
/// flag as MSC1767 (extensible events core).
msc3931_enabled: bool,

/// If MSC3758 (exact_event_match push rule condition) is enabled.
msc3758_exact_event_match: bool,
}

#[pymethods]
Expand All @@ -106,22 +109,23 @@ impl PushRuleEvaluator {
#[allow(clippy::too_many_arguments)]
#[new]
pub fn py_new(
flattened_keys: BTreeMap<String, String>,
flattened_keys: BTreeMap<String, SimpleJsonValue>,
has_mentions: bool,
user_mentions: BTreeSet<String>,
room_mention: bool,
room_member_count: u64,
sender_power_level: Option<i64>,
notification_power_levels: BTreeMap<String, i64>,
related_events_flattened: BTreeMap<String, BTreeMap<String, String>>,
related_events_flattened: BTreeMap<String, BTreeMap<String, SimpleJsonValue>>,
related_event_match_enabled: bool,
room_version_feature_flags: Vec<String>,
msc3931_enabled: bool,
msc3758_exact_event_match: bool,
) -> Result<Self, Error> {
let body = flattened_keys
.get("content.body")
.cloned()
.unwrap_or_default();
let body = match flattened_keys.get("content.body") {
Some(SimpleJsonValue::Str(s)) => s.clone(),
_ => String::new(),
};

Ok(PushRuleEvaluator {
flattened_keys,
Expand All @@ -136,6 +140,7 @@ impl PushRuleEvaluator {
related_event_match_enabled,
room_version_feature_flags,
msc3931_enabled,
msc3758_exact_event_match,
})
}

Expand Down Expand Up @@ -252,6 +257,9 @@ impl PushRuleEvaluator {
KnownCondition::EventMatch(event_match) => {
self.match_event_match(event_match, user_id)?
}
KnownCondition::ExactEventMatch(exact_event_match) => {
self.match_exact_event_match(exact_event_match)?
}
KnownCondition::RelatedEventMatch(event_match) => {
self.match_related_event_match(event_match, user_id)?
}
Expand Down Expand Up @@ -337,7 +345,9 @@ impl PushRuleEvaluator {
return Ok(false);
};

let haystack = if let Some(haystack) = self.flattened_keys.get(&*event_match.key) {
let haystack = if let Some(SimpleJsonValue::Str(haystack)) =
self.flattened_keys.get(&*event_match.key)
{
haystack
} else {
return Ok(false);
Expand All @@ -355,6 +365,27 @@ impl PushRuleEvaluator {
compiled_pattern.is_match(haystack)
}

/// Evaluates a `exact_event_match` condition. (MSC3758)
fn match_exact_event_match(
&self,
exact_event_match: &ExactEventMatchCondition,
) -> Result<bool, Error> {
// First check if the feature is enabled.
if !self.msc3758_exact_event_match {
return Ok(false);
}

let value = &exact_event_match.value;

let haystack = if let Some(haystack) = self.flattened_keys.get(&*exact_event_match.key) {
haystack
} else {
return Ok(false);
};

Ok(haystack == &**value)
}

/// Evaluates a `related_event_match` condition. (MSC3664)
fn match_related_event_match(
&self,
Expand Down Expand Up @@ -410,7 +441,7 @@ impl PushRuleEvaluator {
return Ok(false);
};

let haystack = if let Some(haystack) = event.get(&**key) {
let haystack = if let Some(SimpleJsonValue::Str(haystack)) = event.get(&**key) {
haystack
} else {
return Ok(false);
Expand Down Expand Up @@ -455,7 +486,10 @@ impl PushRuleEvaluator {
#[test]
fn push_rule_evaluator() {
let mut flattened_keys = BTreeMap::new();
flattened_keys.insert("content.body".to_string(), "foo bar bob hello".to_string());
flattened_keys.insert(
"content.body".to_string(),
SimpleJsonValue::Str("foo bar bob hello".to_string()),
);
let evaluator = PushRuleEvaluator::py_new(
flattened_keys,
false,
Expand All @@ -468,6 +502,7 @@ fn push_rule_evaluator() {
true,
vec![],
true,
true,
)
.unwrap();

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

let mut flattened_keys = BTreeMap::new();
flattened_keys.insert("content.body".to_string(), "foo bar bob hello".to_string());
flattened_keys.insert(
"content.body".to_string(),
SimpleJsonValue::Str("foo bar bob hello".to_string()),
);
let flags = vec![RoomVersionFeatures::ExtensibleEvents.as_str().to_string()];
let evaluator = PushRuleEvaluator::py_new(
flattened_keys,
Expand All @@ -496,6 +534,7 @@ fn test_requires_room_version_supports_condition() {
false,
flags,
true,
true,
)
.unwrap();

Expand Down
Loading

0 comments on commit 14be78d

Please sign in to comment.