fix(matrix): skip events received before bot startup
Matrix sync replays the room timeline on each startup or `/restart`, causing already-handled messages to be reprocessed (#3553). Even with `store_sync_tokens=True`, the sync token isn't reliably re-injected when restoring a session via access_token + load_store(), so the client re-reads recent timeline entries. Filter `event.server_timestamp` against the process start time so old events are dropped at the `_on_message` / `_on_media_message` entry points. Trade-off: messages received during downtime won't be processed, which matches the issue reporter's expectation. Closes #3553 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Xubin Ren
co-authored by
Claude Opus 4.7
parent
d9800ecdd2
commit
15007afd4a
@@ -380,6 +380,62 @@ async def test_on_message_skips_typing_for_self_message() -> None:
|
||||
assert client.typing_calls == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_on_message_skips_pre_startup_event() -> None:
|
||||
channel = MatrixChannel(_make_config(), MessageBus())
|
||||
client = _FakeAsyncClient("", "", "", None)
|
||||
channel.client = client
|
||||
channel._started_at_ms = 1_000_000
|
||||
|
||||
handled: list[str] = []
|
||||
|
||||
async def _fake_handle_message(**kwargs) -> None:
|
||||
handled.append(kwargs["sender_id"])
|
||||
|
||||
channel._handle_message = _fake_handle_message # type: ignore[method-assign]
|
||||
|
||||
room = SimpleNamespace(room_id="!room:matrix.org", display_name="Test room")
|
||||
old_event = SimpleNamespace(
|
||||
sender="@alice:matrix.org", body="old", source={}, server_timestamp=999_999
|
||||
)
|
||||
fresh_event = SimpleNamespace(
|
||||
sender="@alice:matrix.org", body="fresh", source={}, server_timestamp=1_000_001
|
||||
)
|
||||
|
||||
await channel._on_message(room, old_event)
|
||||
await channel._on_message(room, fresh_event)
|
||||
|
||||
assert handled == ["@alice:matrix.org"]
|
||||
assert client.typing_calls == [
|
||||
("!room:matrix.org", True, TYPING_NOTICE_TIMEOUT_MS),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_on_media_message_skips_pre_startup_event() -> None:
|
||||
channel = MatrixChannel(_make_config(), MessageBus())
|
||||
client = _FakeAsyncClient("", "", "", None)
|
||||
channel.client = client
|
||||
channel._started_at_ms = 1_000_000
|
||||
|
||||
handled: list[str] = []
|
||||
|
||||
async def _fake_handle_message(**kwargs) -> None:
|
||||
handled.append(kwargs["sender_id"])
|
||||
|
||||
channel._handle_message = _fake_handle_message # type: ignore[method-assign]
|
||||
|
||||
room = SimpleNamespace(room_id="!room:matrix.org", display_name="Test room")
|
||||
old_event = SimpleNamespace(
|
||||
sender="@alice:matrix.org", body="old", source={}, server_timestamp=999_999
|
||||
)
|
||||
|
||||
await channel._on_media_message(room, old_event)
|
||||
|
||||
assert handled == []
|
||||
assert client.typing_calls == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_on_message_skips_typing_for_denied_sender() -> None:
|
||||
channel = MatrixChannel(_make_config(allow_from=["@bob:matrix.org"]), MessageBus())
|
||||
|
||||
Reference in New Issue
Block a user