remoteRF-server-testing 0.0.5__tar.gz → 0.0.7__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_testing-0.0.5 → remoterf_server_testing-0.0.7}/PKG-INFO +1 -1
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/pyproject.toml +1 -1
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/rpc_manager.py +107 -55
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/tools/gist_status.py +14 -22
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server_testing.egg-info/PKG-INFO +1 -1
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/README.md +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/setup.cfg +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/grpc/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/idl/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/idl/device_schema.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/idl/pluto_schema.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/idl/schema.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/api_token.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/db_connection.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/db_location.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/list_string.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/common/utils/process_arg.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/drivers/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/host/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/host/host_auth_token.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/host/host_directory_store.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/host/host_tunnel_server.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/acc_perms.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/cert_provider.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/device_manager.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/grpc_server.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/reservation.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/user_group_cli.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/server/user_group_handler.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/serverrf_cli.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/tools/__init__.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/tools/gen_certs.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/tools/gist_status_testing.py +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server_testing.egg-info/SOURCES.txt +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server_testing.egg-info/dependency_links.txt +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server_testing.egg-info/entry_points.txt +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server_testing.egg-info/requires.txt +0 -0
- {remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server_testing.egg-info/top_level.txt +0 -0
|
@@ -55,6 +55,11 @@ from ..common.utils import *
|
|
|
55
55
|
from .device_manager import acquire_device, VirtualDevice, get_device_schema, find_device_id_by_name, get_schema_by_token, resolve_gid_for_token
|
|
56
56
|
from ..host import host_tunnel_server as hts
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
def _normalize_device_rpc_type(value: str) -> str:
|
|
60
|
+
return "".join(ch for ch in str(value or "").lower() if ch.isalnum())
|
|
61
|
+
|
|
62
|
+
|
|
58
63
|
class RpcManager:
|
|
59
64
|
def __init__(self):
|
|
60
65
|
self.debug = False
|
|
@@ -62,60 +67,6 @@ class RpcManager:
|
|
|
62
67
|
def run_rpc(self, *, function_name, args) -> map:
|
|
63
68
|
fn_type = function_name.split(':', 1)[0]
|
|
64
69
|
|
|
65
|
-
if fn_type == "Pluto":
|
|
66
|
-
if 'a' not in args:
|
|
67
|
-
return {'a': map_arg('No token provided')}
|
|
68
|
-
|
|
69
|
-
api_token = unmap_arg(args['a'])
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
with acquire_device(api_token) as (gid, dev):
|
|
73
|
-
|
|
74
|
-
if isinstance(dev, VirtualDevice):
|
|
75
|
-
fwd_args = dict(args)
|
|
76
|
-
fwd_args.pop('a', None)
|
|
77
|
-
fwd_args['g'] = map_arg(int(gid))
|
|
78
|
-
return hts.handle_host_device(
|
|
79
|
-
hts.get_tunnel_registry(create=False),
|
|
80
|
-
host_id=dev.host_id,
|
|
81
|
-
device_id=dev.device_id,
|
|
82
|
-
function_name=function_name,
|
|
83
|
-
args=fwd_args,
|
|
84
|
-
timeout_sec=10.0,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
# Schema-based local dispatch.
|
|
88
|
-
# Wire format: "Pluto:{prop}:{verb}" verb = GET | SET | CALL0 | CALL1
|
|
89
|
-
parts = function_name.split(':')
|
|
90
|
-
prop = parts[1]
|
|
91
|
-
verb = parts[2] if len(parts) > 2 else ""
|
|
92
|
-
|
|
93
|
-
if verb == "GET":
|
|
94
|
-
result = dev.dispatch(f"get_{prop}", {})
|
|
95
|
-
return {prop: map_arg(result)}
|
|
96
|
-
|
|
97
|
-
elif verb == "SET":
|
|
98
|
-
value = unmap_arg(args[prop])
|
|
99
|
-
dev.dispatch(f"set_{prop}", {"value": value})
|
|
100
|
-
return {}
|
|
101
|
-
|
|
102
|
-
elif verb == "CALL0":
|
|
103
|
-
result = dev.dispatch(f"call_{prop}", {})
|
|
104
|
-
return {prop: map_arg(result)} if result is not None else {prop: map_arg('None')}
|
|
105
|
-
|
|
106
|
-
elif verb == "CALL1":
|
|
107
|
-
if 'arg1' not in args:
|
|
108
|
-
raise ValueError("CALL1 requires 'arg1' in args")
|
|
109
|
-
value = unmap_arg(args['arg1'])
|
|
110
|
-
result = dev.dispatch(f"call_{prop}", {"value": value})
|
|
111
|
-
return {prop: map_arg(result)} if result is not None else {prop: map_arg('None')}
|
|
112
|
-
|
|
113
|
-
else:
|
|
114
|
-
raise ValueError(f"Unknown verb {verb!r} in {function_name!r}")
|
|
115
|
-
|
|
116
|
-
except Exception as e:
|
|
117
|
-
return {'a': map_arg(str(e))}
|
|
118
|
-
|
|
119
70
|
if fn_type == "IDL":
|
|
120
71
|
return self._handle_idl(function_name.split(':', 1)[1], args)
|
|
121
72
|
|
|
@@ -125,10 +76,111 @@ class RpcManager:
|
|
|
125
76
|
if function_name == "echo":
|
|
126
77
|
return args
|
|
127
78
|
|
|
79
|
+
if self._looks_like_device_rpc(function_name):
|
|
80
|
+
return self._handle_device_rpc(function_name=function_name, args=args)
|
|
81
|
+
|
|
128
82
|
return {'a': map_arg(f'Unknown RPC: {function_name}')}
|
|
129
83
|
|
|
130
84
|
# ── IDL control-plane ────────────────────────────────────────────
|
|
131
85
|
|
|
86
|
+
def _looks_like_device_rpc(self, function_name: str) -> bool:
|
|
87
|
+
parts = function_name.split(':', 2)
|
|
88
|
+
return len(parts) == 3 and all(parts)
|
|
89
|
+
|
|
90
|
+
def _handle_device_rpc(self, *, function_name: str, args: dict) -> dict:
|
|
91
|
+
if 'a' not in args:
|
|
92
|
+
return {'a': map_arg('No token provided')}
|
|
93
|
+
|
|
94
|
+
api_token = unmap_arg(args['a'])
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
with acquire_device(api_token) as (gid, dev):
|
|
98
|
+
self._validate_device_rpc_type(function_name=function_name, gid=gid, dev=dev)
|
|
99
|
+
|
|
100
|
+
if self._should_use_builtin_ip_fallback(function_name=function_name, gid=gid, dev=dev):
|
|
101
|
+
return {"ip": map_arg(self._builtin_ip_fallback(gid=gid, dev=dev))}
|
|
102
|
+
|
|
103
|
+
if isinstance(dev, VirtualDevice):
|
|
104
|
+
fwd_args = dict(args)
|
|
105
|
+
fwd_args.pop('a', None)
|
|
106
|
+
fwd_args['g'] = map_arg(int(gid))
|
|
107
|
+
return hts.handle_host_device(
|
|
108
|
+
hts.get_tunnel_registry(create=False),
|
|
109
|
+
host_id=dev.host_id,
|
|
110
|
+
device_id=dev.device_id,
|
|
111
|
+
function_name=function_name,
|
|
112
|
+
args=fwd_args,
|
|
113
|
+
timeout_sec=10.0,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return self._dispatch_local_schema(function_name=function_name, args=args, dev=dev)
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
return {'a': map_arg(str(e))}
|
|
120
|
+
|
|
121
|
+
def _validate_device_rpc_type(self, *, function_name: str, gid: int, dev: object) -> None:
|
|
122
|
+
requested_type = function_name.split(':', 1)[0]
|
|
123
|
+
actual_type = self._resolve_device_type(gid=gid, dev=dev)
|
|
124
|
+
|
|
125
|
+
if not actual_type:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
if _normalize_device_rpc_type(requested_type) != _normalize_device_rpc_type(actual_type):
|
|
129
|
+
raise ValueError(
|
|
130
|
+
f"RPC device type {requested_type!r} does not match reserved device type {actual_type!r}"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def _should_use_builtin_ip_fallback(self, *, function_name: str, gid: int, dev: object) -> bool:
|
|
134
|
+
_, prop, verb = function_name.split(':', 2)
|
|
135
|
+
if prop != "ip" or verb != "CALL0":
|
|
136
|
+
return False
|
|
137
|
+
|
|
138
|
+
schema = dev if hasattr(dev, "list_exposed") else get_device_schema(gid)
|
|
139
|
+
if schema is None or not hasattr(schema, "list_exposed"):
|
|
140
|
+
return True
|
|
141
|
+
|
|
142
|
+
calls = schema.list_exposed().get("calls", [])
|
|
143
|
+
return "call_ip" not in calls
|
|
144
|
+
|
|
145
|
+
def _builtin_ip_fallback(self, *, gid: int, dev: object) -> str:
|
|
146
|
+
actual_type = self._resolve_device_type(gid=gid, dev=dev) or "device"
|
|
147
|
+
return f"{actual_type}:{int(gid)}"
|
|
148
|
+
|
|
149
|
+
def _resolve_device_type(self, *, gid: int, dev: object) -> str:
|
|
150
|
+
for candidate in (getattr(dev, "device_type", None), getattr(dev, "kind", None)):
|
|
151
|
+
if candidate:
|
|
152
|
+
return str(candidate)
|
|
153
|
+
|
|
154
|
+
schema = get_device_schema(gid)
|
|
155
|
+
if schema is None:
|
|
156
|
+
return ""
|
|
157
|
+
return str(getattr(schema, "device_type", "") or "")
|
|
158
|
+
|
|
159
|
+
def _dispatch_local_schema(self, *, function_name: str, args: dict, dev: object) -> dict:
|
|
160
|
+
_, prop, verb = function_name.split(':', 2)
|
|
161
|
+
|
|
162
|
+
if verb == "GET":
|
|
163
|
+
result = dev.dispatch(f"get_{prop}", {})
|
|
164
|
+
return {prop: map_arg(result)}
|
|
165
|
+
|
|
166
|
+
if verb == "SET":
|
|
167
|
+
value = unmap_arg(args[prop])
|
|
168
|
+
dev.dispatch(f"set_{prop}", {"value": value})
|
|
169
|
+
return {}
|
|
170
|
+
|
|
171
|
+
if verb == "CALL0":
|
|
172
|
+
result = dev.dispatch(f"call_{prop}", {})
|
|
173
|
+
return {prop: map_arg(result)} if result is not None else {prop: map_arg('None')}
|
|
174
|
+
|
|
175
|
+
if verb == "CALL1":
|
|
176
|
+
if 'arg1' not in args:
|
|
177
|
+
raise ValueError("CALL1 requires 'arg1' in args")
|
|
178
|
+
value = unmap_arg(args['arg1'])
|
|
179
|
+
result = dev.dispatch(f"call_{prop}", {"value": value})
|
|
180
|
+
return {prop: map_arg(result)} if result is not None else {prop: map_arg('None')}
|
|
181
|
+
|
|
182
|
+
raise ValueError(f"Unknown verb {verb!r} in {function_name!r}")
|
|
183
|
+
|
|
132
184
|
def _handle_idl(self, sub: str, args: dict) -> dict:
|
|
133
185
|
"""
|
|
134
186
|
IDL:get_drivers → schema + driver metadata for a device.
|
|
@@ -190,4 +242,4 @@ class RpcManager:
|
|
|
190
242
|
|
|
191
243
|
return {'error': map_arg(f'Unknown IDL call: {sub!r}')}
|
|
192
244
|
|
|
193
|
-
rpc_manager = RpcManager()
|
|
245
|
+
rpc_manager = RpcManager()
|
|
@@ -8,7 +8,7 @@ import sys
|
|
|
8
8
|
import time
|
|
9
9
|
import threading
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Dict, Optional
|
|
11
|
+
from typing import Dict, Optional, Tuple
|
|
12
12
|
|
|
13
13
|
import requests
|
|
14
14
|
|
|
@@ -34,7 +34,7 @@ def _read_env_kv(path: Path) -> Dict[str, str]:
|
|
|
34
34
|
return out
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def _load_gist_env() ->
|
|
37
|
+
def _load_gist_env() -> Optional[Tuple[str, str, str]]:
|
|
38
38
|
p = _cfg_dir() / "gist.env"
|
|
39
39
|
kv = _read_env_kv(p)
|
|
40
40
|
|
|
@@ -42,25 +42,10 @@ def _load_gist_env() -> tuple[str, str, str]:
|
|
|
42
42
|
token = kv.get("GITHUB_TOKEN", "").strip()
|
|
43
43
|
filename = kv.get("STATUS_GIST_FILENAME", "").strip()
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
missing.append("STATUS_GIST_ID")
|
|
48
|
-
if not token:
|
|
49
|
-
missing.append("GITHUB_TOKEN")
|
|
50
|
-
if not filename:
|
|
51
|
-
missing.append("STATUS_GIST_FILENAME")
|
|
52
|
-
|
|
53
|
-
if missing:
|
|
54
|
-
print(f"[gist_status] Missing {', '.join(missing)} in {p}", file=sys.stderr)
|
|
55
|
-
print(
|
|
56
|
-
"[gist_status] Fix: run:\n"
|
|
57
|
-
" serverrf --gist --set --id <gist_id> --file <filename>\n"
|
|
58
|
-
"Or manually create gist.env with those keys.",
|
|
59
|
-
file=sys.stderr,
|
|
60
|
-
)
|
|
61
|
-
raise SystemExit(2)
|
|
45
|
+
if not gist_id or not token or not filename:
|
|
46
|
+
return None
|
|
62
47
|
|
|
63
|
-
return gist_id, token, filename
|
|
48
|
+
return (gist_id, token, filename)
|
|
64
49
|
|
|
65
50
|
|
|
66
51
|
def build_status() -> dict:
|
|
@@ -96,7 +81,10 @@ def push_gist(*, gist_id: str, gh_token: str, filename: str, payload: dict) -> N
|
|
|
96
81
|
|
|
97
82
|
|
|
98
83
|
def _publisher_loop(period_sec: int) -> None:
|
|
99
|
-
|
|
84
|
+
cfg = _load_gist_env()
|
|
85
|
+
if cfg is None:
|
|
86
|
+
return
|
|
87
|
+
gist_id, gh_token, filename = cfg
|
|
100
88
|
|
|
101
89
|
try:
|
|
102
90
|
push_gist(gist_id=gist_id, gh_token=gh_token, filename=filename, payload=build_status())
|
|
@@ -122,6 +110,10 @@ def start_status_publisher() -> None:
|
|
|
122
110
|
if _publisher_thread is not None and _publisher_thread.is_alive():
|
|
123
111
|
return
|
|
124
112
|
|
|
113
|
+
if _load_gist_env() is None:
|
|
114
|
+
print("[gist_status] off (not configured; see README gist docs)", file=sys.stderr)
|
|
115
|
+
return
|
|
116
|
+
|
|
125
117
|
t = threading.Thread(
|
|
126
118
|
target=_publisher_loop,
|
|
127
119
|
args=(int(120),),
|
|
@@ -136,4 +128,4 @@ def start_status_publisher() -> None:
|
|
|
136
128
|
# if __name__ == "__main__":
|
|
137
129
|
# start_status_publisher(period_sec=120)
|
|
138
130
|
# while True:
|
|
139
|
-
# time.sleep(3600)
|
|
131
|
+
# time.sleep(3600)
|
|
File without changes
|
|
File without changes
|
{remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/host/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server_testing-0.0.5 → remoterf_server_testing-0.0.7}/src/remoteRF_server/serverrf_cli.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|