fix: Deduplicate echo paths and improve incoming path matching

- Deduplicate 2-char repeater codes in echo badge (same repeater via
  different routes was shown twice, e.g., "3 (d1, 5e, 5e)")
- Use deduplicated count for unique repeaters, not unique full paths
- Improve incoming path correlation: widen window to 10s, prefer
  path_len match but fall back to timestamp-only if needed
- Add debug logging for incoming path correlation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2026-02-07 16:29:23 +01:00
parent b9a9436271
commit ddb69f1a18
2 changed files with 23 additions and 9 deletions

View File

@@ -308,6 +308,8 @@ def get_messages():
resp_data = response.json()
echo_counts = resp_data.get('echo_counts', [])
incoming_paths = resp_data.get('incoming_paths', [])
if incoming_paths:
logger.debug(f"Echo data: {len(echo_counts)} sent, {len(incoming_paths)} incoming paths from bridge")
# Merge sent echo counts + paths into own messages
for msg in messages:
@@ -322,13 +324,24 @@ def get_messages():
break
# Merge incoming paths into received messages
# Match by timestamp proximity + path_len confirmation
for msg in messages:
if not msg.get('is_own'):
best_match = None
best_delta = 10 # max 10 second window
for ip in incoming_paths:
if (abs(msg['timestamp'] - ip['timestamp']) < 5 and
msg.get('path_len') == ip.get('path_len')):
msg['path'] = ip['path']
break
delta = abs(msg['timestamp'] - ip['timestamp'])
if delta < best_delta:
# Prefer matches where path_len also matches
if msg.get('path_len') == ip.get('path_len'):
best_match = ip
best_delta = delta
elif best_match is None:
# Fallback: timestamp-only match
best_match = ip
best_delta = delta
if best_match:
msg['path'] = best_match['path']
except Exception as e:
logger.debug(f"Echo data fetch failed (non-critical): {e}")

View File

@@ -726,12 +726,13 @@ function createMessageElement(msg) {
if (msg.is_own) {
// Own messages: right-aligned, no avatar
// Echo badge shows how many repeaters heard the message + their path codes
const echoPaths = (msg.echo_paths || []).map(p => p.substring(0, 2));
// Echo badge shows unique repeaters that heard the message + their path codes
const echoPaths = [...new Set((msg.echo_paths || []).map(p => p.substring(0, 2)))];
const echoCount = echoPaths.length;
const pathDisplay = echoPaths.length > 0 ? ` (${echoPaths.join(', ')})` : '';
const echoDisplay = msg.echo_count > 0
? `<span class="echo-badge" title="Heard by ${msg.echo_count} repeater(s): ${echoPaths.join(', ')}">
<i class="bi bi-broadcast"></i> ${msg.echo_count}${pathDisplay}
const echoDisplay = echoCount > 0
? `<span class="echo-badge" title="Heard by ${echoCount} repeater(s): ${echoPaths.join(', ')}">
<i class="bi bi-broadcast"></i> ${echoCount}${pathDisplay}
</span>`
: '';