From 16d92c96bde3a65fc54a93b4662df30cafc831e4 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Thu, 15 Oct 2026 00:56:04 +0200 Subject: fix(node): a chat-epoch notice answers no request, not even the asker's Revoking a device or removing a member opens a chat epoch, announced to everyone connected to the group, the asker included. Sent inside the handler, the asker's copy was stamped with its request's id and arrived as the answer to device_revoke, before the real one. It now leaves outside the reply context. Co-Authored-By: Claude Opus 5.5 --- .../src/meshbay_node/transport/webrtc/chat.py | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'packages/meshbay-node/src') diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc/chat.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc/chat.py index f200884..ed2c43a 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/webrtc/chat.py +++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc/chat.py @@ -20,6 +20,7 @@ from meshbay_common.protocol import MNP from meshbay_node import linkpreview, ops from meshbay_node.chat import FORMAT_SEALED_V1, ReplayedMessage +from meshbay_node.transport.webrtc.channel import _REPLY_TO log = logging.getLogger("meshbay_node.transport.webrtc_server") @@ -115,15 +116,22 @@ class ChatMixin: self._audit("chat_epoch_failed", reason) return self._audit("chat_epoch", f"{reason}:{result['epoch']}") - # Everyone still connected picks the new key up without reconnecting. - for session in list( - (self._ctx.get("groups") or {}).get(group_id, {}) - .get("_peers", {}).values()): - try: - session._send({"type": MNP.CHAT_EPOCH_ACK, "v": MNP_VERSION, - "epoch": result["epoch"]}) - except Exception: - pass + # Everyone still connected picks the new key up without reconnecting — + # this session too, which is why the notice leaves outside the reply + # context: stamped with the id of the request that caused it (a device + # revoked, a member removed), it would arrive as that request's answer. + token = _REPLY_TO.set((None, None)) + try: + for session in list( + (self._ctx.get("groups") or {}).get(group_id, {}) + .get("_peers", {}).values()): + try: + session._send({"type": MNP.CHAT_EPOCH_ACK, "v": MNP_VERSION, + "epoch": result["epoch"]}) + except Exception: + pass + finally: + _REPLY_TO.reset(token) def _do_chat_directory(self, msg: dict) -> None: """ -- cgit v1.2.3