Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/18513.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support the import of the `RatelimitOverride` type from `synapse.module_api` in modules and rename `messages_per_second` to `per_second`.
7 changes: 6 additions & 1 deletion docs/modules/ratelimit_callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The available ratelimit callbacks are:
_First introduced in Synapse v1.132.0_

```python
async def get_ratelimit_override_for_user(user: str, limiter_name: str) -> Optional[RatelimitOverride]
async def get_ratelimit_override_for_user(user: str, limiter_name: str) -> Optional[synapse.module_api.RatelimitOverride]
```

Called when constructing a ratelimiter of a particular type for a user. The module can
Expand All @@ -26,6 +26,11 @@ The limiters that are currently supported are:
- `rc_invites.per_user`
- `rc_invites.per_issuer`

The `RatelimitOverride` return type has the following fields:

- `per_second: float`. The number of actions that can be performed in a second. `0.0` means that ratelimiting is disabled.
- `burst_count: int`. The number of actions that can be performed before being limited.

If multiple modules implement this callback, they will be considered in order. If a
callback returns `None`, Synapse falls through to the next one. The value of the first
callback that does not return `None` will be used. If this happens, Synapse will not call
Expand Down
2 changes: 1 addition & 1 deletion synapse/api/ratelimiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ async def can_do_action(
)

if module_override:
rate_hz = module_override.messages_per_second
rate_hz = module_override.per_second
burst_count = module_override.burst_count

# Override default values if set
Expand Down
2 changes: 2 additions & 0 deletions synapse/module_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
)
from synapse.module_api.callbacks.ratelimit_callbacks import (
GET_RATELIMIT_OVERRIDE_FOR_USER_CALLBACK,
RatelimitOverride,
)
from synapse.module_api.callbacks.spamchecker_callbacks import (
CHECK_EVENT_FOR_SPAM_CALLBACK,
Expand Down Expand Up @@ -197,6 +198,7 @@
"ProfileInfo",
"RoomAlias",
"UserProfile",
"RatelimitOverride",
]

logger = logging.getLogger(__name__)
Expand Down
14 changes: 13 additions & 1 deletion synapse/module_api/callbacks/ratelimit_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
import logging
from typing import TYPE_CHECKING, Awaitable, Callable, List, Optional

from synapse.storage.databases.main.room import RatelimitOverride
import attr

from synapse.util.async_helpers import delay_cancellation
from synapse.util.metrics import Measure

Expand All @@ -24,6 +25,17 @@

logger = logging.getLogger(__name__)


@attr.s(auto_attribs=True)
class RatelimitOverride:
"""Represents a ratelimit being overridden."""

per_second: float
"""The number of actions that can be performed in a second. `0.0` means that ratelimiting is disabled."""
burst_count: int
"""How many actions that can be performed before being limited."""


GET_RATELIMIT_OVERRIDE_FOR_USER_CALLBACK = Callable[
[str, str], Awaitable[Optional[RatelimitOverride]]
]
Expand Down
4 changes: 3 additions & 1 deletion synapse/storage/databases/main/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@

@attr.s(slots=True, frozen=True, auto_attribs=True)
class RatelimitOverride:
messages_per_second: float
# n.b. elsewhere in Synapse messages_per_second is represented as a float, but it is
# an integer in the database
messages_per_second: int
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

burst_count: int


Expand Down
4 changes: 2 additions & 2 deletions tests/api/test_ratelimiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from synapse.api.ratelimiting import LimitExceededError, Ratelimiter
from synapse.appservice import ApplicationService
from synapse.config.ratelimiting import RatelimitSettings
from synapse.module_api import RatelimitOverride
from synapse.module_api.callbacks.ratelimit_callbacks import RatelimitModuleApiCallbacks
from synapse.storage.databases.main.room import RatelimitOverride
from synapse.types import create_requester

from tests import unittest
Expand Down Expand Up @@ -477,7 +477,7 @@ async def get_ratelimit_override_for_user(
) -> Optional[RatelimitOverride]:
if user_id == test_user_id:
return RatelimitOverride(
messages_per_second=0.1,
per_second=0.1,
burst_count=10,
)
return None
Expand Down
Loading