diff --git a/changelog.d/13254.misc b/changelog.d/13254.misc
new file mode 100644
index 0000000000..cba6b9ee0f
--- /dev/null
+++ b/changelog.d/13254.misc
@@ -0,0 +1 @@
+Preparatory work for a per-room rate limiter on joins.
diff --git a/synapse/notifier.py b/synapse/notifier.py
index 54b0ec4b97..c42bb8266a 100644
--- a/synapse/notifier.py
+++ b/synapse/notifier.py
@@ -228,6 +228,7 @@ class Notifier:
# Called when there are new things to stream over replication
self.replication_callbacks: List[Callable[[], None]] = []
+ self._new_join_in_room_callbacks: List[Callable[[str, str], None]] = []
self._federation_client = hs.get_federation_http_client()
@@ -280,6 +281,19 @@ class Notifier:
"""
self.replication_callbacks.append(cb)
+ def add_new_join_in_room_callback(self, cb: Callable[[str, str], None]) -> None:
+ """Add a callback that will be called when a user joins a room.
+
+ This only fires on genuine membership changes, e.g. "invite" -> "join".
+ Membership transitions like "join" -> "join" (for e.g. displayname changes) do
+ not trigger the callback.
+
+ When called, the callback receives two arguments: the event ID and the room ID.
+ It should *not* return a Deferred - if it needs to do any asynchronous work, a
+ background thread should be started and wrapped with run_as_background_process.
+ """
+ self._new_join_in_room_callbacks.append(cb)
+
async def on_new_room_event(
self,
event: EventBase,
@@ -723,6 +737,10 @@ class Notifier:
for cb in self.replication_callbacks:
cb()
+ def notify_user_joined_room(self, event_id: str, room_id: str) -> None:
+ for cb in self._new_join_in_room_callbacks:
+ cb(event_id, room_id)
+
def notify_remote_server_up(self, server: str) -> None:
"""Notify any replication that a remote server has come back up"""
# We call federation_sender directly rather than registering as a
|