mirror of
https://github.com/l5yth/potato-mesh.git
synced 2026-07-06 09:52:02 +02:00
Handle proto values in nodeinfo payloads (#167)
This commit is contained in:
+30
-8
@@ -483,18 +483,28 @@ def _node_num_from_id(node_id) -> int | None:
|
||||
def _merge_mappings(base, extra):
|
||||
"""Recursively merge mapping ``extra`` into ``base`` without mutation."""
|
||||
|
||||
base_dict: dict
|
||||
if isinstance(base, Mapping):
|
||||
base_dict = dict(base)
|
||||
elif base:
|
||||
converted_base = _node_to_dict(base)
|
||||
base_dict = dict(converted_base) if isinstance(converted_base, Mapping) else {}
|
||||
else:
|
||||
base_dict = {}
|
||||
|
||||
if not isinstance(extra, Mapping):
|
||||
return base if isinstance(base, Mapping) else (dict(base) if base else {})
|
||||
result = dict(base) if isinstance(base, Mapping) else {}
|
||||
converted_extra = _node_to_dict(extra)
|
||||
if not isinstance(converted_extra, Mapping):
|
||||
return base_dict
|
||||
extra = converted_extra
|
||||
|
||||
for key, value in extra.items():
|
||||
if isinstance(value, Mapping):
|
||||
existing = result.get(key)
|
||||
result[key] = _merge_mappings(
|
||||
existing if isinstance(existing, Mapping) else {}, value
|
||||
)
|
||||
existing = base_dict.get(key)
|
||||
base_dict[key] = _merge_mappings(existing, value)
|
||||
else:
|
||||
result[key] = value
|
||||
return result
|
||||
base_dict[key] = _node_to_dict(value)
|
||||
return base_dict
|
||||
|
||||
|
||||
def _extract_payload_bytes(decoded_section: Mapping) -> bytes | None:
|
||||
@@ -616,6 +626,18 @@ def _nodeinfo_user_dict(node_info, decoded_user) -> dict | None:
|
||||
except Exception:
|
||||
user_dict = None
|
||||
|
||||
if isinstance(decoded_user, ProtoMessage):
|
||||
try:
|
||||
from google.protobuf.json_format import MessageToDict
|
||||
|
||||
decoded_user = MessageToDict(
|
||||
decoded_user,
|
||||
preserving_proto_field_name=False,
|
||||
use_integers_for_enums=False,
|
||||
)
|
||||
except Exception:
|
||||
decoded_user = _node_to_dict(decoded_user)
|
||||
|
||||
if isinstance(decoded_user, Mapping):
|
||||
user_dict = _merge_mappings(user_dict, decoded_user)
|
||||
|
||||
|
||||
@@ -417,6 +417,91 @@ def test_store_packet_dict_handles_user_only_nodeinfo(mesh_module, monkeypatch):
|
||||
assert "deviceMetrics" not in node_entry
|
||||
|
||||
|
||||
def test_store_packet_dict_nodeinfo_merges_proto_user(mesh_module, monkeypatch):
|
||||
mesh = mesh_module
|
||||
captured = []
|
||||
monkeypatch.setattr(
|
||||
mesh,
|
||||
"_queue_post_json",
|
||||
lambda path, payload, *, priority: captured.append((path, payload, priority)),
|
||||
)
|
||||
|
||||
from meshtastic.protobuf import mesh_pb2
|
||||
|
||||
user_msg = mesh_pb2.User()
|
||||
user_msg.id = "!44556677"
|
||||
user_msg.short_name = "Proto"
|
||||
user_msg.long_name = "Proto User"
|
||||
|
||||
node_info = mesh_pb2.NodeInfo()
|
||||
node_info.snr = 2.5
|
||||
|
||||
payload_b64 = base64.b64encode(node_info.SerializeToString()).decode()
|
||||
packet = {
|
||||
"id": 73,
|
||||
"rxTime": 5_000,
|
||||
"fromId": "!44556677",
|
||||
"decoded": {
|
||||
"portnum": "NODEINFO_APP",
|
||||
"payload": {"__bytes_b64__": payload_b64},
|
||||
"user": user_msg,
|
||||
},
|
||||
}
|
||||
|
||||
mesh.store_packet_dict(packet)
|
||||
|
||||
assert captured
|
||||
_, payload, _ = captured[0]
|
||||
node_entry = payload["!44556677"]
|
||||
assert node_entry["lastHeard"] == 5_000
|
||||
assert node_entry["user"]["shortName"] == "Proto"
|
||||
assert node_entry["user"]["longName"] == "Proto User"
|
||||
|
||||
|
||||
def test_store_packet_dict_nodeinfo_sanitizes_nested_proto(mesh_module, monkeypatch):
|
||||
mesh = mesh_module
|
||||
captured = []
|
||||
monkeypatch.setattr(
|
||||
mesh,
|
||||
"_queue_post_json",
|
||||
lambda path, payload, *, priority: captured.append((path, payload, priority)),
|
||||
)
|
||||
|
||||
from meshtastic.protobuf import mesh_pb2
|
||||
|
||||
user_msg = mesh_pb2.User()
|
||||
user_msg.id = "!55667788"
|
||||
user_msg.short_name = "Nested"
|
||||
|
||||
node_info = mesh_pb2.NodeInfo()
|
||||
node_info.hops_away = 1
|
||||
|
||||
payload_b64 = base64.b64encode(node_info.SerializeToString()).decode()
|
||||
packet = {
|
||||
"id": 74,
|
||||
"rxTime": 6_000,
|
||||
"fromId": "!55667788",
|
||||
"decoded": {
|
||||
"portnum": "NODEINFO_APP",
|
||||
"payload": {"__bytes_b64__": payload_b64},
|
||||
"user": {
|
||||
"id": "!55667788",
|
||||
"shortName": "Nested",
|
||||
"raw": user_msg,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mesh.store_packet_dict(packet)
|
||||
|
||||
assert captured
|
||||
_, payload, _ = captured[0]
|
||||
node_entry = payload["!55667788"]
|
||||
assert node_entry["user"]["shortName"] == "Nested"
|
||||
assert isinstance(node_entry["user"]["raw"], dict)
|
||||
assert node_entry["user"]["raw"]["id"] == "!55667788"
|
||||
|
||||
|
||||
def test_store_packet_dict_nodeinfo_uses_from_id_when_user_missing(
|
||||
mesh_module, monkeypatch
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user