remoteRF-server 0.1.62__tar.gz → 0.1.64__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.62 → remoterf_server-0.1.64}/PKG-INFO +25 -12
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/README.md +24 -11
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/pyproject.toml +1 -1
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/host/host_tunnel_server.py +82 -40
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/grpc_server.py +2 -2
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/PKG-INFO +25 -12
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/setup.cfg +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/api_token.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/db_connection.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/db_location.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/list_string.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/process_arg.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/drivers/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/host/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/host/host_directory_store.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/acc_perms.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/cert_provider.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/device_manager.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/reservation.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/rpc_manager.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/user_group_cli.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/user_group_handler.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/serverrf_cli.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/tools/__init__.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/tools/gen_certs.py +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/SOURCES.txt +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/dependency_links.txt +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/entry_points.txt +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/requires.txt +0 -0
- {remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: remoteRF-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.64
|
|
4
4
|
Description-Content-Type: text/markdown
|
|
5
5
|
Requires-Dist: grpcio
|
|
6
6
|
Requires-Dist: protobuf
|
|
@@ -283,13 +283,11 @@ Note that all device and server config parameters need a 'restart' to take affec
|
|
|
283
283
|
|
|
284
284
|
After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**. This interactive shell is used for runtime administration: managing users, devices, reservations, user groups, and enrollment codes.
|
|
285
285
|
|
|
286
|
-
> Tip: Legacy commands (e.g. `show a`, `rm db`) may still work if enabled, but the commands below are the canonical interface.
|
|
287
|
-
|
|
288
286
|
---
|
|
289
287
|
|
|
290
288
|
#### Server
|
|
291
289
|
|
|
292
|
-
* `help` /
|
|
290
|
+
* `help` / `h` — Show help
|
|
293
291
|
* `clear` — Clear the screen
|
|
294
292
|
* `status` — Show server status (uptime / bind info)
|
|
295
293
|
* `quit` / `exit` — Exit the server shell
|
|
@@ -299,8 +297,8 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
299
297
|
#### Users
|
|
300
298
|
|
|
301
299
|
* `users list` — List all accounts
|
|
302
|
-
* `users manage` — Manage a specific user
|
|
303
|
-
* `users purge` —
|
|
300
|
+
* `users manage` — Manage a specific user
|
|
301
|
+
* `users purge` — Delete **all** users
|
|
304
302
|
|
|
305
303
|
---
|
|
306
304
|
|
|
@@ -313,7 +311,7 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
313
311
|
#### Reservations
|
|
314
312
|
|
|
315
313
|
* `reservations list` — List all reservations
|
|
316
|
-
* `reservations purge` —
|
|
314
|
+
* `reservations purge` — Delete **all** reservations
|
|
317
315
|
|
|
318
316
|
---
|
|
319
317
|
|
|
@@ -323,6 +321,7 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
323
321
|
* `groups create` — Create a user group *(interactive)*
|
|
324
322
|
* `groups edit` — Edit a user group *(interactive)*
|
|
325
323
|
* `groups delete` — Delete a user group *(interactive)*
|
|
324
|
+
* `groups csv` - Export all groups as a CSV
|
|
326
325
|
|
|
327
326
|
---
|
|
328
327
|
|
|
@@ -331,12 +330,13 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
331
330
|
* `codes list` — List enrollment codes
|
|
332
331
|
* `codes create` — Create enrollment codes *(interactive)*
|
|
333
332
|
* `codes delete` — Delete an enrollment code *(interactive)*
|
|
333
|
+
* `codes csv` - Export all codes as a CSV
|
|
334
334
|
|
|
335
335
|
---
|
|
336
336
|
|
|
337
337
|
#### Database
|
|
338
338
|
|
|
339
|
-
* `db
|
|
339
|
+
* `db purge` — Remove all database entries
|
|
340
340
|
|
|
341
341
|
---
|
|
342
342
|
|
|
@@ -344,17 +344,30 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
344
344
|
todo:
|
|
345
345
|
<!-- Adding plutos via the CLI -->
|
|
346
346
|
<!-- Testing functionality (disregarding Host pipeline) -->
|
|
347
|
-
Clean up serverrf CLI + basic documentation for all commands, usergroups, export codes by CSV.
|
|
348
|
-
Choice to choose usergroup/code by either int id or string name.
|
|
347
|
+
<!-- Clean up serverrf CLI + basic documentation for all commands, usergroups, export codes by CSV. -->
|
|
349
348
|
|
|
350
|
-
|
|
349
|
+
HostRF meta data -> push upon connection + retry connection on host side.
|
|
350
|
+
|
|
351
|
+
ServerRF display meta data as part of devices list / reservation + online/activity status (appended into device name) + (plus host side warning if the device id is NOT globally unique!)
|
|
352
|
+
|
|
353
|
+
set_device token (virtual devices) + routing/relay to proper host (multiplexed)
|
|
351
354
|
|
|
352
|
-
|
|
355
|
+
User side testing + integration
|
|
356
|
+
|
|
357
|
+
hostrf side CLI/server (basically just device list)
|
|
358
|
+
|
|
359
|
+
edge case testing (disconnected hosts, disconnected server, many users using multiple devices, multi-host)
|
|
360
|
+
|
|
361
|
+
<!-- HostRF integration -> Host directory, device routing, dynamic reservation pulling, with activity/status (online, offline, etc.) -->
|
|
353
362
|
|
|
354
363
|
Cleanup code comments.
|
|
355
364
|
|
|
356
365
|
Update Ian with installation demo (try myself first on the NUC once!) for both server and host.
|
|
357
366
|
|
|
367
|
+
Nice to have (later):
|
|
368
|
+
Activity/stats?
|
|
369
|
+
Ability to remotely manage groups and codes as admin.
|
|
370
|
+
Choice to choose usergroup/code by either int id or string name. (too lazy)
|
|
358
371
|
|
|
359
372
|
todo: Specify/Pull user side --config CLI pointing to this server + debug for connection sake (later)
|
|
360
373
|
|
|
@@ -272,13 +272,11 @@ Note that all device and server config parameters need a 'restart' to take affec
|
|
|
272
272
|
|
|
273
273
|
After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**. This interactive shell is used for runtime administration: managing users, devices, reservations, user groups, and enrollment codes.
|
|
274
274
|
|
|
275
|
-
> Tip: Legacy commands (e.g. `show a`, `rm db`) may still work if enabled, but the commands below are the canonical interface.
|
|
276
|
-
|
|
277
275
|
---
|
|
278
276
|
|
|
279
277
|
#### Server
|
|
280
278
|
|
|
281
|
-
* `help` /
|
|
279
|
+
* `help` / `h` — Show help
|
|
282
280
|
* `clear` — Clear the screen
|
|
283
281
|
* `status` — Show server status (uptime / bind info)
|
|
284
282
|
* `quit` / `exit` — Exit the server shell
|
|
@@ -288,8 +286,8 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
288
286
|
#### Users
|
|
289
287
|
|
|
290
288
|
* `users list` — List all accounts
|
|
291
|
-
* `users manage` — Manage a specific user
|
|
292
|
-
* `users purge` —
|
|
289
|
+
* `users manage` — Manage a specific user
|
|
290
|
+
* `users purge` — Delete **all** users
|
|
293
291
|
|
|
294
292
|
---
|
|
295
293
|
|
|
@@ -302,7 +300,7 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
302
300
|
#### Reservations
|
|
303
301
|
|
|
304
302
|
* `reservations list` — List all reservations
|
|
305
|
-
* `reservations purge` —
|
|
303
|
+
* `reservations purge` — Delete **all** reservations
|
|
306
304
|
|
|
307
305
|
---
|
|
308
306
|
|
|
@@ -312,6 +310,7 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
312
310
|
* `groups create` — Create a user group *(interactive)*
|
|
313
311
|
* `groups edit` — Edit a user group *(interactive)*
|
|
314
312
|
* `groups delete` — Delete a user group *(interactive)*
|
|
313
|
+
* `groups csv` - Export all groups as a CSV
|
|
315
314
|
|
|
316
315
|
---
|
|
317
316
|
|
|
@@ -320,12 +319,13 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
320
319
|
* `codes list` — List enrollment codes
|
|
321
320
|
* `codes create` — Create enrollment codes *(interactive)*
|
|
322
321
|
* `codes delete` — Delete an enrollment code *(interactive)*
|
|
322
|
+
* `codes csv` - Export all codes as a CSV
|
|
323
323
|
|
|
324
324
|
---
|
|
325
325
|
|
|
326
326
|
#### Database
|
|
327
327
|
|
|
328
|
-
* `db
|
|
328
|
+
* `db purge` — Remove all database entries
|
|
329
329
|
|
|
330
330
|
---
|
|
331
331
|
|
|
@@ -333,17 +333,30 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
333
333
|
todo:
|
|
334
334
|
<!-- Adding plutos via the CLI -->
|
|
335
335
|
<!-- Testing functionality (disregarding Host pipeline) -->
|
|
336
|
-
Clean up serverrf CLI + basic documentation for all commands, usergroups, export codes by CSV.
|
|
337
|
-
Choice to choose usergroup/code by either int id or string name.
|
|
336
|
+
<!-- Clean up serverrf CLI + basic documentation for all commands, usergroups, export codes by CSV. -->
|
|
338
337
|
|
|
339
|
-
|
|
338
|
+
HostRF meta data -> push upon connection + retry connection on host side.
|
|
339
|
+
|
|
340
|
+
ServerRF display meta data as part of devices list / reservation + online/activity status (appended into device name) + (plus host side warning if the device id is NOT globally unique!)
|
|
341
|
+
|
|
342
|
+
set_device token (virtual devices) + routing/relay to proper host (multiplexed)
|
|
340
343
|
|
|
341
|
-
|
|
344
|
+
User side testing + integration
|
|
345
|
+
|
|
346
|
+
hostrf side CLI/server (basically just device list)
|
|
347
|
+
|
|
348
|
+
edge case testing (disconnected hosts, disconnected server, many users using multiple devices, multi-host)
|
|
349
|
+
|
|
350
|
+
<!-- HostRF integration -> Host directory, device routing, dynamic reservation pulling, with activity/status (online, offline, etc.) -->
|
|
342
351
|
|
|
343
352
|
Cleanup code comments.
|
|
344
353
|
|
|
345
354
|
Update Ian with installation demo (try myself first on the NUC once!) for both server and host.
|
|
346
355
|
|
|
356
|
+
Nice to have (later):
|
|
357
|
+
Activity/stats?
|
|
358
|
+
Ability to remotely manage groups and codes as admin.
|
|
359
|
+
Choice to choose usergroup/code by either int id or string name. (too lazy)
|
|
347
360
|
|
|
348
361
|
todo: Specify/Pull user side --config CLI pointing to this server + debug for connection sake (later)
|
|
349
362
|
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/host/host_tunnel_server.py
RENAMED
|
@@ -32,6 +32,13 @@ from .host_directory_store import (
|
|
|
32
32
|
cfg_dir_from_file,
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
+
import hashlib
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def host_key(host_id: str) -> str:
|
|
39
|
+
h = hashlib.sha256((host_id or "").encode("utf-8")).hexdigest()
|
|
40
|
+
return h[:16] # short stable key
|
|
41
|
+
|
|
35
42
|
|
|
36
43
|
def _copy_argument_map(dst_map: Any, src_map: Any) -> None:
|
|
37
44
|
if src_map is None:
|
|
@@ -103,6 +110,7 @@ class HostSession:
|
|
|
103
110
|
fut.set_exception(RuntimeError(f"Host '{self.host_id}' disconnected"))
|
|
104
111
|
self.inflight.clear()
|
|
105
112
|
|
|
113
|
+
|
|
106
114
|
class HostTunnelRegistry:
|
|
107
115
|
"""
|
|
108
116
|
Persistent host/device directory + live sessions.
|
|
@@ -188,16 +196,6 @@ class HostTunnelRegistry:
|
|
|
188
196
|
known_hosts = csv_split(kv_lists.get("KNOWN_HOSTS", ""))
|
|
189
197
|
known_devices = csv_split(kv_lists.get("KNOWN_DEVICES", ""))
|
|
190
198
|
|
|
191
|
-
# also accept hosts referenced by HOST_*_DEVICES keys even if KNOWN_HOSTS drifted
|
|
192
|
-
hosts_from_keys: Set[str] = set()
|
|
193
|
-
for k, v in kv_lists.items():
|
|
194
|
-
if k.startswith("HOST_") and k.endswith("_DEVICES"):
|
|
195
|
-
# We don't know the original host_id from the sanitized key reliably.
|
|
196
|
-
# That's fine; we still load routes primarily from DEVICE_*_HOST in meta.
|
|
197
|
-
# But we DO want to retain the device list; we’ll stitch it via meta host ids.
|
|
198
|
-
# So: just collect devices from these keys.
|
|
199
|
-
pass
|
|
200
|
-
|
|
201
199
|
# Reset directory + status (do not touch live sessions)
|
|
202
200
|
with self._lock:
|
|
203
201
|
self._routes.clear()
|
|
@@ -218,9 +216,6 @@ class HostTunnelRegistry:
|
|
|
218
216
|
if k.startswith("HOST_") and k.endswith("_DEVICES"):
|
|
219
217
|
devices_from_host_lists.update(csv_split(v))
|
|
220
218
|
|
|
221
|
-
devices_from_meta: Set[str] = set()
|
|
222
|
-
# any DEVICE_<X>_HOST implies a known device id (but we can’t reverse sanitize_env_key)
|
|
223
|
-
# so we rely on KNOWN_DEVICES + HOST_*_DEVICES as primary device-id sources.
|
|
224
219
|
# meta augments those devices; it can’t introduce new raw device ids safely.
|
|
225
220
|
all_devices: List[str] = sorted(set(known_devices) | devices_from_host_lists)
|
|
226
221
|
|
|
@@ -242,15 +237,11 @@ class HostTunnelRegistry:
|
|
|
242
237
|
kind = (kv_meta.get(f"DEVICE_{dk}_KIND", "") or "").strip()
|
|
243
238
|
|
|
244
239
|
if host_id:
|
|
245
|
-
# ensure host exists
|
|
246
240
|
if host_id not in self._host_status:
|
|
247
241
|
self._host_status[host_id] = HostStatus(host_id=host_id, online=False, last_seen_ms=0)
|
|
248
242
|
self._host_devices.setdefault(host_id, set()).add(device_id)
|
|
249
|
-
|
|
250
|
-
# route exists even while offline
|
|
251
243
|
self._routes[device_id] = DeviceRoute(host_id=host_id, host_local_id=int(local_id))
|
|
252
244
|
|
|
253
|
-
# keep info visible even when offline
|
|
254
245
|
self._device_infos[device_id] = host_tunnel_pb2.DeviceInfo(
|
|
255
246
|
device_id=str(device_id),
|
|
256
247
|
local_id=int(local_id),
|
|
@@ -273,12 +264,36 @@ class HostTunnelRegistry:
|
|
|
273
264
|
# persistence write helpers
|
|
274
265
|
# ---------------------------
|
|
275
266
|
|
|
267
|
+
def _persist_host_meta(self, host_id: str, *, host_name: str = "", platform: str = "", version: str = "") -> None:
|
|
268
|
+
hk = host_key(host_id)
|
|
269
|
+
self._env_meta.set_kv_if_absent(f"HOST_{hk}_ID", host_id)
|
|
270
|
+
if host_name:
|
|
271
|
+
self._env_meta.upsert_kv(f"HOST_{hk}_NAME", host_name)
|
|
272
|
+
if platform:
|
|
273
|
+
self._env_meta.upsert_kv(f"HOST_{hk}_PLATFORM", platform)
|
|
274
|
+
if version:
|
|
275
|
+
self._env_meta.upsert_kv(f"HOST_{hk}_VERSION", version)
|
|
276
|
+
|
|
277
|
+
def persist_host_meta_from_hello(self, hello: Any) -> None:
|
|
278
|
+
"""
|
|
279
|
+
Safe helper so HostTunnelServicer can persist from HostHello without needing to know field names.
|
|
280
|
+
"""
|
|
281
|
+
try:
|
|
282
|
+
hid = str(getattr(hello, "host_id", "") or "").strip()
|
|
283
|
+
ver = str(getattr(hello, "version", "") or "").strip()
|
|
284
|
+
if hid:
|
|
285
|
+
self._persist_host_meta(hid, version=ver)
|
|
286
|
+
except Exception:
|
|
287
|
+
pass
|
|
288
|
+
|
|
276
289
|
def _persist_host(self, host_id: str) -> None:
|
|
277
290
|
self._env_lists.append_to_csv_list("KNOWN_HOSTS", host_id)
|
|
278
291
|
|
|
279
292
|
def _persist_device(self, host_id: str, device_id: str, local_id: int, device_info: Any) -> None:
|
|
280
293
|
self._env_lists.append_to_csv_list("KNOWN_DEVICES", device_id)
|
|
281
|
-
|
|
294
|
+
hk = host_key(host_id)
|
|
295
|
+
self._env_meta.set_kv_if_absent(f"HOST_{hk}_ID", host_id) # reverse map
|
|
296
|
+
self._env_lists.append_to_csv_list(f"HOST_{hk}_DEVICES", device_id)
|
|
282
297
|
|
|
283
298
|
dk = sanitize_env_key(device_id)
|
|
284
299
|
self._env_meta.upsert_kv(f"DEVICE_{dk}_HOST", host_id)
|
|
@@ -350,8 +365,6 @@ class HostTunnelRegistry:
|
|
|
350
365
|
ds.online = True
|
|
351
366
|
ds.last_seen_ms = now
|
|
352
367
|
|
|
353
|
-
# no need to invalidate full cache; active-cache TTL handles this
|
|
354
|
-
# but host status flips can matter; be conservative:
|
|
355
368
|
self._invalidate_caches_locked()
|
|
356
369
|
|
|
357
370
|
def announce_devices(self, host_id: str, devices: list) -> None:
|
|
@@ -382,17 +395,14 @@ class HostTunnelRegistry:
|
|
|
382
395
|
if not device_id:
|
|
383
396
|
continue
|
|
384
397
|
|
|
385
|
-
# local_id is basically not used; keep for completeness
|
|
386
398
|
try:
|
|
387
399
|
local_id = int(getattr(d, "local_id", 0))
|
|
388
400
|
except Exception:
|
|
389
401
|
local_id = 0
|
|
390
402
|
|
|
391
|
-
# route
|
|
392
403
|
self._routes[device_id] = DeviceRoute(host_id=host_id, host_local_id=local_id)
|
|
393
404
|
self._host_devices[host_id].add(device_id)
|
|
394
405
|
|
|
395
|
-
# status
|
|
396
406
|
ds = self._device_status.get(device_id) or DeviceStatus(
|
|
397
407
|
device_id=device_id,
|
|
398
408
|
host_id=host_id,
|
|
@@ -404,13 +414,11 @@ class HostTunnelRegistry:
|
|
|
404
414
|
ds.last_seen_ms = now
|
|
405
415
|
self._device_status[device_id] = ds
|
|
406
416
|
|
|
407
|
-
# info (copy protobuf if possible)
|
|
408
417
|
try:
|
|
409
418
|
tmp = host_tunnel_pb2.DeviceInfo()
|
|
410
419
|
tmp.CopyFrom(d)
|
|
411
420
|
self._device_infos[device_id] = tmp
|
|
412
421
|
except Exception:
|
|
413
|
-
# fallback minimal
|
|
414
422
|
self._device_infos[device_id] = host_tunnel_pb2.DeviceInfo(
|
|
415
423
|
device_id=device_id,
|
|
416
424
|
local_id=int(local_id),
|
|
@@ -428,10 +436,6 @@ class HostTunnelRegistry:
|
|
|
428
436
|
# ---------------------------
|
|
429
437
|
|
|
430
438
|
def is_host_device(self, device_id: str) -> bool:
|
|
431
|
-
"""
|
|
432
|
-
O(1): does the directory route this device_id to a host?
|
|
433
|
-
(Host may be offline.)
|
|
434
|
-
"""
|
|
435
439
|
did = (device_id or "").strip()
|
|
436
440
|
if not did:
|
|
437
441
|
return False
|
|
@@ -439,10 +443,6 @@ class HostTunnelRegistry:
|
|
|
439
443
|
return did in self._routes
|
|
440
444
|
|
|
441
445
|
def is_host_device_active(self, device_id: str) -> bool:
|
|
442
|
-
"""
|
|
443
|
-
O(1) route lookup + cached host-alive check (TTL).
|
|
444
|
-
True iff device routes to a host AND that host's tunnel session is alive.
|
|
445
|
-
"""
|
|
446
446
|
did = (device_id or "").strip()
|
|
447
447
|
if not did:
|
|
448
448
|
return False
|
|
@@ -468,12 +468,6 @@ class HostTunnelRegistry:
|
|
|
468
468
|
# ---------------------------
|
|
469
469
|
|
|
470
470
|
def device_directory_cached(self, *, ttl_ms: Optional[int] = None) -> Dict[str, Tuple[str, Any, bool]]:
|
|
471
|
-
"""
|
|
472
|
-
Returns:
|
|
473
|
-
{ device_id: (host_id, device_info, is_active) }
|
|
474
|
-
|
|
475
|
-
Cached rebuild at most once per ttl_ms.
|
|
476
|
-
"""
|
|
477
471
|
now = now_ms()
|
|
478
472
|
ttl = int(self._dir_cache_ttl_ms if ttl_ms is None else ttl_ms)
|
|
479
473
|
|
|
@@ -630,6 +624,7 @@ class HostTunnelRegistry:
|
|
|
630
624
|
cancel_on_timeout=cancel_on_timeout,
|
|
631
625
|
)
|
|
632
626
|
|
|
627
|
+
|
|
633
628
|
def handle_host_device(
|
|
634
629
|
registry: HostTunnelRegistry,
|
|
635
630
|
*,
|
|
@@ -692,7 +687,25 @@ class HostTunnelServicer(host_tunnel_pb2_grpc.HostTunnelServicer):
|
|
|
692
687
|
host_id = str(hello.host_id).strip() or "unknown-host"
|
|
693
688
|
session = HostSession(host_id)
|
|
694
689
|
self.registry.register_host(host_id, session)
|
|
690
|
+
self.registry.persist_host_meta_from_hello(hello)
|
|
691
|
+
|
|
692
|
+
# Ask host for metadata immediately on join (best-effort)
|
|
693
|
+
try:
|
|
694
|
+
mrid = secrets.token_hex(12)
|
|
695
|
+
session.send(
|
|
696
|
+
host_tunnel_pb2.HostFrame(
|
|
697
|
+
meta_request=host_tunnel_pb2.MetaRequest(
|
|
698
|
+
req_id=mrid,
|
|
699
|
+
include_platform=True,
|
|
700
|
+
include_env=True,
|
|
701
|
+
include_devices=True,
|
|
702
|
+
)
|
|
703
|
+
)
|
|
704
|
+
)
|
|
705
|
+
except Exception:
|
|
706
|
+
pass
|
|
695
707
|
|
|
708
|
+
# Also ping/ack
|
|
696
709
|
try:
|
|
697
710
|
session.send(
|
|
698
711
|
host_tunnel_pb2.HostFrame(
|
|
@@ -735,6 +748,35 @@ class HostTunnelServicer(host_tunnel_pb2_grpc.HostTunnelServicer):
|
|
|
735
748
|
if fut is not None and not fut.done():
|
|
736
749
|
fut.set_result(resp)
|
|
737
750
|
|
|
751
|
+
elif which == "meta_response":
|
|
752
|
+
# Print host metadata (best-effort diagnostics)
|
|
753
|
+
try:
|
|
754
|
+
mr = frame.meta_response
|
|
755
|
+
if not mr.ok:
|
|
756
|
+
print(f"[HOST META] host_id={host_id or '?'} ERROR: {mr.error}")
|
|
757
|
+
continue
|
|
758
|
+
|
|
759
|
+
meta = mr.meta
|
|
760
|
+
print(f"\n[HOST META] host_id={meta.host_id} version={meta.version} unix_ms={meta.unix_ms}")
|
|
761
|
+
|
|
762
|
+
if meta.kv:
|
|
763
|
+
for k in sorted(meta.kv.keys()):
|
|
764
|
+
print(f" {k}={meta.kv[k]}")
|
|
765
|
+
|
|
766
|
+
if meta.devices:
|
|
767
|
+
print(" devices:")
|
|
768
|
+
for d in meta.devices:
|
|
769
|
+
print(
|
|
770
|
+
f" - local_id={d.local_id} "
|
|
771
|
+
f"label={d.label!r} "
|
|
772
|
+
f"device_id={d.device_id!r} "
|
|
773
|
+
f"serial={d.serial!r} "
|
|
774
|
+
f"kind={d.kind!r}"
|
|
775
|
+
)
|
|
776
|
+
print()
|
|
777
|
+
except Exception:
|
|
778
|
+
pass
|
|
779
|
+
|
|
738
780
|
elif which == "heartbeat":
|
|
739
781
|
if session is not None and host_id is not None:
|
|
740
782
|
session.last_heartbeat_ms = int(frame.heartbeat.unix_ms) or now_ms()
|
|
@@ -826,4 +868,4 @@ def start_host_tunnel_server(
|
|
|
826
868
|
|
|
827
869
|
th = threading.Thread(target=run, daemon=True)
|
|
828
870
|
th.start()
|
|
829
|
-
return server, th, reg
|
|
871
|
+
return server, th, reg
|
|
@@ -490,7 +490,7 @@ def help() -> None:
|
|
|
490
490
|
print()
|
|
491
491
|
|
|
492
492
|
printf("Database:", Sty.BOLD)
|
|
493
|
-
printf(" db
|
|
493
|
+
printf(" db purge ", Sty.MAGENTA, "- Remove all database entries", Sty.DEFAULT)
|
|
494
494
|
print()
|
|
495
495
|
|
|
496
496
|
def server_input(inpu: str) -> bool:
|
|
@@ -546,7 +546,7 @@ def server_input(inpu: str) -> bool:
|
|
|
546
546
|
"rm ar": lambda: _stay(reservation_handler.remove_all_reservations), # old
|
|
547
547
|
|
|
548
548
|
# ---- db ----
|
|
549
|
-
"db
|
|
549
|
+
"db purge": lambda: _stay(reservation_handler.rm_db),
|
|
550
550
|
"rm db": lambda: _stay(reservation_handler.rm_db), # old
|
|
551
551
|
|
|
552
552
|
# ---- groups ----
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: remoteRF-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.64
|
|
4
4
|
Description-Content-Type: text/markdown
|
|
5
5
|
Requires-Dist: grpcio
|
|
6
6
|
Requires-Dist: protobuf
|
|
@@ -283,13 +283,11 @@ Note that all device and server config parameters need a 'restart' to take affec
|
|
|
283
283
|
|
|
284
284
|
After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**. This interactive shell is used for runtime administration: managing users, devices, reservations, user groups, and enrollment codes.
|
|
285
285
|
|
|
286
|
-
> Tip: Legacy commands (e.g. `show a`, `rm db`) may still work if enabled, but the commands below are the canonical interface.
|
|
287
|
-
|
|
288
286
|
---
|
|
289
287
|
|
|
290
288
|
#### Server
|
|
291
289
|
|
|
292
|
-
* `help` /
|
|
290
|
+
* `help` / `h` — Show help
|
|
293
291
|
* `clear` — Clear the screen
|
|
294
292
|
* `status` — Show server status (uptime / bind info)
|
|
295
293
|
* `quit` / `exit` — Exit the server shell
|
|
@@ -299,8 +297,8 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
299
297
|
#### Users
|
|
300
298
|
|
|
301
299
|
* `users list` — List all accounts
|
|
302
|
-
* `users manage` — Manage a specific user
|
|
303
|
-
* `users purge` —
|
|
300
|
+
* `users manage` — Manage a specific user
|
|
301
|
+
* `users purge` — Delete **all** users
|
|
304
302
|
|
|
305
303
|
---
|
|
306
304
|
|
|
@@ -313,7 +311,7 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
313
311
|
#### Reservations
|
|
314
312
|
|
|
315
313
|
* `reservations list` — List all reservations
|
|
316
|
-
* `reservations purge` —
|
|
314
|
+
* `reservations purge` — Delete **all** reservations
|
|
317
315
|
|
|
318
316
|
---
|
|
319
317
|
|
|
@@ -323,6 +321,7 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
323
321
|
* `groups create` — Create a user group *(interactive)*
|
|
324
322
|
* `groups edit` — Edit a user group *(interactive)*
|
|
325
323
|
* `groups delete` — Delete a user group *(interactive)*
|
|
324
|
+
* `groups csv` - Export all groups as a CSV
|
|
326
325
|
|
|
327
326
|
---
|
|
328
327
|
|
|
@@ -331,12 +330,13 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
331
330
|
* `codes list` — List enrollment codes
|
|
332
331
|
* `codes create` — Create enrollment codes *(interactive)*
|
|
333
332
|
* `codes delete` — Delete an enrollment code *(interactive)*
|
|
333
|
+
* `codes csv` - Export all codes as a CSV
|
|
334
334
|
|
|
335
335
|
---
|
|
336
336
|
|
|
337
337
|
#### Database
|
|
338
338
|
|
|
339
|
-
* `db
|
|
339
|
+
* `db purge` — Remove all database entries
|
|
340
340
|
|
|
341
341
|
---
|
|
342
342
|
|
|
@@ -344,17 +344,30 @@ After running `serverrf --serve`, you’ll enter the **RemoteRF Server Shell**.
|
|
|
344
344
|
todo:
|
|
345
345
|
<!-- Adding plutos via the CLI -->
|
|
346
346
|
<!-- Testing functionality (disregarding Host pipeline) -->
|
|
347
|
-
Clean up serverrf CLI + basic documentation for all commands, usergroups, export codes by CSV.
|
|
348
|
-
Choice to choose usergroup/code by either int id or string name.
|
|
347
|
+
<!-- Clean up serverrf CLI + basic documentation for all commands, usergroups, export codes by CSV. -->
|
|
349
348
|
|
|
350
|
-
|
|
349
|
+
HostRF meta data -> push upon connection + retry connection on host side.
|
|
350
|
+
|
|
351
|
+
ServerRF display meta data as part of devices list / reservation + online/activity status (appended into device name) + (plus host side warning if the device id is NOT globally unique!)
|
|
352
|
+
|
|
353
|
+
set_device token (virtual devices) + routing/relay to proper host (multiplexed)
|
|
351
354
|
|
|
352
|
-
|
|
355
|
+
User side testing + integration
|
|
356
|
+
|
|
357
|
+
hostrf side CLI/server (basically just device list)
|
|
358
|
+
|
|
359
|
+
edge case testing (disconnected hosts, disconnected server, many users using multiple devices, multi-host)
|
|
360
|
+
|
|
361
|
+
<!-- HostRF integration -> Host directory, device routing, dynamic reservation pulling, with activity/status (online, offline, etc.) -->
|
|
353
362
|
|
|
354
363
|
Cleanup code comments.
|
|
355
364
|
|
|
356
365
|
Update Ian with installation demo (try myself first on the NUC once!) for both server and host.
|
|
357
366
|
|
|
367
|
+
Nice to have (later):
|
|
368
|
+
Activity/stats?
|
|
369
|
+
Ability to remotely manage groups and codes as admin.
|
|
370
|
+
Choice to choose usergroup/code by either int id or string name. (too lazy)
|
|
358
371
|
|
|
359
372
|
todo: Specify/Pull user side --config CLI pointing to this server + debug for connection sake (later)
|
|
360
373
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/__init__.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_host_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_pb2.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/__init__.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/ansi_codes.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/api_token.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/db_connection.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/db_location.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/common/utils/list_string.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/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.62 → remoterf_server-0.1.64}/src/remoteRF_server/host/host_directory_store.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/cert_provider.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/device_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server/server/user_group_cli.py
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/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.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{remoterf_server-0.1.62 → remoterf_server-0.1.64}/src/remoteRF_server.egg-info/top_level.txt
RENAMED
|
File without changes
|