Phase 4: Update advert path storage

This commit is contained in:
Jack Kingsman
2026-03-07 19:06:19 -08:00
parent f97c846378
commit b0ffa28e46
4 changed files with 26 additions and 14 deletions

View File

@@ -132,7 +132,11 @@ async def on_contact_message(event: "Event") -> None:
logger.debug("DM from %s handled by event handler (fallback path)", sender_pubkey[:12])
# Build paths array for broadcast
paths = [MessagePath(path=path or "", received_at=received_at, path_len=path_len)] if path is not None else None
paths = (
[MessagePath(path=path or "", received_at=received_at, path_len=path_len)]
if path is not None
else None
)
# Broadcast the new message
broadcast_event(
@@ -221,9 +225,7 @@ async def on_path_update(event: "Event") -> None:
)
return
await ContactRepository.update_path(
contact.public_key, str(path), normalized_path_len
)
await ContactRepository.update_path(contact.public_key, str(path), normalized_path_len)
async def on_new_contact(event: "Event") -> None:

View File

@@ -196,7 +196,11 @@ async def create_message_from_decrypted(
# Build paths array for broadcast
# Use "is not None" to include empty string (direct/0-hop messages)
paths = [MessagePath(path=path or "", received_at=received, path_len=path_len)] if path is not None else None
paths = (
[MessagePath(path=path or "", received_at=received, path_len=path_len)]
if path is not None
else None
)
# Broadcast new message to connected clients (and fanout modules when realtime)
broadcast_event(
@@ -305,7 +309,11 @@ async def create_dm_message_from_decrypted(
await RawPacketRepository.mark_decrypted(packet_id, msg_id)
# Build paths array for broadcast
paths = [MessagePath(path=path or "", received_at=received, path_len=path_len)] if path is not None else None
paths = (
[MessagePath(path=path or "", received_at=received, path_len=path_len)]
if path is not None
else None
)
# Broadcast new message to connected clients (and fanout modules when realtime)
sender_name = contact.name if contact and not outgoing else None
@@ -709,6 +717,7 @@ async def _process_advertisement(
path_hex=new_path_hex,
timestamp=timestamp,
max_paths=10,
hop_count=new_path_len,
)
# Record name history

View File

@@ -8,6 +8,7 @@ from app.models import (
ContactAdvertPathSummary,
ContactNameHistory,
)
from app.path_utils import first_hop_hex
class AmbiguousPublicKeyPrefixError(ValueError):
@@ -200,9 +201,7 @@ class ContactRepository:
return [ContactRepository._row_to_contact(row) for row in rows]
@staticmethod
async def update_path(
public_key: str, path: str, path_len: int
) -> None:
async def update_path(public_key: str, path: str, path_len: int) -> None:
await db.conn.execute(
"""UPDATE contacts SET last_path = ?, last_path_len = ?,
last_seen = ? WHERE public_key = ?""",
@@ -290,10 +289,11 @@ class ContactAdvertPathRepository:
@staticmethod
def _row_to_path(row) -> ContactAdvertPath:
path = row["path_hex"] or ""
next_hop = path[:2].lower() if len(path) >= 2 else None
path_len = row["path_len"]
next_hop = first_hop_hex(path, path_len)
return ContactAdvertPath(
path=path,
path_len=row["path_len"],
path_len=path_len,
next_hop=next_hop,
first_seen=row["first_seen"],
last_seen=row["last_seen"],
@@ -306,6 +306,7 @@ class ContactAdvertPathRepository:
path_hex: str,
timestamp: int,
max_paths: int = 10,
hop_count: int | None = None,
) -> None:
"""
Upsert a unique advert path observation for a contact and prune to N most recent.
@@ -315,7 +316,7 @@ class ContactAdvertPathRepository:
normalized_key = public_key.lower()
normalized_path = path_hex.lower()
path_len = len(normalized_path) // 2
path_len = hop_count if hop_count is not None else len(normalized_path) // 2
await db.conn.execute(
"""

View File

@@ -204,8 +204,8 @@ async def get_contact_detail(public_key: str) -> ContactDetail:
# Compute nearest repeaters from first-hop prefixes in advert paths
first_hop_stats: dict[str, dict] = {} # prefix -> {heard_count, path_len, last_seen}
for p in advert_paths:
if p.path and len(p.path) >= 2:
prefix = p.path[:2].lower()
prefix = p.next_hop
if prefix:
if prefix not in first_hop_stats:
first_hop_stats[prefix] = {
"heard_count": 0,