mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-05-07 05:45:11 +02:00
Reduce WS churn for incoming duplicates that don't affect ack/path list
This commit is contained in:
+15
-10
@@ -91,17 +91,22 @@ async def _handle_duplicate_message(
|
||||
if existing_msg.outgoing:
|
||||
ack_count = await MessageRepository.increment_ack_count(existing_msg.id)
|
||||
else:
|
||||
ack_count = await MessageRepository.get_ack_count(existing_msg.id)
|
||||
ack_count = existing_msg.acked
|
||||
|
||||
# Broadcast updated paths
|
||||
broadcast_event(
|
||||
"message_acked",
|
||||
{
|
||||
"message_id": existing_msg.id,
|
||||
"ack_count": ack_count,
|
||||
"paths": [p.model_dump() for p in paths] if paths else [],
|
||||
},
|
||||
)
|
||||
# Only broadcast when something actually changed:
|
||||
# - outgoing: ack count was incremented
|
||||
# - path provided: a new path entry was appended
|
||||
# The path=None case happens for direct-delivery DMs (0-hop, no routing bytes).
|
||||
# A non-outgoing duplicate with no new path changes nothing in the DB, so skip.
|
||||
if existing_msg.outgoing or path is not None:
|
||||
broadcast_event(
|
||||
"message_acked",
|
||||
{
|
||||
"message_id": existing_msg.id,
|
||||
"ack_count": ack_count,
|
||||
"paths": [p.model_dump() for p in paths] if paths else [],
|
||||
},
|
||||
)
|
||||
|
||||
# Mark this packet as decrypted
|
||||
await RawPacketRepository.mark_decrypted(packet_id, existing_msg.id)
|
||||
|
||||
@@ -224,6 +224,49 @@ class TestChannelEchoDetection:
|
||||
assert "aa" in path_values
|
||||
assert "bbcc" in path_values
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_incoming_duplicate_no_path_skips_broadcast(self, test_db, captured_broadcasts):
|
||||
"""Non-outgoing duplicate with no new path does NOT broadcast message_acked."""
|
||||
from app.packet_processor import create_message_from_decrypted
|
||||
|
||||
pkt1, _ = await RawPacketRepository.create(b"inc_np_1", SENDER_TIMESTAMP)
|
||||
|
||||
broadcasts, mock_broadcast = captured_broadcasts
|
||||
|
||||
with patch("app.packet_processor.broadcast_event", mock_broadcast):
|
||||
msg_id = await create_message_from_decrypted(
|
||||
packet_id=pkt1,
|
||||
channel_key=CHANNEL_KEY,
|
||||
sender="OtherUser",
|
||||
message_text="No path msg",
|
||||
timestamp=SENDER_TIMESTAMP,
|
||||
received_at=SENDER_TIMESTAMP,
|
||||
path=None,
|
||||
)
|
||||
|
||||
assert msg_id is not None
|
||||
broadcasts.clear()
|
||||
|
||||
# Duplicate arrives, also with no path
|
||||
pkt2, _ = await RawPacketRepository.create(b"inc_np_2", SENDER_TIMESTAMP + 1)
|
||||
|
||||
with patch("app.packet_processor.broadcast_event", mock_broadcast):
|
||||
result = await create_message_from_decrypted(
|
||||
packet_id=pkt2,
|
||||
channel_key=CHANNEL_KEY,
|
||||
sender="OtherUser",
|
||||
message_text="No path msg",
|
||||
timestamp=SENDER_TIMESTAMP,
|
||||
received_at=SENDER_TIMESTAMP + 1,
|
||||
path=None,
|
||||
)
|
||||
|
||||
assert result is None
|
||||
|
||||
# No message_acked broadcast — nothing changed
|
||||
ack_broadcasts = [b for b in broadcasts if b["type"] == "message_acked"]
|
||||
assert len(ack_broadcasts) == 0
|
||||
|
||||
|
||||
class TestDMEchoDetection:
|
||||
"""Test echo detection for direct messages."""
|
||||
@@ -330,6 +373,58 @@ class TestDMEchoDetection:
|
||||
path_values = [p["path"] for p in paths]
|
||||
assert "bbcc" in path_values
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_incoming_dm_duplicate_no_path_skips_broadcast(
|
||||
self, test_db, captured_broadcasts
|
||||
):
|
||||
"""Non-outgoing DM duplicate with no new path does NOT broadcast message_acked."""
|
||||
from app.packet_processor import create_dm_message_from_decrypted
|
||||
|
||||
pkt1, _ = await RawPacketRepository.create(b"dm_np_1", SENDER_TIMESTAMP)
|
||||
decrypted = DecryptedDirectMessage(
|
||||
timestamp=SENDER_TIMESTAMP,
|
||||
flags=0,
|
||||
message="No path DM",
|
||||
dest_hash="fa",
|
||||
src_hash="a1",
|
||||
)
|
||||
|
||||
broadcasts, mock_broadcast = captured_broadcasts
|
||||
|
||||
with patch("app.packet_processor.broadcast_event", mock_broadcast):
|
||||
msg_id = await create_dm_message_from_decrypted(
|
||||
packet_id=pkt1,
|
||||
decrypted=decrypted,
|
||||
their_public_key=CONTACT_PUB,
|
||||
our_public_key=OUR_PUB,
|
||||
received_at=SENDER_TIMESTAMP,
|
||||
path=None,
|
||||
outgoing=False,
|
||||
)
|
||||
|
||||
assert msg_id is not None
|
||||
broadcasts.clear()
|
||||
|
||||
# Duplicate arrives, also with no path
|
||||
pkt2, _ = await RawPacketRepository.create(b"dm_np_2", SENDER_TIMESTAMP + 1)
|
||||
|
||||
with patch("app.packet_processor.broadcast_event", mock_broadcast):
|
||||
result = await create_dm_message_from_decrypted(
|
||||
packet_id=pkt2,
|
||||
decrypted=decrypted,
|
||||
their_public_key=CONTACT_PUB,
|
||||
our_public_key=OUR_PUB,
|
||||
received_at=SENDER_TIMESTAMP + 1,
|
||||
path=None,
|
||||
outgoing=False,
|
||||
)
|
||||
|
||||
assert result is None
|
||||
|
||||
# No message_acked broadcast — nothing changed
|
||||
ack_broadcasts = [b for b in broadcasts if b["type"] == "message_acked"]
|
||||
assert len(ack_broadcasts) == 0
|
||||
|
||||
|
||||
class TestDualPathDedup:
|
||||
"""Test deduplication between the packet_processor and event_handler fallback paths.
|
||||
|
||||
Reference in New Issue
Block a user