eval.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. from time import time
  2. from typing import Any, Collection, Dict, List
  3. from synapse.api.constants import EventTypes
  4. from synapse.api.room_versions import RoomVersions
  5. from synapse.config.experimental import ExperimentalConfig
  6. from synapse.events import EventBase, make_event_from_dict
  7. from synapse.push.baserules import FilteredPushRules, PushRules
  8. from synapse.push.push_rule_evaluator import PushRuleEvaluatorForEvent
  9. def compute_push_actions(
  10. experimental_config: ExperimentalConfig,
  11. evaluator: PushRuleEvaluatorForEvent,
  12. event: EventBase,
  13. rules_by_user: Dict[str, FilteredPushRules],
  14. profiles: Dict[str, Any],
  15. count_as_unread: bool,
  16. uids_with_visibility: Collection[str],
  17. ) -> Dict[str, List]:
  18. actions_by_user = {}
  19. default_rules = FilteredPushRules(PushRules(), {}, experimental_config)
  20. matching_default_rule = None
  21. for rule, _ in default_rules:
  22. if not rule.default_enabled:
  23. continue
  24. matches = evaluator.check_conditions(rule.conditions, "uid", None)
  25. if matches:
  26. matching_default_rule = rule
  27. break
  28. joining_user = None
  29. if event.type == EventTypes.Member:
  30. joining_user = event.state_key
  31. for uid, rules in rules_by_user.items():
  32. if event.sender == uid:
  33. try:
  34. actions_by_user.pop(uid)
  35. except KeyError:
  36. pass
  37. continue
  38. if uid not in uids_with_visibility:
  39. try:
  40. actions_by_user.pop(uid)
  41. except KeyError:
  42. pass
  43. continue
  44. display_name = None
  45. profile = profiles.get(uid)
  46. if profile:
  47. display_name = profile.display_name
  48. if not display_name and joining_user:
  49. # Handle the case where we are pushing a membership event to
  50. # that user, as they might not be already joined.
  51. if joining_user == uid:
  52. display_name = event.content.get("displayname", None)
  53. if not isinstance(display_name, str):
  54. display_name = None
  55. if count_as_unread:
  56. # Add an element for the current user if the event needs to be marked as
  57. # unread, so that add_push_actions_to_staging iterates over it.
  58. # If the event shouldn't be marked as unread but should notify the
  59. # current user, it'll be added to the dict later.
  60. actions_by_user[uid] = []
  61. matched_default = False
  62. if matching_default_rule:
  63. if not rules.enabled_map.get(matching_default_rule.rule_id, True):
  64. continue
  65. matched_default = True
  66. override = rules.push_rules.overriden_base_rules.get(
  67. matching_default_rule.rule_id
  68. )
  69. if override:
  70. actions = override.actions
  71. else:
  72. actions = matching_default_rule.actions
  73. actions = [x for x in actions if x != "dont_notify"]
  74. if actions and "notify" in actions:
  75. actions_by_user[uid] = matching_default_rule.actions
  76. for rule, enabled in rules.user_specific_rules():
  77. if not enabled:
  78. continue
  79. if (
  80. matched_default
  81. and rule.priority_class < matching_default_rule.priority_class
  82. ):
  83. break
  84. matches = evaluator.check_conditions(rule.conditions, uid, display_name)
  85. if matches:
  86. actions = [x for x in rule.actions if x != "dont_notify"]
  87. if actions and "notify" in actions:
  88. # Push rules say we should notify the user of this event
  89. actions_by_user[uid] = actions
  90. else:
  91. try:
  92. actions_by_user.pop(uid)
  93. except KeyError:
  94. pass
  95. break
  96. return actions_by_user
  97. if __name__ == "__main__":
  98. event = make_event_from_dict(
  99. {
  100. "auth_events": [
  101. "$Y6V1n3kQq_G2Q2gqma4tXbS0TtZQYne-zk8EGymcErI",
  102. "$RWzLUHmF5Hc6kr5hJuCY7gcDt3bVXS2JL6oJD7lTEdo",
  103. "$uIZRw93tT3lXnpMj40J8aPbnDkXeaWtgJWBVrfeQsYs",
  104. ],
  105. "prev_events": ["$6lCOe9WyCBREZrvfdShVHO7OgBZ3HA82AN-TsGzsj94"],
  106. "type": "m.room.message",
  107. "room_id": "!mWlQLVyRcFtLrKOgEl:localhost:8448",
  108. "sender": "@user-nn87-main:localhost:8448",
  109. "content": {
  110. "org.matrix.msc1767.text": "test",
  111. "body": "test",
  112. "msgtype": "m.text",
  113. },
  114. "depth": 5006,
  115. "prev_state": [],
  116. "origin": "localhost:8448",
  117. "origin_server_ts": 1660738396696,
  118. "hashes": {"sha256": "j2X9zgQU6jUqARb9blCdX5UL8SKKJgG1cTxb7uZOiLI"},
  119. "signatures": {
  120. "localhost:8448": {
  121. "ed25519:a_ERAh": "BsToq2Bf2DqksU5i7vsMN2hxgRBmou+5++IK4+Af8GLt46E9Po1L5Iv1JLxe4eN/zN/jYW03ULGdrzzJkCzaDA"
  122. }
  123. },
  124. "unsigned": {"age_ts": 1660738396696},
  125. },
  126. RoomVersions.V10,
  127. )
  128. evaluator = PushRuleEvaluatorForEvent(event, 5000, 0, {}, {}, False)
  129. experimental_config = ExperimentalConfig()
  130. experimental_config.read_config({})
  131. rules_by_user = {
  132. f"@user-{i}:localhost": FilteredPushRules(PushRules(), {}, experimental_config)
  133. for i in range(5000)
  134. }
  135. uids_with_visibility = set(rules_by_user)
  136. start = time()
  137. number = 100
  138. for _ in range(number):
  139. result = compute_push_actions(
  140. experimental_config,
  141. evaluator,
  142. event,
  143. rules_by_user,
  144. {},
  145. True,
  146. uids_with_visibility,
  147. )
  148. end = time()
  149. print(f"Average time: {(end - start)*1000/number:.3}ms")