mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-08-05 00:12:47 +02:00
Refactor advert frame handling in CompanionFrameServer
- Improved the `_build_advert_push_frames` function to handle optional fields and ensure thread safety. - Enhanced the `on_advert_received` method to robustly process incoming contact data, including better handling of public keys and optional fields for advert details. - Added error handling to log exceptions during advert processing, improving reliability.
This commit is contained in:
@@ -94,20 +94,28 @@ logger = logging.getLogger("CompanionFrameServer")
|
||||
|
||||
def _build_advert_push_frames(data: dict) -> tuple[bytes, Optional[bytes]]:
|
||||
"""Build PUSH_CODE_ADVERT short frame and optional PUSH_CODE_NEW_ADVERT full frame from extracted data. Thread-safe for asyncio.to_thread."""
|
||||
pubkey_b = data["pubkey_b"]
|
||||
pubkey_b = data.get("pubkey_b", b"")
|
||||
if isinstance(pubkey_b, bytes):
|
||||
pubkey_b = pubkey_b[:32].ljust(32, b"\x00")
|
||||
else:
|
||||
pubkey_b = b"\x00" * 32
|
||||
short = bytes([PUSH_CODE_ADVERT]) + pubkey_b
|
||||
if not data.get("include_full"):
|
||||
return (short, None)
|
||||
op = data.get("out_path", b"")
|
||||
op = (op if isinstance(op, bytes) else bytes(op or []))[:MAX_PATH_SIZE].ljust(MAX_PATH_SIZE, b"\x00")
|
||||
nb = data.get("name_b", b"")
|
||||
nb = (nb if isinstance(nb, bytes) else (nb.encode("utf-8", errors="replace") if isinstance(nb, str) else b""))[:32].ljust(32, b"\x00")
|
||||
full = (
|
||||
bytes([PUSH_CODE_NEW_ADVERT])
|
||||
+ pubkey_b
|
||||
+ bytes([data["adv_type"], data["flags"], data["opl_byte"]])
|
||||
+ data["out_path"]
|
||||
+ data["name_b"]
|
||||
+ struct.pack("<I", data["last_advert"])
|
||||
+ struct.pack("<i", data["gps_lat_int"])
|
||||
+ struct.pack("<i", data["gps_lon_int"])
|
||||
+ struct.pack("<I", data["lastmod"])
|
||||
+ bytes([data.get("adv_type", 0), data.get("flags", 0), data.get("opl_byte", 0xFF)])
|
||||
+ op
|
||||
+ nb
|
||||
+ struct.pack("<I", data.get("last_advert", 0))
|
||||
+ struct.pack("<i", data.get("gps_lat_int", 0))
|
||||
+ struct.pack("<i", data.get("gps_lon_int", 0))
|
||||
+ struct.pack("<I", data.get("lastmod", 0))
|
||||
)
|
||||
return (short, full)
|
||||
|
||||
@@ -209,58 +217,66 @@ class CompanionFrameServer:
|
||||
_write_push(data)
|
||||
|
||||
async def on_advert_received(contact):
|
||||
if isinstance(contact, dict):
|
||||
pubkey = contact.get("public_key", b"")
|
||||
try:
|
||||
if isinstance(contact, dict):
|
||||
pubkey = contact.get("public_key", b"")
|
||||
if isinstance(pubkey, str):
|
||||
pubkey = bytes.fromhex(pubkey)
|
||||
else:
|
||||
pubkey = getattr(contact, "public_key", getattr(contact, "pub_key", b""))
|
||||
if isinstance(pubkey, str):
|
||||
pubkey = bytes.fromhex(pubkey)
|
||||
else:
|
||||
pubkey = getattr(contact, "public_key", getattr(contact, "pub_key", b""))
|
||||
if isinstance(pubkey, str):
|
||||
pubkey = bytes.fromhex(pubkey)
|
||||
if len(pubkey) < 32:
|
||||
return
|
||||
pubkey_b = pubkey[:32] if isinstance(pubkey, bytes) else bytes.fromhex(str(pubkey))[:32]
|
||||
include_full = (
|
||||
not isinstance(contact, dict)
|
||||
and hasattr(contact, "name")
|
||||
and contact.name
|
||||
)
|
||||
data = {
|
||||
"pubkey_b": pubkey_b,
|
||||
"include_full": include_full,
|
||||
"adv_type": 0,
|
||||
"flags": 0,
|
||||
"opl_byte": 0xFF,
|
||||
"out_path": b"\x00" * MAX_PATH_SIZE,
|
||||
"name_b": b"\x00" * 32,
|
||||
"last_advert": 0,
|
||||
"gps_lat_int": 0,
|
||||
"gps_lon_int": 0,
|
||||
"lastmod": 0,
|
||||
}
|
||||
if include_full:
|
||||
data["adv_type"] = getattr(contact, "adv_type", 0)
|
||||
data["flags"] = getattr(contact, "flags", 0)
|
||||
opl = getattr(contact, "out_path_len", -1)
|
||||
data["opl_byte"] = 0xFF if opl < 0 else min(opl, 255)
|
||||
out_path = getattr(contact, "out_path", b"") or b""
|
||||
if isinstance(out_path, str):
|
||||
out_path = bytes.fromhex(out_path) if out_path else b""
|
||||
elif isinstance(out_path, (list, bytearray)):
|
||||
out_path = bytes(out_path)
|
||||
data["out_path"] = bytes(out_path)[:MAX_PATH_SIZE].ljust(MAX_PATH_SIZE, b"\x00")
|
||||
name = contact.name
|
||||
data["name_b"] = (name.encode("utf-8")[:32] if isinstance(name, str) else name[:32]).ljust(32, b"\x00")
|
||||
data["last_advert"] = getattr(contact, "last_advert_timestamp", 0)
|
||||
data["lastmod"] = getattr(contact, "lastmod", 0)
|
||||
gps_lat = getattr(contact, "gps_lat", 0.0)
|
||||
gps_lon = getattr(contact, "gps_lon", 0.0)
|
||||
data["gps_lat_int"] = int(gps_lat * 1e6)
|
||||
data["gps_lon_int"] = int(gps_lon * 1e6)
|
||||
short, full = await asyncio.to_thread(_build_advert_push_frames, data)
|
||||
_write_push(short)
|
||||
if full is not None:
|
||||
_write_push(full)
|
||||
if not isinstance(pubkey, bytes) or len(pubkey) < 32:
|
||||
return
|
||||
pubkey_b = pubkey[:32].ljust(32, b"\x00")
|
||||
include_full = (
|
||||
not isinstance(contact, dict)
|
||||
and getattr(contact, "name", None)
|
||||
)
|
||||
data = {
|
||||
"pubkey_b": pubkey_b,
|
||||
"include_full": bool(include_full),
|
||||
"adv_type": 0,
|
||||
"flags": 0,
|
||||
"opl_byte": 0xFF,
|
||||
"out_path": b"\x00" * MAX_PATH_SIZE,
|
||||
"name_b": b"\x00" * 32,
|
||||
"last_advert": 0,
|
||||
"gps_lat_int": 0,
|
||||
"gps_lon_int": 0,
|
||||
"lastmod": 0,
|
||||
}
|
||||
if include_full:
|
||||
data["adv_type"] = getattr(contact, "adv_type", 0)
|
||||
data["flags"] = getattr(contact, "flags", 0)
|
||||
opl = getattr(contact, "out_path_len", -1)
|
||||
data["opl_byte"] = 0xFF if opl < 0 else min(opl, 255)
|
||||
out_path = getattr(contact, "out_path", b"") or b""
|
||||
if isinstance(out_path, str):
|
||||
out_path = bytes.fromhex(out_path) if out_path else b""
|
||||
elif isinstance(out_path, (list, bytearray)):
|
||||
out_path = bytes(out_path)
|
||||
data["out_path"] = bytes(out_path)[:MAX_PATH_SIZE].ljust(MAX_PATH_SIZE, b"\x00")
|
||||
name = getattr(contact, "name", "") or ""
|
||||
if isinstance(name, str):
|
||||
data["name_b"] = name.encode("utf-8", errors="replace")[:32].ljust(32, b"\x00")
|
||||
elif isinstance(name, bytes):
|
||||
data["name_b"] = name[:32].ljust(32, b"\x00")
|
||||
else:
|
||||
data["name_b"] = b"\x00" * 32
|
||||
data["last_advert"] = getattr(contact, "last_advert_timestamp", 0)
|
||||
data["lastmod"] = getattr(contact, "lastmod", 0)
|
||||
gps_lat = getattr(contact, "gps_lat", 0.0)
|
||||
gps_lon = getattr(contact, "gps_lon", 0.0)
|
||||
data["gps_lat_int"] = int(gps_lat * 1e6)
|
||||
data["gps_lon_int"] = int(gps_lon * 1e6)
|
||||
short, full = await asyncio.to_thread(_build_advert_push_frames, data)
|
||||
_write_push(short)
|
||||
if full is not None:
|
||||
await asyncio.sleep(0)
|
||||
_write_push(full)
|
||||
except Exception as e:
|
||||
logger.exception("advert_received callback error: %s", e)
|
||||
|
||||
async def on_contact_path_updated(pub_key, path_len, path):
|
||||
if isinstance(pub_key, bytes) and len(pub_key) >= 32:
|
||||
|
||||
Reference in New Issue
Block a user