mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-07-06 01:41:07 +02:00
feat(analyzer): compute pkt_payload from channel secrets for Analyzer URLs
meshcore v2 doesn't provide pkt_payload in events, so compute it lazily in the API from channel secrets + message data. Analyzer URLs now appear for ALL messages (own and incoming), not just own. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@ def _to_str(val) -> str:
|
||||
return str(val)
|
||||
|
||||
|
||||
|
||||
class DeviceManager:
|
||||
"""
|
||||
Manages MeshCore device connection.
|
||||
@@ -47,6 +48,7 @@ class DeviceManager:
|
||||
self._device_name = None
|
||||
self._self_info = None
|
||||
self._subscriptions = [] # active event subscriptions
|
||||
self._channel_secrets = {} # {channel_idx: secret_hex} for pkt_payload
|
||||
|
||||
@property
|
||||
def is_connected(self) -> bool:
|
||||
@@ -176,6 +178,9 @@ class DeviceManager:
|
||||
await self.mc.ensure_contacts()
|
||||
self._sync_contacts_to_db()
|
||||
|
||||
# Cache channel secrets for pkt_payload computation
|
||||
await self._load_channel_secrets()
|
||||
|
||||
# Start auto message fetching (events fire on new messages)
|
||||
await self.mc.start_auto_message_fetching()
|
||||
|
||||
@@ -183,6 +188,22 @@ class DeviceManager:
|
||||
logger.error(f"Device connection failed: {e}")
|
||||
self._connected = False
|
||||
|
||||
async def _load_channel_secrets(self):
|
||||
"""Load channel secrets from device for pkt_payload computation."""
|
||||
try:
|
||||
for idx in range(8): # MeshCore supports channels 0-7
|
||||
event = await self.mc.commands.get_channel(idx)
|
||||
if event:
|
||||
data = getattr(event, 'payload', None) or {}
|
||||
secret = data.get('channel_secret', data.get('secret', b''))
|
||||
if isinstance(secret, bytes):
|
||||
secret = secret.hex()
|
||||
if secret and len(secret) == 32:
|
||||
self._channel_secrets[idx] = secret
|
||||
logger.info(f"Cached {len(self._channel_secrets)} channel secrets")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load channel secrets: {e}")
|
||||
|
||||
async def _subscribe_events(self):
|
||||
"""Subscribe to all relevant device events."""
|
||||
from meshcore.events import EventType
|
||||
|
||||
+38
-8
@@ -411,10 +411,39 @@ def get_messages():
|
||||
days=days,
|
||||
)
|
||||
|
||||
# Build channel secret lookup for pkt_payload computation
|
||||
channel_secrets = {}
|
||||
_, channels_list = get_channels_cached()
|
||||
if channels_list:
|
||||
for ch_info in channels_list:
|
||||
ch_key = ch_info.get('key', '')
|
||||
ch_idx = ch_info.get('index')
|
||||
if ch_key and ch_idx is not None:
|
||||
channel_secrets[ch_idx] = ch_key
|
||||
|
||||
# Convert DB rows to frontend-compatible format
|
||||
messages = []
|
||||
for row in db_messages:
|
||||
pkt_payload = row.get('pkt_payload')
|
||||
ch_idx = row.get('channel_idx', 0)
|
||||
sender_ts = row.get('sender_timestamp')
|
||||
txt_type = row.get('txt_type', 0)
|
||||
|
||||
# Compute pkt_payload if not stored (v2: meshcore doesn't provide it)
|
||||
if not pkt_payload and sender_ts and ch_idx in channel_secrets:
|
||||
# Reconstruct raw_text as firmware sends it: "SenderName: message"
|
||||
sender = row.get('sender', '')
|
||||
content = row.get('content', '')
|
||||
is_own = bool(row.get('is_own', 0))
|
||||
if is_own:
|
||||
device_name = runtime_config.get_device_name() or ''
|
||||
raw_text = f"{device_name}: {content}" if device_name else content
|
||||
else:
|
||||
raw_text = f"{sender}: {content}" if sender else content
|
||||
pkt_payload = compute_pkt_payload(
|
||||
channel_secrets[ch_idx], sender_ts, txt_type, raw_text
|
||||
)
|
||||
|
||||
msg = {
|
||||
'sender': row.get('sender', ''),
|
||||
'content': row.get('content', ''),
|
||||
@@ -423,19 +452,20 @@ def get_messages():
|
||||
'is_own': bool(row.get('is_own', 0)),
|
||||
'snr': row.get('snr'),
|
||||
'path_len': row.get('path_len'),
|
||||
'channel_idx': row.get('channel_idx', 0),
|
||||
'sender_timestamp': row.get('sender_timestamp'),
|
||||
'txt_type': row.get('txt_type', 0),
|
||||
'channel_idx': ch_idx,
|
||||
'sender_timestamp': sender_ts,
|
||||
'txt_type': txt_type,
|
||||
'raw_text': row.get('content', ''),
|
||||
'pkt_payload': pkt_payload,
|
||||
}
|
||||
|
||||
# Enrich own messages with echo data and analyzer URL
|
||||
if msg['is_own'] and pkt_payload:
|
||||
echoes = db.get_echoes_for_message(pkt_payload)
|
||||
msg['echo_count'] = len(echoes)
|
||||
msg['echo_paths'] = [e.get('path', '') for e in echoes]
|
||||
# Enrich with echo data and analyzer URL
|
||||
if pkt_payload:
|
||||
msg['analyzer_url'] = compute_analyzer_url(pkt_payload)
|
||||
if msg['is_own']:
|
||||
echoes = db.get_echoes_for_message(pkt_payload)
|
||||
msg['echo_count'] = len(echoes)
|
||||
msg['echo_paths'] = [e.get('path', '') for e in echoes]
|
||||
|
||||
messages.append(msg)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user