mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
Phase 7: Integration & Migration
This commit is contained in:
@@ -7,6 +7,7 @@ import logging
|
||||
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
|
||||
|
||||
from app.fanout.base import FanoutModule
|
||||
from app.path_utils import split_path_hex
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -45,9 +46,12 @@ def _format_body(data: dict, *, include_path: bool) -> str:
|
||||
if include_path:
|
||||
paths = data.get("paths")
|
||||
if paths and isinstance(paths, list) and len(paths) > 0:
|
||||
path_str = paths[0].get("path", "") if isinstance(paths[0], dict) else ""
|
||||
first_path = paths[0] if isinstance(paths[0], dict) else {}
|
||||
path_str = first_path.get("path", "")
|
||||
path_len = first_path.get("path_len")
|
||||
else:
|
||||
path_str = None
|
||||
path_len = None
|
||||
|
||||
if msg_type == "PRIV" and path_str is None:
|
||||
via = " **via:** [`direct`]"
|
||||
@@ -56,7 +60,8 @@ def _format_body(data: dict, *, include_path: bool) -> str:
|
||||
if path_str == "":
|
||||
via = " **via:** [`direct`]"
|
||||
else:
|
||||
hops = [path_str[i : i + 2] for i in range(0, len(path_str), 2)]
|
||||
hop_count = path_len if isinstance(path_len, int) else len(path_str) // 2
|
||||
hops = split_path_hex(path_str, hop_count)
|
||||
if hops:
|
||||
hop_list = ", ".join(f"`{h}`" for h in hops)
|
||||
via = f" **via:** [{hop_list}]"
|
||||
|
||||
@@ -24,6 +24,7 @@ import aiomqtt
|
||||
import nacl.bindings
|
||||
|
||||
from app.fanout.mqtt_base import BaseMqttPublisher
|
||||
from app.path_utils import split_path_hex
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -153,23 +154,29 @@ def _calculate_packet_hash(raw_bytes: bytes) -> str:
|
||||
if has_transport:
|
||||
offset += 4 # Skip 4 bytes of transport codes
|
||||
|
||||
# Read path_len (1 byte on wire). Invalid/truncated packets map to zero hash.
|
||||
# Read path byte (packed as [hash_mode:2][hop_count:6]).
|
||||
# Invalid/truncated packets map to zero hash.
|
||||
if offset >= len(raw_bytes):
|
||||
return "0" * 16
|
||||
path_len = raw_bytes[offset]
|
||||
path_byte = raw_bytes[offset]
|
||||
offset += 1
|
||||
hash_mode = (path_byte >> 6) & 0x03
|
||||
hop_count = path_byte & 0x3F
|
||||
hash_size = (hash_mode + 1) if hash_mode < 3 else 1
|
||||
path_wire_len = hop_count * hash_size
|
||||
|
||||
# Skip past path to get to payload. Invalid/truncated packets map to zero hash.
|
||||
if len(raw_bytes) < offset + path_len:
|
||||
if len(raw_bytes) < offset + path_wire_len:
|
||||
return "0" * 16
|
||||
payload_start = offset + path_len
|
||||
payload_start = offset + path_wire_len
|
||||
payload_data = raw_bytes[payload_start:]
|
||||
|
||||
# Hash: payload_type(1 byte) [+ path_len as uint16_t LE for TRACE] + payload_data
|
||||
# Hash: payload_type(1 byte) [+ path_byte as uint16_t LE for TRACE] + payload_data
|
||||
# IMPORTANT: TRACE hash uses the raw wire byte (not decoded hop count) to match firmware.
|
||||
hash_obj = hashlib.sha256()
|
||||
hash_obj.update(bytes([payload_type]))
|
||||
if payload_type == 9: # PAYLOAD_TYPE_TRACE
|
||||
hash_obj.update(path_len.to_bytes(2, byteorder="little"))
|
||||
hash_obj.update(path_byte.to_bytes(2, byteorder="little"))
|
||||
hash_obj.update(payload_data)
|
||||
|
||||
return hash_obj.hexdigest()[:16].upper()
|
||||
@@ -209,20 +216,24 @@ def _decode_packet_fields(raw_bytes: bytes) -> tuple[str, str, str, list[str], i
|
||||
if len(raw_bytes) <= offset:
|
||||
return route, packet_type, payload_len, path_values, payload_type
|
||||
|
||||
path_len = raw_bytes[offset]
|
||||
path_byte = raw_bytes[offset]
|
||||
offset += 1
|
||||
hash_mode = (path_byte >> 6) & 0x03
|
||||
hop_count = path_byte & 0x3F
|
||||
hash_size = (hash_mode + 1) if hash_mode < 3 else 1
|
||||
path_wire_len = hop_count * hash_size
|
||||
|
||||
if len(raw_bytes) < offset + path_len:
|
||||
if len(raw_bytes) < offset + path_wire_len:
|
||||
return route, packet_type, payload_len, path_values, payload_type
|
||||
|
||||
path_bytes = raw_bytes[offset : offset + path_len]
|
||||
offset += path_len
|
||||
path_bytes = raw_bytes[offset : offset + path_wire_len]
|
||||
offset += path_wire_len
|
||||
|
||||
payload_type = (header >> 2) & 0x0F
|
||||
route = _ROUTE_MAP.get(route_type, "U")
|
||||
packet_type = str(payload_type)
|
||||
payload_len = str(max(0, len(raw_bytes) - offset))
|
||||
path_values = [f"{b:02x}" for b in path_bytes]
|
||||
path_values = split_path_hex(path_bytes.hex(), hop_count)
|
||||
|
||||
return route, packet_type, payload_len, path_values, payload_type
|
||||
except Exception:
|
||||
|
||||
@@ -456,16 +456,20 @@ def _extract_payload_for_hash(raw_packet: bytes) -> bytes | None:
|
||||
return None
|
||||
offset += 4
|
||||
|
||||
# Get path length
|
||||
# Get path byte (packed as [hash_mode:2][hop_count:6])
|
||||
if len(raw_packet) < offset + 1:
|
||||
return None
|
||||
path_length = raw_packet[offset]
|
||||
path_byte = raw_packet[offset]
|
||||
offset += 1
|
||||
hash_mode = (path_byte >> 6) & 0x03
|
||||
hop_count = path_byte & 0x3F
|
||||
hash_size = (hash_mode + 1) if hash_mode < 3 else 1
|
||||
path_wire_len = hop_count * hash_size
|
||||
|
||||
# Skip path bytes
|
||||
if len(raw_packet) < offset + path_length:
|
||||
if len(raw_packet) < offset + path_wire_len:
|
||||
return None
|
||||
offset += path_length
|
||||
offset += path_wire_len
|
||||
|
||||
# Rest is payload (may be empty, matching decoder.py behavior)
|
||||
return raw_packet[offset:]
|
||||
@@ -638,16 +642,20 @@ def _extract_path_from_packet(raw_packet: bytes) -> str | None:
|
||||
return None
|
||||
offset += 4
|
||||
|
||||
# Get path length
|
||||
# Get path byte (packed as [hash_mode:2][hop_count:6])
|
||||
if len(raw_packet) < offset + 1:
|
||||
return None
|
||||
path_length = raw_packet[offset]
|
||||
path_byte = raw_packet[offset]
|
||||
offset += 1
|
||||
hash_mode = (path_byte >> 6) & 0x03
|
||||
hop_count = path_byte & 0x3F
|
||||
hash_size = (hash_mode + 1) if hash_mode < 3 else 1
|
||||
path_wire_len = hop_count * hash_size
|
||||
|
||||
# Extract path bytes
|
||||
if len(raw_packet) < offset + path_length:
|
||||
if len(raw_packet) < offset + path_wire_len:
|
||||
return None
|
||||
path_bytes = raw_packet[offset : offset + path_length]
|
||||
path_bytes = raw_packet[offset : offset + path_wire_len]
|
||||
|
||||
return path_bytes.hex()
|
||||
except (IndexError, ValueError):
|
||||
|
||||
@@ -24,15 +24,18 @@ function extractPayload(packetHex: string): string | null {
|
||||
offset += 8; // 4 bytes = 8 hex chars
|
||||
}
|
||||
|
||||
// Get path length
|
||||
// Get path byte (packed as [hash_mode:2][hop_count:6])
|
||||
if (packetHex.length < offset + 2) return null;
|
||||
const pathLength = parseInt(packetHex.slice(offset, offset + 2), 16);
|
||||
const pathByte = parseInt(packetHex.slice(offset, offset + 2), 16);
|
||||
offset += 2;
|
||||
const hashMode = (pathByte >> 6) & 0x03;
|
||||
const hopCount = pathByte & 0x3f;
|
||||
const hashSize = hashMode < 3 ? hashMode + 1 : 1;
|
||||
const pathHexChars = hopCount * hashSize * 2;
|
||||
|
||||
// Skip path data
|
||||
const pathBytes = pathLength * 2; // hex chars
|
||||
if (packetHex.length < offset + pathBytes) return null;
|
||||
offset += pathBytes;
|
||||
if (packetHex.length < offset + pathHexChars) return null;
|
||||
offset += pathHexChars;
|
||||
|
||||
// Rest is payload
|
||||
return packetHex.slice(offset);
|
||||
|
||||
Reference in New Issue
Block a user