fix: close relay loop from prefixed dedup mismatch
The dispatcher deduped on inbound text but relayed a prefixed copy
("[net/sender] text"), so a re-heard relayed message hashed differently
and was re-relayed, stacking another prefix each hop — an unbounded loop,
exactly what the dedup was meant to prevent.
Add MessageBus.mark_seen() and record the on-air relayed string before
sending, so the bridge recognises and drops its own relayed copies.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d04e4c8370
commit
dbfdf1c851
@ -56,5 +56,21 @@ class MessageBus:
|
|||||||
self._seen[h] = now + self._dedup_ttl
|
self._seen[h] = now + self._dedup_ttl
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def mark_seen(self, text: str) -> None:
|
||||||
|
"""Record text as already-seen without reporting duplicate status.
|
||||||
|
|
||||||
|
The dispatcher relays a *prefixed* copy of each message (e.g.
|
||||||
|
"[meshtastic/x] hello"), not the original text. Dedup is content-hash
|
||||||
|
based, so unless the exact on-air relayed string is recorded here, the
|
||||||
|
bridge won't recognise its own relayed copy when it echoes back from
|
||||||
|
another network — it would re-relay it, stacking another prefix each
|
||||||
|
hop (an unbounded loop). Marking every outbound string seen closes
|
||||||
|
that loop.
|
||||||
|
"""
|
||||||
|
h = self._content_hash(text)
|
||||||
|
now = time.monotonic()
|
||||||
|
with self._lock:
|
||||||
|
self._seen[h] = now + self._dedup_ttl
|
||||||
|
|
||||||
def get(self, timeout: float | None = None) -> BridgeMessage:
|
def get(self, timeout: float | None = None) -> BridgeMessage:
|
||||||
return self._queue.get(timeout=timeout)
|
return self._queue.get(timeout=timeout)
|
||||||
|
|||||||
@ -82,11 +82,16 @@ def main() -> int:
|
|||||||
if bus.is_duplicate(message.text):
|
if bus.is_duplicate(message.text):
|
||||||
continue
|
continue
|
||||||
print(f"[{message.network}] {message.sender}: {message.text}")
|
print(f"[{message.network}] {message.sender}: {message.text}")
|
||||||
|
relayed = f"[{message.network}/{message.sender}] {message.text}"
|
||||||
|
# Record the exact on-air string so that if this relayed copy is
|
||||||
|
# re-heard from another network it's recognised as a duplicate and
|
||||||
|
# not re-relayed (which would stack another prefix each hop).
|
||||||
|
bus.mark_seen(relayed)
|
||||||
for network, adapter in adapters.items():
|
for network, adapter in adapters.items():
|
||||||
if network == message.network:
|
if network == message.network:
|
||||||
continue # don't echo back onto the network it came from
|
continue # don't echo back onto the network it came from
|
||||||
try:
|
try:
|
||||||
adapter.send(f"[{message.network}/{message.sender}] {message.text}")
|
adapter.send(relayed)
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
print(f" ! failed to relay onto {network}: {exc}", file=sys.stderr)
|
print(f" ! failed to relay onto {network}: {exc}", file=sys.stderr)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user