remoteRF-server 0.1.66__tar.gz → 0.1.68__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.66 → remoterf_server-0.1.68}/PKG-INFO +1 -1
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/pyproject.toml +1 -1
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/host/host_tunnel_server.py +62 -11
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/grpc_server.py +95 -2
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/PKG-INFO +1 -1
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/README.md +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/setup.cfg +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/api_token.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/db_connection.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/db_location.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/list_string.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/process_arg.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/drivers/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/host/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/host/host_directory_store.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/acc_perms.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/cert_provider.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/device_manager.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/reservation.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/rpc_manager.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/user_group_cli.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/user_group_handler.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/serverrf_cli.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/tools/__init__.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/tools/gen_certs.py +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/SOURCES.txt +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/dependency_links.txt +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/entry_points.txt +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/requires.txt +0 -0
- {remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/top_level.txt +0 -0
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/host/host_tunnel_server.py
RENAMED
|
@@ -18,6 +18,7 @@ from concurrent.futures import Future
|
|
|
18
18
|
from concurrent import futures
|
|
19
19
|
|
|
20
20
|
import grpc
|
|
21
|
+
import os
|
|
21
22
|
|
|
22
23
|
# Your existing GenericRPC schema compiled to python.
|
|
23
24
|
from ..common.grpc import grpc_pb2 as generic_pb2 # type: ignore
|
|
@@ -38,9 +39,58 @@ from .host_directory_store import (
|
|
|
38
39
|
)
|
|
39
40
|
|
|
40
41
|
# =============================================================================
|
|
41
|
-
# Always-on logging
|
|
42
|
+
# Always-on logging with lightweight toggles (env + runtime)
|
|
42
43
|
# =============================================================================
|
|
43
44
|
|
|
45
|
+
_LOG_LOCK = threading.Lock()
|
|
46
|
+
_LOG_LEVELS: set[str] = set() # {"INFO","WARN","ERROR"}
|
|
47
|
+
_LOG_SUPPRESS: set[str] = set() # {"HEARTBEAT","OUTBOUND","INBOUND"}
|
|
48
|
+
|
|
49
|
+
def _init_log_state_from_env() -> None:
|
|
50
|
+
"""
|
|
51
|
+
Env knobs:
|
|
52
|
+
REMOTERF_LOG_LEVELS="INFO,WARN,ERROR" (default: WARN,ERROR)
|
|
53
|
+
REMOTERF_LOG_SUPPRESS="HEARTBEAT" (default: HEARTBEAT)
|
|
54
|
+
"""
|
|
55
|
+
global _LOG_LEVELS, _LOG_SUPPRESS
|
|
56
|
+
|
|
57
|
+
levels = os.getenv("REMOTERF_LOG_LEVELS", "").strip()
|
|
58
|
+
suppress = os.getenv("REMOTERF_LOG_SUPPRESS", "").strip()
|
|
59
|
+
|
|
60
|
+
if not levels:
|
|
61
|
+
_LOG_LEVELS = {"WARN", "ERROR"}
|
|
62
|
+
else:
|
|
63
|
+
_LOG_LEVELS = {x.strip().upper() for x in levels.split(",") if x.strip()}
|
|
64
|
+
|
|
65
|
+
if not suppress:
|
|
66
|
+
_LOG_SUPPRESS = {"HEARTBEAT"} # sane default: avoid spam
|
|
67
|
+
else:
|
|
68
|
+
_LOG_SUPPRESS = {x.strip().upper() for x in suppress.split(",") if x.strip()}
|
|
69
|
+
|
|
70
|
+
_init_log_state_from_env()
|
|
71
|
+
|
|
72
|
+
def set_log_levels(levels: str) -> None:
|
|
73
|
+
"""Runtime: set levels, e.g. set_log_levels('INFO,WARN,ERROR')"""
|
|
74
|
+
global _LOG_LEVELS
|
|
75
|
+
with _LOG_LOCK:
|
|
76
|
+
_LOG_LEVELS = {x.strip().upper() for x in (levels or "").split(",") if x.strip()}
|
|
77
|
+
|
|
78
|
+
def set_log_suppress(tags: str) -> None:
|
|
79
|
+
"""Runtime: set suppressed tags, e.g. set_log_suppress('HEARTBEAT,OUTBOUND')"""
|
|
80
|
+
global _LOG_SUPPRESS
|
|
81
|
+
with _LOG_LOCK:
|
|
82
|
+
_LOG_SUPPRESS = {x.strip().upper() for x in (tags or "").split(",") if x.strip()}
|
|
83
|
+
|
|
84
|
+
def _should_log(level: str, tag: str = "") -> bool:
|
|
85
|
+
lvl = (level or "").upper()
|
|
86
|
+
tg = (tag or "").upper()
|
|
87
|
+
with _LOG_LOCK:
|
|
88
|
+
if lvl not in _LOG_LEVELS:
|
|
89
|
+
return False
|
|
90
|
+
if tg and tg in _LOG_SUPPRESS:
|
|
91
|
+
return False
|
|
92
|
+
return True
|
|
93
|
+
|
|
44
94
|
def _ts() -> str:
|
|
45
95
|
t = time.time()
|
|
46
96
|
sec = int(t)
|
|
@@ -48,24 +98,25 @@ def _ts() -> str:
|
|
|
48
98
|
lt = time.localtime(sec)
|
|
49
99
|
return time.strftime("%H:%M:%S", lt) + f".{ms:03d}"
|
|
50
100
|
|
|
51
|
-
def _log(level: str, msg: str) -> None:
|
|
101
|
+
def _log(level: str, msg: str, *, tag: str = "") -> None:
|
|
102
|
+
if not _should_log(level, tag):
|
|
103
|
+
return
|
|
52
104
|
tn = threading.current_thread().name
|
|
53
105
|
print(f"{_ts()} {level:<5} [{tn}] hostrf.host_tunnel_server: {msg}", file=sys.stderr, flush=True)
|
|
54
106
|
|
|
55
|
-
def info(msg: str) -> None:
|
|
56
|
-
_log("INFO", msg)
|
|
107
|
+
def info(msg: str, *, tag: str = "") -> None:
|
|
108
|
+
_log("INFO", msg, tag=tag)
|
|
57
109
|
|
|
58
|
-
def warn(msg: str) -> None:
|
|
59
|
-
_log("WARN", msg)
|
|
110
|
+
def warn(msg: str, *, tag: str = "") -> None:
|
|
111
|
+
_log("WARN", msg, tag=tag)
|
|
60
112
|
|
|
61
|
-
def error(msg: str) -> None:
|
|
62
|
-
_log("ERROR", msg)
|
|
113
|
+
def error(msg: str, *, tag: str = "") -> None:
|
|
114
|
+
_log("ERROR", msg, tag=tag)
|
|
63
115
|
|
|
64
|
-
def exception(msg: str) -> None:
|
|
65
|
-
_log("ERROR", msg)
|
|
116
|
+
def exception(msg: str, *, tag: str = "") -> None:
|
|
117
|
+
_log("ERROR", msg, tag=tag)
|
|
66
118
|
traceback.print_exc(limit=80, file=sys.stderr)
|
|
67
119
|
|
|
68
|
-
|
|
69
120
|
# =============================================================================
|
|
70
121
|
# Helpers
|
|
71
122
|
# =============================================================================
|
|
@@ -17,6 +17,8 @@ from datetime import datetime
|
|
|
17
17
|
# os.environ.setdefault("GRPC_VERBOSITY", "ERROR")
|
|
18
18
|
# os.environ.setdefault("GRPC_TRACE", "")
|
|
19
19
|
|
|
20
|
+
TUNNEL_REGISTRY: HostTunnelRegistry | None = None
|
|
21
|
+
|
|
20
22
|
import grpc
|
|
21
23
|
|
|
22
24
|
import traceback
|
|
@@ -201,10 +203,13 @@ def serve():
|
|
|
201
203
|
|
|
202
204
|
# --- attach HostTunnel to the SAME grpc server/port/creds ---
|
|
203
205
|
directory_env = Path(__file__).resolve().parent.parent / "config" / ".env.host_directory"
|
|
204
|
-
|
|
206
|
+
|
|
207
|
+
# --- attach HostTunnel to the SAME grpc server/port/creds ---
|
|
208
|
+
global TUNNEL_REGISTRY
|
|
209
|
+
TUNNEL_REGISTRY = HostTunnelRegistry()
|
|
205
210
|
|
|
206
211
|
host_tunnel_pb2_grpc.add_HostTunnelServicer_to_server(
|
|
207
|
-
HostTunnelServicer(
|
|
212
|
+
HostTunnelServicer(TUNNEL_REGISTRY),
|
|
208
213
|
server
|
|
209
214
|
)
|
|
210
215
|
|
|
@@ -366,6 +371,81 @@ def get_devices():
|
|
|
366
371
|
for key, value in data.items():
|
|
367
372
|
printf(f"Device ID:", Sty.DEFAULT, f' {key}', Sty.MAGENTA, f" Device Name: ", Sty.DEFAULT, f"{(value)}", Sty.GRAY)
|
|
368
373
|
|
|
374
|
+
def _fmt_ms_ago(ms: int) -> str:
|
|
375
|
+
if not ms:
|
|
376
|
+
return "-"
|
|
377
|
+
now = int(time.time() * 1000)
|
|
378
|
+
dt = max(0, now - int(ms))
|
|
379
|
+
if dt < 1000:
|
|
380
|
+
return f"{dt}ms"
|
|
381
|
+
if dt < 60_000:
|
|
382
|
+
return f"{dt/1000:.1f}s"
|
|
383
|
+
return f"{dt/60_000:.1f}m"
|
|
384
|
+
|
|
385
|
+
def _cmd_hosts_status() -> None:
|
|
386
|
+
global TUNNEL_REGISTRY
|
|
387
|
+
reg = TUNNEL_REGISTRY
|
|
388
|
+
if reg is None:
|
|
389
|
+
printf("Host tunnel registry not initialized yet.", Sty.RED)
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
hosts = reg.list_hosts() # host_id -> HostStatus
|
|
393
|
+
devices = reg.list_devices() # device_id -> DeviceStatus
|
|
394
|
+
|
|
395
|
+
# Build host -> device list
|
|
396
|
+
by_host: dict[str, list[str]] = {}
|
|
397
|
+
for did, ds in devices.items():
|
|
398
|
+
by_host.setdefault(ds.host_id or "-", []).append(did)
|
|
399
|
+
|
|
400
|
+
printf("Hosts (live):", Sty.BOLD)
|
|
401
|
+
if not hosts:
|
|
402
|
+
printf(" (none)", Sty.GRAY)
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
for hid, hs in sorted(hosts.items(), key=lambda kv: kv[0]):
|
|
406
|
+
dlist = sorted(by_host.get(hid, []))
|
|
407
|
+
printf(
|
|
408
|
+
" ", Sty.DEFAULT,
|
|
409
|
+
f"{hid}", Sty.MAGENTA,
|
|
410
|
+
" online=", Sty.DEFAULT, f"{hs.online}", Sty.GREEN if hs.online else Sty.RED,
|
|
411
|
+
" last_seen=", Sty.DEFAULT, f"{_fmt_ms_ago(hs.last_seen_ms)} ago", Sty.BLUE,
|
|
412
|
+
" devices=", Sty.DEFAULT, f"{len(dlist)}", Sty.GRAY
|
|
413
|
+
)
|
|
414
|
+
for did in dlist:
|
|
415
|
+
ds = devices.get(did)
|
|
416
|
+
if ds is None:
|
|
417
|
+
continue
|
|
418
|
+
printf(
|
|
419
|
+
" - ", Sty.DEFAULT,
|
|
420
|
+
f"{did}", Sty.MAGENTA,
|
|
421
|
+
" local_id=", Sty.DEFAULT, f"{ds.host_local_id}", Sty.GRAY,
|
|
422
|
+
" online=", Sty.DEFAULT, f"{ds.online}", Sty.GREEN if ds.online else Sty.RED,
|
|
423
|
+
" last_seen=", Sty.DEFAULT, f"{_fmt_ms_ago(ds.last_seen_ms)} ago", Sty.BLUE
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
def _cmd_devices_status() -> None:
|
|
427
|
+
global TUNNEL_REGISTRY
|
|
428
|
+
reg = TUNNEL_REGISTRY
|
|
429
|
+
if reg is None:
|
|
430
|
+
printf("Host tunnel registry not initialized yet.", Sty.RED)
|
|
431
|
+
return
|
|
432
|
+
|
|
433
|
+
devices = reg.list_devices()
|
|
434
|
+
printf("Devices (live):", Sty.BOLD)
|
|
435
|
+
if not devices:
|
|
436
|
+
printf(" (none)", Sty.GRAY)
|
|
437
|
+
return
|
|
438
|
+
|
|
439
|
+
for did, ds in sorted(devices.items(), key=lambda kv: kv[0]):
|
|
440
|
+
printf(
|
|
441
|
+
" ", Sty.DEFAULT,
|
|
442
|
+
f"{did}", Sty.MAGENTA,
|
|
443
|
+
" host=", Sty.DEFAULT, f"{ds.host_id or '-'}", Sty.GRAY,
|
|
444
|
+
" local_id=", Sty.DEFAULT, f"{ds.host_local_id}", Sty.GRAY,
|
|
445
|
+
" online=", Sty.DEFAULT, f"{ds.online}", Sty.GREEN if ds.online else Sty.RED,
|
|
446
|
+
" last_seen=", Sty.DEFAULT, f"{_fmt_ms_ago(ds.last_seen_ms)} ago", Sty.BLUE
|
|
447
|
+
)
|
|
448
|
+
|
|
369
449
|
# def help():
|
|
370
450
|
# printf("/------- HELP -------/", Sty.BOLD)
|
|
371
451
|
# printf("'exit' ", Sty.MAGENTA, " - Stop server.", Sty.DEFAULT)
|
|
@@ -488,6 +568,11 @@ def help() -> None:
|
|
|
488
568
|
printf(" codes delete ", Sty.MAGENTA, "- Delete an enrollment code (interactive)", Sty.DEFAULT)
|
|
489
569
|
printf(" codes csv ", Sty.MAGENTA, "- Export ALL enrollment codes as CSV to Downloads", Sty.DEFAULT)
|
|
490
570
|
print()
|
|
571
|
+
|
|
572
|
+
printf("Host Tunnel (live):", Sty.BOLD)
|
|
573
|
+
printf(" hosts status ", Sty.MAGENTA, "- Live host online/last_seen/devices", Sty.DEFAULT)
|
|
574
|
+
printf(" devices status ", Sty.MAGENTA, "- Live device online/last_seen/route", Sty.DEFAULT)
|
|
575
|
+
print()
|
|
491
576
|
|
|
492
577
|
printf("Database:", Sty.BOLD)
|
|
493
578
|
printf(" db purge ", Sty.MAGENTA, "- Remove all database entries", Sty.DEFAULT)
|
|
@@ -581,6 +666,14 @@ def server_input(inpu: str) -> bool:
|
|
|
581
666
|
"rm code": lambda: _stay(lambda: remove_enrollment_code_local(session)), # old
|
|
582
667
|
"rm c": lambda: _stay(lambda: remove_enrollment_code_local(session)), # old
|
|
583
668
|
|
|
669
|
+
# ---- host tunnel ----
|
|
670
|
+
"hosts status": lambda: _stay(_cmd_hosts_status),
|
|
671
|
+
"host status": lambda: _stay(_cmd_hosts_status),
|
|
672
|
+
"tunnel hosts": lambda: _stay(_cmd_hosts_status),
|
|
673
|
+
|
|
674
|
+
"devices status": lambda: _stay(_cmd_devices_status),
|
|
675
|
+
"tunnel devices": lambda: _stay(_cmd_devices_status),
|
|
676
|
+
|
|
584
677
|
"codes csv": lambda: _stay(export_enrollment_codes_csv_local),
|
|
585
678
|
}
|
|
586
679
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/__init__.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_host_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_pb2.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/__init__.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/ansi_codes.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/api_token.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/db_connection.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/db_location.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/common/utils/list_string.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/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.66 → remoterf_server-0.1.68}/src/remoteRF_server/host/host_directory_store.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/cert_provider.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/device_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server/server/user_group_cli.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/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.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.66 → remoterf_server-0.1.68}/src/remoteRF_server.egg-info/top_level.txt
RENAMED
|
File without changes
|