remoteRF-server 1.1.0.dev46__py3-none-any.whl → 1.1.0.dev48__py3-none-any.whl
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/server/direct_path.py +38 -2
- remoteRF_server/server/user_group_cli.py +22 -5
- {remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/METADATA +1 -1
- {remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/RECORD +8 -8
- {remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/WHEEL +0 -0
- {remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/entry_points.txt +0 -0
- {remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/licenses/LICENSE +0 -0
- {remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/top_level.txt +0 -0
|
@@ -50,6 +50,41 @@ from .global_onboarding import RELAYED, hostname, is_offsite
|
|
|
50
50
|
|
|
51
51
|
logger = logging.getLogger("remoteRF_server.direct")
|
|
52
52
|
|
|
53
|
+
|
|
54
|
+
async def close_ice(ice) -> None:
|
|
55
|
+
"""Close an aioice Connection without the library's after-close noise.
|
|
56
|
+
|
|
57
|
+
aioice leaves STUN retry timers armed and connectivity-check tasks waiting
|
|
58
|
+
on futures nobody resolves; the timers then fire on closed sockets and the
|
|
59
|
+
tasks die "pending" when the loop stops. Fail those transactions first so
|
|
60
|
+
everything finishes cleanly, then close."""
|
|
61
|
+
from aioice import stun
|
|
62
|
+
|
|
63
|
+
for protocol in list(getattr(ice, "_protocols", [])):
|
|
64
|
+
for transaction in list(getattr(protocol, "transactions", {}).values()):
|
|
65
|
+
handle = getattr(transaction, "_Transaction__timeout_handle", None)
|
|
66
|
+
if handle is not None:
|
|
67
|
+
handle.cancel()
|
|
68
|
+
future = getattr(transaction, "_Transaction__future", None)
|
|
69
|
+
if future is not None and not future.done():
|
|
70
|
+
future.set_exception(stun.TransactionTimeout())
|
|
71
|
+
await ice.close()
|
|
72
|
+
await asyncio.sleep(0) # let the check tasks see their failures and exit
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def quiet_aioice_errors(loop) -> None:
|
|
76
|
+
"""A STUN retry on an already-closed socket is not an error worth a
|
|
77
|
+
traceback in someone's shell; everything else keeps the default handler."""
|
|
78
|
+
default = loop.default_exception_handler
|
|
79
|
+
|
|
80
|
+
def handler(loop, context):
|
|
81
|
+
exc = context.get("exception")
|
|
82
|
+
if isinstance(exc, (AttributeError, OSError)) and "Transaction" in repr(context.get("handle", "")):
|
|
83
|
+
return
|
|
84
|
+
default(context)
|
|
85
|
+
|
|
86
|
+
loop.set_exception_handler(handler)
|
|
87
|
+
|
|
53
88
|
ALPN = "remoterf-direct/1"
|
|
54
89
|
MAX_FRAME = 100 * 1024 * 1024 # the gRPC message ceiling
|
|
55
90
|
IDLE_SECONDS = 600
|
|
@@ -307,7 +342,7 @@ class _Path:
|
|
|
307
342
|
task.cancel()
|
|
308
343
|
with contextlib.suppress(asyncio.CancelledError):
|
|
309
344
|
await task
|
|
310
|
-
await self.ice
|
|
345
|
+
await close_ice(self.ice)
|
|
311
346
|
|
|
312
347
|
|
|
313
348
|
async def _offer(key: str, user: str, remote: dict) -> dict:
|
|
@@ -327,7 +362,7 @@ async def _offer(key: str, user: str, remote: dict) -> dict:
|
|
|
327
362
|
await ice.add_remote_candidate(Candidate.from_sdp(str(sdp)))
|
|
328
363
|
await ice.add_remote_candidate(None)
|
|
329
364
|
except Exception:
|
|
330
|
-
await ice
|
|
365
|
+
await close_ice(ice)
|
|
331
366
|
raise
|
|
332
367
|
path = _paths[key] = _Path(key, user, ice)
|
|
333
368
|
path.task = asyncio.ensure_future(path.run())
|
|
@@ -343,6 +378,7 @@ def _get_loop() -> asyncio.AbstractEventLoop:
|
|
|
343
378
|
with _lock:
|
|
344
379
|
if _loop is None:
|
|
345
380
|
_loop = asyncio.new_event_loop()
|
|
381
|
+
quiet_aioice_errors(_loop)
|
|
346
382
|
threading.Thread(
|
|
347
383
|
target=_loop.run_forever, name="remoterf-direct", daemon=True
|
|
348
384
|
).start()
|
|
@@ -27,6 +27,19 @@ from .global_onboarding import invite, lan_endpoint
|
|
|
27
27
|
from .user_group_handler import user_group_handler
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def _print_device_choices() -> None:
|
|
31
|
+
"""The ids a whitelist can name, so nobody has to guess."""
|
|
32
|
+
from . import device_manager
|
|
33
|
+
|
|
34
|
+
devices = device_manager.get_all_devices_str()
|
|
35
|
+
if not devices:
|
|
36
|
+
print("No devices are configured yet (devices.yml).")
|
|
37
|
+
return
|
|
38
|
+
print("Devices on this server:")
|
|
39
|
+
for gid in sorted(devices):
|
|
40
|
+
print(f" {gid:>4} {devices[gid]}")
|
|
41
|
+
|
|
42
|
+
|
|
30
43
|
def _invites(rows: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
31
44
|
"""Add the pasteable `invite` form to code rows (bare for LAN-only groups)."""
|
|
32
45
|
lan_only = {
|
|
@@ -103,7 +116,8 @@ def make_user_group_local(session) -> None:
|
|
|
103
116
|
return None
|
|
104
117
|
|
|
105
118
|
if not s or s.lower() in {"all", "*"}:
|
|
106
|
-
|
|
119
|
+
print("List the device ids this group may use, e.g. '0,1,2'.")
|
|
120
|
+
continue
|
|
107
121
|
|
|
108
122
|
# Allow both commas and whitespace
|
|
109
123
|
parts = [p for p in s.replace(",", " ").split() if p]
|
|
@@ -136,7 +150,8 @@ def make_user_group_local(session) -> None:
|
|
|
136
150
|
return
|
|
137
151
|
|
|
138
152
|
# ---- Parameters ----
|
|
139
|
-
|
|
153
|
+
_print_device_choices()
|
|
154
|
+
devices_whitelist = _prompt_int_list("Devices whitelist (e.g. 0,1,2) (c to cancel): ")
|
|
140
155
|
if devices_whitelist is None:
|
|
141
156
|
return
|
|
142
157
|
|
|
@@ -157,7 +172,7 @@ def make_user_group_local(session) -> None:
|
|
|
157
172
|
lan_only = not _prompt_yes_no("Reachable from outside your network (via Global)? (Y/n): ", default_no=False)
|
|
158
173
|
|
|
159
174
|
# ---- Final confirmation ----
|
|
160
|
-
wl_str = ",".join(map(str, devices_whitelist))
|
|
175
|
+
wl_str = ",".join(map(str, devices_whitelist))
|
|
161
176
|
print("\nAbout to create user group with:")
|
|
162
177
|
print(f" group_name : {group_name}")
|
|
163
178
|
print(f" devices_whitelist : {wl_str}")
|
|
@@ -270,7 +285,8 @@ def edit_user_group_local(session) -> None:
|
|
|
270
285
|
if s == "":
|
|
271
286
|
return "" # unchanged
|
|
272
287
|
if s.lower() in {"all", "*"}:
|
|
273
|
-
|
|
288
|
+
print("List the device ids this group may use, e.g. '0,1,2'.")
|
|
289
|
+
return _prompt_devices_optional(msg)
|
|
274
290
|
parts = [p for p in s.replace(",", " ").split() if p]
|
|
275
291
|
try:
|
|
276
292
|
vals = [int(p) for p in parts]
|
|
@@ -313,8 +329,9 @@ def edit_user_group_local(session) -> None:
|
|
|
313
329
|
if group_name == "":
|
|
314
330
|
group_name = None
|
|
315
331
|
|
|
332
|
+
_print_device_choices()
|
|
316
333
|
devices_whitelist = _prompt_devices_optional(
|
|
317
|
-
"New devices whitelist (e.g. 0,1,2 |
|
|
334
|
+
"New devices whitelist (e.g. 0,1,2 | Enter unchanged, c cancel): "
|
|
318
335
|
)
|
|
319
336
|
if devices_whitelist is None:
|
|
320
337
|
return
|
|
@@ -56,14 +56,14 @@ remoteRF_server/server/commands.py,sha256=ccb_Ab1mbIkosBsFGJnDSccrjWtR_Lymvvn3Iq
|
|
|
56
56
|
remoteRF_server/server/console.py,sha256=J91LfwPVmBgielOxfE740NOYduekggyZkqi-47y_A4w,4472
|
|
57
57
|
remoteRF_server/server/control.py,sha256=Uq1Fk0zIoHHX_EXfz3OuNle8urvO_UhAiB5Lk5cs2e4,5177
|
|
58
58
|
remoteRF_server/server/device_manager.py,sha256=PPuCwlPSmjfVpCqy_hCaOr9WvFgE8mqtLMhWOAgXNDA,39281
|
|
59
|
-
remoteRF_server/server/direct_path.py,sha256=
|
|
59
|
+
remoteRF_server/server/direct_path.py,sha256=ry4wRbqMQdSSh-HVFlbbMdTCNM0XksTl-h9MORJ0PLM,16781
|
|
60
60
|
remoteRF_server/server/dynamic_v2.py,sha256=AMhQEFhNAvCNcF-PdfCCQQLmeoaR7s1Os8et1KFGn_8,70814
|
|
61
61
|
remoteRF_server/server/global_onboarding.py,sha256=NcKG8TYhCJEiaCtdXL1jEgVm-R_xWpOIj5KI4bWfkr0,39942
|
|
62
62
|
remoteRF_server/server/grpc_server.py,sha256=91FpJubzN_Wfuk6fW_owIEzNCukd333sAGW68FUU8pk,46787
|
|
63
63
|
remoteRF_server/server/host_dynamic_v2.py,sha256=1rJQwP4knSd0EXkByrSn_ryjLx81f6sp6SNYr_aEass,8105
|
|
64
64
|
remoteRF_server/server/reservation.py,sha256=BQJLGNVAdKMZu2Lg4DGO9UhuJ0b1GSF8K1DgIOFrYUg,67816
|
|
65
65
|
remoteRF_server/server/rpc_manager.py,sha256=BDvsTSVRxwNF2ujuMbIb5TYNAUI6AH4xXBuXrb8lltM,17223
|
|
66
|
-
remoteRF_server/server/user_group_cli.py,sha256=
|
|
66
|
+
remoteRF_server/server/user_group_cli.py,sha256=0QbsGfeIqkyU6E1naGwR-i7BxptPMMTQCi1m7yM03JM,26259
|
|
67
67
|
remoteRF_server/server/user_group_handler.py,sha256=1ax73W_P3H6GDxQS13evwA7G7skIElFVLuS0MFqsFyU,41780
|
|
68
68
|
remoteRF_server/server/v2_errors.py,sha256=IS3hIhf5tDe7jaOrDAVQPjGBpqAjN7442BlJYgfJo7g,3331
|
|
69
69
|
remoteRF_server/server/deployment/__init__.py,sha256=YV86uafd8XiGD7sLaqNfO5xxmt5te2R6DUhD-w1lZuY,77
|
|
@@ -90,9 +90,9 @@ remoteRF_server/tools/gen_certs.py,sha256=Vbyu8JjRu__UYPVmyCRXt5SOw0Za1HV7g1md3G
|
|
|
90
90
|
remoteRF_server/tools/gist_status.py,sha256=SFv2iQgQrIKT9gxKrU-_Dr7S0p0rE4wQM6J3OC6FcoM,4649
|
|
91
91
|
remoteRF_server/tools/gist_status_testing.py,sha256=IYw7UkPjAUpKDTtIlnYGb5g6SJkwz4TRGUfJJ6f4LhQ,2690
|
|
92
92
|
remoteRF_server/tools/introspect_uhd.py,sha256=vUpPb0rM9tsHPxWadS3EfMDE-gMd-TvNV0TjrZOQqBY,4531
|
|
93
|
-
remoterf_server-1.1.0.
|
|
94
|
-
remoterf_server-1.1.0.
|
|
95
|
-
remoterf_server-1.1.0.
|
|
96
|
-
remoterf_server-1.1.0.
|
|
97
|
-
remoterf_server-1.1.0.
|
|
98
|
-
remoterf_server-1.1.0.
|
|
93
|
+
remoterf_server-1.1.0.dev48.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
94
|
+
remoterf_server-1.1.0.dev48.dist-info/METADATA,sha256=ZhdOC9w67CZe59Nn38BVHXVFsnyGESpLxDE5izAzi5s,42069
|
|
95
|
+
remoterf_server-1.1.0.dev48.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
96
|
+
remoterf_server-1.1.0.dev48.dist-info/entry_points.txt,sha256=_bbKk65PfYi-n6zUjqOiOwcalf_Ws1TCGATIe1TukxE,136
|
|
97
|
+
remoterf_server-1.1.0.dev48.dist-info/top_level.txt,sha256=NuYWe8dSx3qdbxshWBwOgx68EHmJ9I8Zvxam4ARsQ_I,30
|
|
98
|
+
remoterf_server-1.1.0.dev48.dist-info/RECORD,,
|
|
File without changes
|
{remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{remoterf_server-1.1.0.dev46.dist-info → remoterf_server-1.1.0.dev48.dist-info}/top_level.txt
RENAMED
|
File without changes
|