fix(bluetooth): never hang when bluetoothd is not running #77

Merged
Breadway merged 1 commit from fix/bset-65-bluetooth-timeout into main 2026-10-14 11:58:54 +08:00
Owner

Closes BSET-65

What

bluetoothctl waits forever for bluetoothd. When the service is stopped, or never starts because there is no adapter, get_adapter_powered never returned and the page stayed on "Loading..." indefinitely.

  • Every bluetoothctl call goes through btctl(), which uses tokio::time::timeout plus kill_on_drop. Limits: 5s for show/devices/info/power/disconnect/remove, 15s for scan, 30s for pair/connect. A timeout returns a readable error.
  • New get_bluetooth_state checks systemctl is-active bluetooth.service and /sys/class/bluetooth/hci* before calling bluetoothctl. It returns no-adapter, service-off or ready {powered}.
  • The page now shows a "The Bluetooth service is off" state with a Start Bluetooth button. It runs pkexec systemctl start bluetooth.service (fixed unit, nothing caller-supplied) and then reloads.
  • Home still uses get_adapter_powered, which is now bounded, so it can't hang either.

Tests

  • New: a hung command times out and is killed (sleep 30 vs 200ms), quick command output, sysfs adapter detection.
  • cargo fmt, clippy --all-targets -D warnings, cargo test (147), svelte-check 0/0, npm test, build.
  • Live BOS VM (no adapter, bluetooth.service inactive): the page shows "No Bluetooth adapter found" immediately. On main it stayed on Loading for 2+ minutes.

Capability changes

Added: the service-off state and the Start Bluetooth button. Nothing removed.

Closes BSET-65 ## What `bluetoothctl` waits forever for bluetoothd. When the service is stopped, or never starts because there is no adapter, `get_adapter_powered` never returned and the page stayed on "Loading..." indefinitely. - Every bluetoothctl call goes through `btctl()`, which uses `tokio::time::timeout` plus `kill_on_drop`. Limits: 5s for show/devices/info/power/disconnect/remove, 15s for scan, 30s for pair/connect. A timeout returns a readable error. - New `get_bluetooth_state` checks `systemctl is-active bluetooth.service` and `/sys/class/bluetooth/hci*` before calling bluetoothctl. It returns `no-adapter`, `service-off` or `ready {powered}`. - The page now shows a "The Bluetooth service is off" state with a **Start Bluetooth** button. It runs `pkexec systemctl start bluetooth.service` (fixed unit, nothing caller-supplied) and then reloads. - Home still uses `get_adapter_powered`, which is now bounded, so it can't hang either. ## Tests - New: a hung command times out and is killed (`sleep 30` vs 200ms), quick command output, sysfs adapter detection. - cargo fmt, clippy --all-targets -D warnings, cargo test (147), svelte-check 0/0, npm test, build. - Live BOS VM (no adapter, bluetooth.service inactive): the page shows "No Bluetooth adapter found" immediately. On main it stayed on Loading for 2+ minutes. ## Capability changes Added: the service-off state and the Start Bluetooth button. Nothing removed.
fix(bluetooth): never hang when bluetoothd is not running
All checks were successful
check / check (push) Successful in 4m39s
40a9ec5ae9
bluetoothctl waits forever for bluetoothd, so with the service stopped (or
no adapter, so it never starts) the Bluetooth page stayed on Loading.
Every bluetoothctl call now goes through btctl(): bounded by a timeout and
killed on drop. get_bluetooth_state checks the service and
/sys/class/bluetooth first and returns no-adapter, service-off or ready.
Service-off shows Start Bluetooth (pkexec systemctl start bluetooth.service,
fixed unit only).

Verified in a BOS VM with no adapter and bluetooth.service inactive: the
page shows No Bluetooth adapter found immediately instead of hanging.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Breadway/bos-settings!77
No description provided.