fix: keep local Relay Chat commands above hub notices

This commit is contained in:
Ivan 2026-08-15 17:36:31 -05:00
parent f1071d6105
commit 2cba0cf683
No known key found for this signature in database
3 changed files with 58 additions and 18 deletions

Binary file not shown.

View file

@ -606,6 +606,25 @@ class RRCHub:
raise RuntimeError(msg)
RNS.Packet(link, payload).send()
def _send_env_then_maybe_record(self, env, local_msg):
"""Send on the wire, then record local history if send succeeded.
Mesh send is async, so the local echo still lands before a remote
reply. Loopback delivery is synchronous, so the echo is recorded
first or the hub notice would appear above the typed command.
"""
with self._lock:
link = self.link
loopback = isinstance(link, _LoopbackEndpoint)
if link is None or link.status != RNS.Link.ACTIVE:
msg = "not connected"
raise RuntimeError(msg)
if local_msg is not None and loopback:
self._record_message(local_msg, local=True)
self._send_env(env)
if local_msg is not None and not loopback:
self._record_message(local_msg, local=True)
def join_room(self, room, key=None, silent=False):
r = proto.normalize_room(room)
body = None
@ -654,20 +673,17 @@ class RRCHub:
)
if nick:
env[proto.K_NICK] = nick
self._send_env(env)
local_msg = None
if record_local:
history_text = self._redact_command_for_history(text)
self._record_message(
proto.RRCMessage(
"msg",
r,
self.manager.identity.hash,
nick,
history_text,
proto.now_ms(),
),
local=True,
local_msg = proto.RRCMessage(
"msg",
r,
self.manager.identity.hash,
nick,
self._redact_command_for_history(text),
proto.now_ms(),
)
self._send_env_then_maybe_record(env, local_msg)
@staticmethod
def _redact_command_for_history(text):
@ -735,8 +751,8 @@ class RRCHub:
mid = env[proto.K_ID]
if isinstance(mid, (bytes, bytearray)):
self._sent_ids.append(bytes(mid))
self._send_env(env)
self._record_message(
self._send_env_then_maybe_record(
env,
proto.RRCMessage(
"msg",
r,
@ -745,7 +761,6 @@ class RRCHub:
text,
proto.now_ms(),
),
local=True,
)
return mid
@ -769,8 +784,8 @@ class RRCHub:
mid = env[proto.K_ID]
if isinstance(mid, (bytes, bytearray)):
self._sent_ids.append(bytes(mid))
self._send_env(env)
self._record_message(
self._send_env_then_maybe_record(
env,
proto.RRCMessage(
"action",
r,
@ -779,7 +794,6 @@ class RRCHub:
text,
proto.now_ms(),
),
local=True,
)
return mid

View file

@ -400,6 +400,32 @@ def test_loopback_nick_command_updates_override(tmp_path):
assert msgs[-1].text == "nickname set to bob"
def test_mesh_command_not_recorded_when_send_fails(tmp_path):
_, hub = _loopback_client_hub(tmp_path)
hub.messages["general"] = []
status = hub.link.status
class MeshLink:
pass
mesh = MeshLink()
mesh.status = status
hub.link = mesh
def boom(_env):
raise RuntimeError("link down")
hub._send_env = boom
raised = None
try:
hub.send_command("/help", room="general")
except RuntimeError as exc:
raised = exc
assert raised is not None
assert str(raised) == "link down"
assert hub.messages["general"] == []
def test_server_members_dict_all_and_per_room(tmp_path):
server = make_running_server()
server.register_room("general")