remoteRF-server 1.1.0.dev48__py3-none-any.whl → 1.1.0.dev50__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 +36 -14
- {remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/METADATA +1 -1
- {remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/RECORD +7 -7
- {remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/WHEEL +0 -0
- {remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/entry_points.txt +0 -0
- {remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/licenses/LICENSE +0 -0
- {remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/top_level.txt +0 -0
|
@@ -54,22 +54,39 @@ logger = logging.getLogger("remoteRF_server.direct")
|
|
|
54
54
|
async def close_ice(ice) -> None:
|
|
55
55
|
"""Close an aioice Connection without the library's after-close noise.
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
A cancelled ``connect()`` (a punch that timed out) never reaches aioice's
|
|
58
|
+
own "cancel remaining checks" loop, so its check tasks keep running and
|
|
59
|
+
its STUN timers stay armed against sockets close() is about to take. Stop
|
|
60
|
+
both before closing."""
|
|
61
|
+
# Cancel the connectivity checks first. Failing their STUN transactions
|
|
62
|
+
# instead only makes aioice start replacement checks, which then hang on
|
|
63
|
+
# a closed socket and die "pending" when they are collected.
|
|
64
|
+
checks = [pair.task for pair in list(getattr(ice, "_check_list", [])) if pair.task is not None]
|
|
65
|
+
for task in checks:
|
|
66
|
+
task.cancel()
|
|
67
|
+
if checks:
|
|
68
|
+
await asyncio.gather(*checks, return_exceptions=True)
|
|
63
69
|
for protocol in list(getattr(ice, "_protocols", [])):
|
|
64
70
|
for transaction in list(getattr(protocol, "transactions", {}).values()):
|
|
65
71
|
handle = getattr(transaction, "_Transaction__timeout_handle", None)
|
|
66
72
|
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())
|
|
73
|
+
handle.cancel() # a retry would fire on the socket close() is about to take
|
|
71
74
|
await ice.close()
|
|
72
|
-
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def cancel_tasks(tasks) -> None:
|
|
78
|
+
"""Cancel these tasks and wait for them to finish.
|
|
79
|
+
|
|
80
|
+
A task that is cancelled but never awaited can be collected while still
|
|
81
|
+
pending, and Python prints a traceback for it that nobody can act on.
|
|
82
|
+
The caller's own task is never cancelled, so this is safe to call from
|
|
83
|
+
inside one of the tasks being torn down."""
|
|
84
|
+
current = asyncio.current_task()
|
|
85
|
+
tasks = [task for task in tasks if task is not None and task is not current and not task.done()]
|
|
86
|
+
for task in tasks:
|
|
87
|
+
task.cancel()
|
|
88
|
+
if tasks:
|
|
89
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
73
90
|
|
|
74
91
|
|
|
75
92
|
def quiet_aioice_errors(loop) -> None:
|
|
@@ -246,6 +263,7 @@ class _Path:
|
|
|
246
263
|
self.calls = 0
|
|
247
264
|
self.task: Optional[asyncio.Task] = None
|
|
248
265
|
self.transport: Optional[_IceTransport] = None
|
|
266
|
+
self.streams: set[asyncio.Task] = set()
|
|
249
267
|
|
|
250
268
|
async def run(self) -> None:
|
|
251
269
|
protocol = None
|
|
@@ -264,8 +282,7 @@ class _Path:
|
|
|
264
282
|
printf(f"Direct path open: {self.user} from {self.peer[0]}:{self.peer[1]} ({where})", Sty.GRAY)
|
|
265
283
|
await asyncio.wait({pump, closed}, return_when=asyncio.FIRST_COMPLETED)
|
|
266
284
|
finally:
|
|
267
|
-
pump
|
|
268
|
-
closed.cancel()
|
|
285
|
+
await cancel_tasks((pump, closed))
|
|
269
286
|
except Exception as exc: # noqa: BLE001 - a failed punch is expected on some networks
|
|
270
287
|
printf(f"Direct path failed: {self.user}: {type(exc).__name__}: {exc}", Sty.GRAY)
|
|
271
288
|
finally:
|
|
@@ -306,7 +323,11 @@ class _Path:
|
|
|
306
323
|
protocol.datagram_received(data, self.peer)
|
|
307
324
|
|
|
308
325
|
def _stream(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
|
309
|
-
|
|
326
|
+
# Tracked, not fire-and-forget: a stream holds a device call, and the
|
|
327
|
+
# path may close under it.
|
|
328
|
+
task = asyncio.ensure_future(self._serve(reader, writer))
|
|
329
|
+
self.streams.add(task)
|
|
330
|
+
task.add_done_callback(self.streams.discard)
|
|
310
331
|
|
|
311
332
|
async def _serve(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
|
312
333
|
bad_frame = None
|
|
@@ -342,6 +363,7 @@ class _Path:
|
|
|
342
363
|
task.cancel()
|
|
343
364
|
with contextlib.suppress(asyncio.CancelledError):
|
|
344
365
|
await task
|
|
366
|
+
await cancel_tasks(list(self.streams))
|
|
345
367
|
await close_ice(self.ice)
|
|
346
368
|
|
|
347
369
|
|
|
@@ -56,7 +56,7 @@ 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=TrL0aWCUXN9Lmuww-v_AXtLIOqTkckm2vPW91xcnOLI,17875
|
|
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
|
|
@@ -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.dev50.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
94
|
+
remoterf_server-1.1.0.dev50.dist-info/METADATA,sha256=jy_xvhBrCSFGJ5x5I_ZBgDynd1Hwe7uFv-1KaC-Fs60,42069
|
|
95
|
+
remoterf_server-1.1.0.dev50.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
96
|
+
remoterf_server-1.1.0.dev50.dist-info/entry_points.txt,sha256=_bbKk65PfYi-n6zUjqOiOwcalf_Ws1TCGATIe1TukxE,136
|
|
97
|
+
remoterf_server-1.1.0.dev50.dist-info/top_level.txt,sha256=NuYWe8dSx3qdbxshWBwOgx68EHmJ9I8Zvxam4ARsQ_I,30
|
|
98
|
+
remoterf_server-1.1.0.dev50.dist-info/RECORD,,
|
|
File without changes
|
{remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{remoterf_server-1.1.0.dev48.dist-info → remoterf_server-1.1.0.dev50.dist-info}/top_level.txt
RENAMED
|
File without changes
|