Skip to content

Commit

Permalink
support async port closing in webserial
Browse files Browse the repository at this point in the history
  • Loading branch information
tl-sl committed Nov 3, 2024
1 parent 532c05e commit 7e9fa0b
Showing 1 changed file with 21 additions and 10 deletions.
31 changes: 21 additions & 10 deletions src/webserial_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MockSqlite3:
sys.modules["sqlite3"] = MockSqlite3()

_SERIAL_PORT = None
_SERIAL_PORT_CLOSING_QUEUE = []
_SERIAL_PORT_CLOSING_TASKS = []

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -111,14 +111,24 @@ def _cleanup(self, exception: BaseException | None) -> None:
self._js_writer.releaseLock()
self._js_writer = None

closing_task = None

if self._port is not None:
_SERIAL_PORT_CLOSING_QUEUE.append(
asyncio.create_task(close_port(self._port))
)
closing_task = asyncio.create_task(close_port(self._port))
_SERIAL_PORT_CLOSING_TASKS.append(closing_task)
self._port = None

if self._protocol is not None:
self._protocol.connection_lost(exception)
if closing_task is None:
self._protocol.connection_lost(exception)
else:
closing_task.add_done_callback(
lambda _, protocol=self._protocol: protocol.connection_lost(exception)
)
closing_task.add_done_callback(
lambda _: _SERIAL_PORT_CLOSING_TASKS.remove(closing_task)
)

self._protocol = None

def close(self) -> None:
Expand All @@ -141,11 +151,12 @@ async def create_serial_connection(
rtscts=False,
xonxoff=False,
) -> tuple[WebSerialTransport, asyncio.Protocol]:
# XXX: Since asyncio's `transport.close` is synchronous but JavaScript's is not, we
# must delegate closing to a task and then "block" at the next asynchronous entry
# point to allow the serial port to be re-opened immediately after being closed
while _SERIAL_PORT_CLOSING_QUEUE:
await _SERIAL_PORT_CLOSING_QUEUE.pop()
while _SERIAL_PORT_CLOSING_TASKS:
_LOGGER.warning(
"Serial connection was not closed before a new one was opened!"
" Waiting before opening a new one."
)
await _SERIAL_PORT_CLOSING_TASKS.pop()

# `url` is ignored, `_SERIAL_PORT` is used instead
await _SERIAL_PORT.open(
Expand Down

0 comments on commit 7e9fa0b

Please sign in to comment.