remoteRF-server 0.1.98__tar.gz → 0.1.99__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/PKG-INFO +1 -1
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/pyproject.toml +1 -1
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/host/host_tunnel_server.py +60 -18
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/device_manager.py +0 -1
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/PKG-INFO +1 -1
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/README.md +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/setup.cfg +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/api_token.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/db_connection.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/db_location.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/list_string.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/process_arg.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/drivers/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/host/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/host/host_directory_store.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/acc_perms.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/cert_provider.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/grpc_server.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/reservation.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/rpc_manager.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/user_group_cli.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/user_group_handler.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/serverrf_cli.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/tools/__init__.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/tools/gen_certs.py +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/SOURCES.txt +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/dependency_links.txt +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/entry_points.txt +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/requires.txt +0 -0
- {remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/top_level.txt +0 -0
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/host/host_tunnel_server.py
RENAMED
|
@@ -263,6 +263,7 @@ class HostTunnelRegistry:
|
|
|
263
263
|
|
|
264
264
|
Enforces:
|
|
265
265
|
- device_id is globally unique across hosts (rejects conflicting host announce)
|
|
266
|
+
- STRICT MODE: device_id MUST be a canonical decimal gid string ("10", not "010", not "pluto:...")
|
|
266
267
|
"""
|
|
267
268
|
|
|
268
269
|
def __init__(self, *, active_cache_ttl_ms: int = 250, dir_cache_ttl_ms: int = 1000) -> None:
|
|
@@ -346,8 +347,15 @@ class HostTunnelRegistry:
|
|
|
346
347
|
all_devices: List[str] = sorted(set(known_devices) | devices_from_host_lists)
|
|
347
348
|
|
|
348
349
|
for device_id in all_devices:
|
|
350
|
+
device_id = (device_id or "").strip()
|
|
349
351
|
if not device_id:
|
|
350
352
|
continue
|
|
353
|
+
|
|
354
|
+
# STRICT MODE: ignore any persisted non-numeric / non-canonical IDs
|
|
355
|
+
if not device_id.isdigit() or device_id != str(int(device_id)):
|
|
356
|
+
warn(f"[registry] skipping persisted non-numeric/non-canonical device_id={device_id!r}")
|
|
357
|
+
continue
|
|
358
|
+
|
|
351
359
|
dk = sanitize_env_key(device_id)
|
|
352
360
|
|
|
353
361
|
host_id = (kv_meta.get(f"DEVICE_{dk}_HOST", "") or "").strip()
|
|
@@ -561,12 +569,40 @@ class HostTunnelRegistry:
|
|
|
561
569
|
def announce_devices(self, host_id: str, devices: list) -> None:
|
|
562
570
|
info(f"[registry] announce_devices: host_id={host_id!r} n={len(devices)}")
|
|
563
571
|
|
|
572
|
+
# STRICT MODE:
|
|
573
|
+
# - device_id MUST be canonical decimal string for gid (e.g. "10")
|
|
574
|
+
# - reject "010", reject "pluto:...", reject duplicates in a single announce
|
|
575
|
+
pairs: List[Tuple[Any, str]] = []
|
|
576
|
+
seen: Set[str] = set()
|
|
577
|
+
|
|
578
|
+
for d in devices:
|
|
579
|
+
raw = str(getattr(d, "device_id", "") or "").strip()
|
|
580
|
+
if not raw:
|
|
581
|
+
continue
|
|
582
|
+
|
|
583
|
+
if not raw.isdigit():
|
|
584
|
+
raise ValueError(
|
|
585
|
+
f"Host device_id must be a numeric gid string (e.g. '10'). "
|
|
586
|
+
f"Got {raw!r} from host_id={host_id!r}."
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
canon = str(int(raw))
|
|
590
|
+
if raw != canon:
|
|
591
|
+
raise ValueError(
|
|
592
|
+
f"Host device_id must be canonical decimal with no leading zeros. "
|
|
593
|
+
f"Got {raw!r}; use {canon!r} (host_id={host_id!r})."
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
if canon in seen:
|
|
597
|
+
raise ValueError(
|
|
598
|
+
f"Duplicate device_id {canon!r} in device announce from host_id={host_id!r}."
|
|
599
|
+
)
|
|
600
|
+
seen.add(canon)
|
|
601
|
+
pairs.append((d, canon))
|
|
602
|
+
|
|
564
603
|
# conflict check first (no partial apply)
|
|
565
604
|
with self._lock:
|
|
566
|
-
for
|
|
567
|
-
device_id = str(getattr(d, "device_id", "")).strip()
|
|
568
|
-
if not device_id:
|
|
569
|
-
continue
|
|
605
|
+
for _, device_id in pairs:
|
|
570
606
|
existing = self._routes.get(device_id)
|
|
571
607
|
if existing is not None and existing.host_id != host_id:
|
|
572
608
|
warn(
|
|
@@ -583,12 +619,13 @@ class HostTunnelRegistry:
|
|
|
583
619
|
with self._lock:
|
|
584
620
|
self._host_devices.setdefault(host_id, set())
|
|
585
621
|
|
|
622
|
+
# Preserve old behavior: skip empty ids with warn (but strict checks already handled non-empty bad ones)
|
|
586
623
|
for d in devices:
|
|
587
|
-
|
|
588
|
-
if not
|
|
624
|
+
device_id0 = str(getattr(d, "device_id", "") or "").strip()
|
|
625
|
+
if not device_id0:
|
|
589
626
|
warn(f"[registry] announce_devices: skipping device with empty device_id host_id={host_id!r}")
|
|
590
|
-
continue
|
|
591
627
|
|
|
628
|
+
for d, device_id in pairs:
|
|
592
629
|
try:
|
|
593
630
|
local_id = int(getattr(d, "local_id", 0))
|
|
594
631
|
except Exception:
|
|
@@ -620,10 +657,12 @@ class HostTunnelRegistry:
|
|
|
620
657
|
try:
|
|
621
658
|
tmp = host_tunnel_pb2.DeviceInfo()
|
|
622
659
|
tmp.CopyFrom(d)
|
|
660
|
+
# ensure stored info reflects canonical device_id key
|
|
661
|
+
tmp.device_id = str(device_id)
|
|
623
662
|
self._device_infos[device_id] = tmp
|
|
624
663
|
except Exception:
|
|
625
664
|
self._device_infos[device_id] = host_tunnel_pb2.DeviceInfo(
|
|
626
|
-
device_id=device_id,
|
|
665
|
+
device_id=str(device_id),
|
|
627
666
|
local_id=int(local_id),
|
|
628
667
|
label=label,
|
|
629
668
|
serial=serial,
|
|
@@ -1077,6 +1116,12 @@ class HostTunnelServicer(host_tunnel_pb2_grpc.HostTunnelServicer):
|
|
|
1077
1116
|
try:
|
|
1078
1117
|
self.registry.announce_devices(host_id, list(ann.devices))
|
|
1079
1118
|
info(f"[inbound] registry announce applied host_id={host_id!r} stream_sess={stream_uuid}")
|
|
1119
|
+
except ValueError as e:
|
|
1120
|
+
error(f"[inbound] INVALID_ARGUMENT device announce host_id={host_id!r} stream_sess={stream_uuid} err={e}")
|
|
1121
|
+
fatal["code"] = "INVALID_ARGUMENT"
|
|
1122
|
+
fatal["details"] = str(e)
|
|
1123
|
+
stop.set()
|
|
1124
|
+
return
|
|
1080
1125
|
except DeviceIdConflictError as e:
|
|
1081
1126
|
error(f"[inbound] DeviceIdConflictError host_id={host_id!r} stream_sess={stream_uuid} err={e}")
|
|
1082
1127
|
fatal["code"] = "ALREADY_EXISTS"
|
|
@@ -1123,7 +1168,7 @@ class HostTunnelServicer(host_tunnel_pb2_grpc.HostTunnelServicer):
|
|
|
1123
1168
|
err_s = str(getattr(mr, "error", "") or "")
|
|
1124
1169
|
info(f"[inbound] META_RESPONSE ok={ok} error={err_s!r} stream_sess={stream_uuid}")
|
|
1125
1170
|
|
|
1126
|
-
# ----
|
|
1171
|
+
# ---- apply devices from meta_response if present ----
|
|
1127
1172
|
if ok and host_id is not None:
|
|
1128
1173
|
devs = []
|
|
1129
1174
|
# try common field names defensively
|
|
@@ -1142,6 +1187,12 @@ class HostTunnelServicer(host_tunnel_pb2_grpc.HostTunnelServicer):
|
|
|
1142
1187
|
self.registry.announce_devices(host_id, devs)
|
|
1143
1188
|
# optional: heartbeat bump
|
|
1144
1189
|
self.registry.heartbeat(host_id, now_ms())
|
|
1190
|
+
except ValueError as e:
|
|
1191
|
+
error(f"[inbound] META_RESPONSE INVALID_ARGUMENT host_id={host_id!r} err={e}")
|
|
1192
|
+
fatal["code"] = "INVALID_ARGUMENT"
|
|
1193
|
+
fatal["details"] = str(e)
|
|
1194
|
+
stop.set()
|
|
1195
|
+
return
|
|
1145
1196
|
except Exception:
|
|
1146
1197
|
exception("[inbound] META_RESPONSE announce_devices failed")
|
|
1147
1198
|
else:
|
|
@@ -1330,15 +1381,6 @@ _TUNNEL_REGISTRY_LOCK = threading.Lock()
|
|
|
1330
1381
|
TUNNEL_REGISTRY: Optional["HostTunnelRegistry"] = None
|
|
1331
1382
|
|
|
1332
1383
|
def get_tunnel_registry(*, create: bool = True) -> Optional["HostTunnelRegistry"]:
|
|
1333
|
-
"""
|
|
1334
|
-
Returns the process-wide HostTunnelRegistry instance.
|
|
1335
|
-
|
|
1336
|
-
IMPORTANT: Import the MODULE (e.g. `import ... as hts`) and access
|
|
1337
|
-
`hts.get_tunnel_registry()` or `hts.TUNNEL_REGISTRY`.
|
|
1338
|
-
|
|
1339
|
-
Avoid `from host_tunnel_server import TUNNEL_REGISTRY` if you ever plan
|
|
1340
|
-
to replace it, because that snapshots the value at import time.
|
|
1341
|
-
"""
|
|
1342
1384
|
global TUNNEL_REGISTRY
|
|
1343
1385
|
|
|
1344
1386
|
if TUNNEL_REGISTRY is not None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/__init__.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_host_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_pb2.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/__init__.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/ansi_codes.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/api_token.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/db_connection.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/db_location.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/list_string.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/common/utils/process_arg.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/host/host_directory_store.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/cert_provider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/user_group_cli.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server/server/user_group_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.98 → remoterf_server-0.1.99}/src/remoteRF_server.egg-info/top_level.txt
RENAMED
|
File without changes
|