Skip to content

Commit

Permalink
backends/bluezdbus/client: fix not disconnecting if get_services() th…
Browse files Browse the repository at this point in the history
…rows

It is possible for get_services() to raise an exception, e.g. if
external code cancels the task. If this happens, we need to be sure
that the device disconnects so the BlueZClient is in a consistent
state (if the connect() method raises and exception, is is expected
that the device will not be connected).

To fix this, we can just move the call to get_services() inside of the
existing try block that will disconnect on any exception, then reraise
the exception.

Fixes #951.
  • Loading branch information
dlech committed Aug 29, 2022
1 parent 6901c63 commit b93082a
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Added
Fixed
-----
* Made BlueZ D-Bus signal callback logging lazy to improve performance.
* Fixed possible bad connection state in BlueZ backend. Fixes #951.

Changed
-------
Expand Down
22 changes: 12 additions & 10 deletions bleak/backends/bluezdbus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,19 @@ def on_value_changed(char_path: str, value: bytes) -> None:
assert_reply(reply)

self._is_connected = True

# Create a task that runs until the device is disconnected.
self._disconnect_monitor_event = asyncio.Event()
asyncio.ensure_future(self._disconnect_monitor())

await self.get_services()

return True
except BaseException:
# calling Disconnect cancels any pending connect request
# Calling Disconnect cancels any pending connect request. Also,
# if connection was successful but get_services() raises (e.g.
# because task was cancelled), the we still need to disconnect
# before passing on the exception.
if self._bus:
# If disconnected callback already fired, this will be a no-op
# since self._bus will be None and the _cleanup_all call will
Expand Down Expand Up @@ -196,15 +207,6 @@ def on_value_changed(char_path: str, value: bytes) -> None:
)

raise

# Create a task that runs until the device is disconnected.
self._disconnect_monitor_event = asyncio.Event()
asyncio.ensure_future(self._disconnect_monitor())

# Get all services. This means making the actual connection.
await self.get_services()

return True
except BaseException:
self._cleanup_all()
raise
Expand Down

0 comments on commit b93082a

Please sign in to comment.