test+harden: modernize salvaged Matrix path for current plugin layout

Two follow-ups on top of the salvaged #46365 fix:

1. Tests: the salvaged tests injected the ephemeral MatrixAdapter via
   sys.modules["gateway.platforms.matrix"], but Matrix migrated to a plugin
   (#41112) and the fallback now imports from plugins.platforms.matrix.adapter.
   Point the three sys.modules patches at the current module path so the
   ephemeral-fallback tests actually exercise the injected fake adapter.

2. Harden the live-adapter lookup: split the gateway import guard from the
   adapter lookup and log (instead of silently swallowing) when a runner
   exists but adapters.get() raises. A silent fall-through there would
   re-introduce the per-send reconnect/OTK-exhaustion storm this fix exists
   to prevent (#46310). Documented that the live adapter is gateway-owned and
   must not be disconnected, and why the ephemeral finally never touches it.
This commit is contained in:
kshitijk4poor 2026-06-28 12:15:13 +05:30 committed by kshitij
parent a7fd62d824
commit fc7a01b6cb
2 changed files with 31 additions and 11 deletions

View file

@ -943,7 +943,7 @@ class TestMatrixMediaLiveAdapterReuse:
"gateway.run._gateway_runner_ref",
return_value=fake_runner,
), patch.dict(
sys.modules, {"gateway.platforms.matrix": SimpleNamespace()}
sys.modules, {"plugins.platforms.matrix.adapter": SimpleNamespace()}
):
result = asyncio.run(
_send_matrix_via_adapter(
@ -993,7 +993,7 @@ class TestMatrixMediaLiveAdapterReuse:
with patch(
"gateway.run._gateway_runner_ref", return_value=None
), patch.dict(sys.modules, {"gateway.platforms.matrix": fake_module}):
), patch.dict(sys.modules, {"plugins.platforms.matrix.adapter": fake_module}):
result = asyncio.run(
_send_matrix_via_adapter(
SimpleNamespace(enabled=True, token="tok", extra={}),
@ -1038,7 +1038,7 @@ class TestMatrixMediaLiveAdapterReuse:
with patch(
"gateway.run._gateway_runner_ref",
return_value=fake_runner,
), patch.dict(sys.modules, {"gateway.platforms.matrix": fake_module}):
), patch.dict(sys.modules, {"plugins.platforms.matrix.adapter": fake_module}):
result = asyncio.run(
_send_matrix_via_adapter(
SimpleNamespace(enabled=True, token="tok", extra={}),

View file

@ -1482,19 +1482,39 @@ async def _send_matrix_via_adapter(pconfig, chat_id, message, media_files=None,
metadata = {"thread_id": thread_id} if thread_id else None
# --- Try the live gateway adapter first (persistent E2EE session) ---
# Reusing the running gateway's already-connected adapter is the whole
# point of #46310: it avoids a per-send login + olm/megolm re-init + OTK
# claim that, under burst sends, exhausts recipient one-time keys and
# silently drops messages. The import is guarded narrowly (gateway code may
# be absent in some standalone contexts); a runner that *exists* but whose
# adapter lookup fails is logged rather than silently swallowed, because a
# silent fall-through here would re-introduce the exact reconnect storm
# this fix prevents.
live_adapter = None
runner = None
try:
from gateway.config import Platform
from gateway.run import _gateway_runner_ref
runner = _gateway_runner_ref()
if runner is not None:
live_adapter = runner.adapters.get(Platform.MATRIX)
except Exception:
live_adapter = None
runner = None
if runner is not None:
try:
from gateway.config import Platform
live_adapter = runner.adapters.get(Platform.MATRIX)
except Exception:
logger.warning(
"Matrix: live gateway adapter lookup failed; falling back to an "
"ephemeral connect (may re-init E2EE per send, see #46310)",
exc_info=True,
)
live_adapter = None
if live_adapter is not None:
return await _send_via_matrix_adapter(
# NOTE: the live adapter is owned by the gateway — we must NOT
# disconnect it. Correctness here depends on this branch returning
# before the ephemeral ``adapter`` is constructed below, so the
# ephemeral ``finally`` disconnect never touches the live session.
return await _matrix_send_core(
live_adapter, chat_id, message, media_files, metadata
)
@ -1509,7 +1529,7 @@ async def _send_matrix_via_adapter(pconfig, chat_id, message, media_files=None,
connected = await adapter.connect()
if not connected:
return _error("Matrix connect failed")
return await _send_via_matrix_adapter(
return await _matrix_send_core(
adapter, chat_id, message, media_files, metadata
)
except Exception as e:
@ -1521,7 +1541,7 @@ async def _send_matrix_via_adapter(pconfig, chat_id, message, media_files=None,
pass
async def _send_via_matrix_adapter(adapter, chat_id, message, media_files, metadata):
async def _matrix_send_core(adapter, chat_id, message, media_files, metadata):
"""Core send logic shared by live and ephemeral Matrix adapters."""
last_result = None