Add msc4354_sticky_duration_ttl_ms support
This commit is contained in:
@@ -279,6 +279,8 @@ class EventUnsignedContentFields:
|
||||
# Requesting user's membership, per MSC4115
|
||||
MEMBERSHIP: Final = "membership"
|
||||
|
||||
STICKY_TTL: Final = "msc4354_sticky_duration_ttl_ms"
|
||||
|
||||
|
||||
class MTextFields:
|
||||
"""Fields found inside m.text content blocks."""
|
||||
@@ -369,3 +371,4 @@ class StickyEventField(TypedDict):
|
||||
class StickyEvent:
|
||||
QUERY_PARAM_NAME: Final = "msc4354_stick_duration_ms"
|
||||
FIELD_NAME: Final = "msc4354_sticky"
|
||||
MAX_DURATION_MS: Final = 3600000 # 1 hour
|
||||
|
||||
@@ -41,7 +41,12 @@ from typing import (
|
||||
import attr
|
||||
from unpaddedbase64 import encode_base64
|
||||
|
||||
from synapse.api.constants import EventContentFields, EventTypes, RelationTypes
|
||||
from synapse.api.constants import (
|
||||
EventContentFields,
|
||||
EventTypes,
|
||||
RelationTypes,
|
||||
StickyEvent,
|
||||
)
|
||||
from synapse.api.room_versions import EventFormatVersions, RoomVersion, RoomVersions
|
||||
from synapse.synapse_rust.events import EventInternalMetadata
|
||||
from synapse.types import (
|
||||
@@ -323,6 +328,20 @@ class EventBase(metaclass=abc.ABCMeta):
|
||||
# this will be a no-op if the event dict is already frozen.
|
||||
self._dict = freeze(self._dict)
|
||||
|
||||
def sticky_duration(self) -> Optional[int]:
|
||||
sticky_obj = self.get_dict().get(StickyEvent.FIELD_NAME, None)
|
||||
if type(sticky_obj) is not dict:
|
||||
return None
|
||||
sticky_duration_ms = sticky_obj.get("duration_ms", None)
|
||||
# MSC: Valid values are the integer range 0-MAX_DURATION_MS
|
||||
if (
|
||||
type(sticky_duration_ms) is int
|
||||
and sticky_duration_ms >= 0
|
||||
and sticky_duration_ms <= StickyEvent.MAX_DURATION_MS
|
||||
):
|
||||
return sticky_duration_ms
|
||||
return None
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.__repr__()
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ logger = logging.getLogger(__name__)
|
||||
# Consumers call 'get_sticky_events_in_rooms' which has `WHERE expires_at > ?`
|
||||
# to filter out expired sticky events that have yet to be deleted.
|
||||
DELETE_EXPIRED_STICKY_EVENTS_MS = 60 * 1000 * 60 # 1 hour
|
||||
MAX_STICKY_DURATION_MS = 3600000 # 1 hour
|
||||
|
||||
|
||||
class StickyEventsWorkerStore(StateGroupWorkerStore, CacheInvalidationWorkerStore):
|
||||
@@ -297,22 +296,14 @@ class StickyEventsWorkerStore(StateGroupWorkerStore, CacheInvalidationWorkerStor
|
||||
if ev.rejected_reason is not None:
|
||||
continue
|
||||
# MSC: The presence of sticky.duration_ms with a valid value makes the event “sticky”
|
||||
sticky_obj = ev.get_dict().get(StickyEvent.FIELD_NAME, None)
|
||||
if type(sticky_obj) is not dict:
|
||||
continue
|
||||
sticky_duration_ms = sticky_obj.get("duration_ms", None)
|
||||
# MSC: Valid values are the integer range 0-MAX_STICKY_DURATION_MS
|
||||
if (
|
||||
type(sticky_duration_ms) is int
|
||||
and sticky_duration_ms >= 0
|
||||
and sticky_duration_ms <= MAX_STICKY_DURATION_MS
|
||||
):
|
||||
sticky_duration = ev.sticky_duration()
|
||||
if sticky_duration:
|
||||
# MSC: The start time is min(now, origin_server_ts).
|
||||
# This ensures that malicious origin timestamps cannot specify start times in the future.
|
||||
# Calculate the end time as start_time + min(sticky.duration_ms, MAX_STICKY_DURATION_MS).
|
||||
# Calculate the end time as start_time + min(sticky.duration_ms, MAX_DURATION_MS).
|
||||
expires_at = min(ev.origin_server_ts, now_ms) + min(
|
||||
ev.get_dict()[StickyEvent.FIELD_NAME]["duration_ms"],
|
||||
MAX_STICKY_DURATION_MS,
|
||||
StickyEvent.MAX_DURATION_MS,
|
||||
)
|
||||
# filter out already expired sticky events
|
||||
if expires_at > now_ms:
|
||||
|
||||
@@ -209,6 +209,15 @@ async def filter_events_for_client(
|
||||
# to the cache!
|
||||
cloned = clone_event(filtered)
|
||||
cloned.unsigned[EventUnsignedContentFields.MEMBERSHIP] = user_membership
|
||||
if storage.main.config.experimental.msc4354_enabled:
|
||||
sticky_duration = cloned.sticky_duration()
|
||||
if sticky_duration:
|
||||
now = storage.main.clock.time_msec()
|
||||
expires_at = min(cloned.origin_server_ts, now) + sticky_duration
|
||||
if sticky_duration and expires_at > now:
|
||||
cloned.unsigned[EventUnsignedContentFields.STICKY_TTL] = (
|
||||
expires_at - now
|
||||
)
|
||||
|
||||
return cloned
|
||||
|
||||
|
||||
Reference in New Issue
Block a user