Skip to content

fix: make magic peripheral handoff resilient (+ extend to adoption, cleanups)#57

Merged
MegaManSec merged 2 commits into
mainfrom
fix/peripheral-handoff-resilient
Jun 18, 2026
Merged

fix: make magic peripheral handoff resilient (+ extend to adoption, cleanups)#57
MegaManSec merged 2 commits into
mainfrom
fix/peripheral-handoff-resilient

Conversation

@MegaManSec

Copy link
Copy Markdown
Owner

Summary

Cherry-picks upstream iFurySt/magic-switch@270c1e5 ("fix: make magic peripheral handoff resilient"), original author preserved, then extends it to this fork's adoption path and tidies the new code to match repo conventions.

What the upstream fix does

  • Take-from-peer now refreshes a stale local pairing. A peripheral can sit at paired=true while openConnection() fails; the old path gave up and left it connectable on neither Mac. It now -removes the stale bond and re-pairs.
  • CONNECT_ALL / CONNECT_ONE receivers ack the real connect result instead of "command received", so a failed handoff is actually rolled back / reclaimed by the sender.
  • Auto-accepts pairing confirmation; surfaces a "Pairing Failed" notification.
  • Raises the handoff timeouts so the connection survives until the real ack.

This fork's additions (2nd commit)

  • Extended the stale-pairing refresh to continueAdoption — this fork's "adopt when the peer vanishes" path (feat: adopt peripherals when the other Mac sleeps or vanishes #54, which upstream never saw) is itself a take-from-peer grab, so it now passes refreshPairingBeforeConnect: true (kept silent, since it's a background retry). Without it, adoption hits the same paired=true / openConnection()-fails dead end the fix removes.
  • Cleanups (no behavior change): extract the duplicated 75 body-timeout literal into a named NetworkDeviceStore.handoffBodyTimeout with the cross-file invariant documented (must exceed the 60s pair watchdog, stay <= IncomingConnection.idleTimeout); document why idleTimeout went 30s -> 75s; comment the post--remove Thread.sleep.

Cherry-pick conflict resolution (folded into 1st commit)

  • This fork hoisted reconnectInFlight.remove(id) to the top of reclaimIfPeerIsFree's else-block, so I dropped upstream's duplicate and kept the new connectPeripheral(...) signature.

Verification

xcodebuild -scheme "Magic Switch" -configuration Debug -> BUILD SUCCEEDED.

iFurySt and others added 2 commits June 18, 2026 19:40
Builds on the cherry-picked handoff-resilience fix.

Behavior change:
- `continueAdoption` is a take-from-peer grab (it claims a peripheral when
  the peer vanishes), so it now passes `refreshPairingBeforeConnect: true`
  like the other take-from-peer callers. Without it, adoption hits the same
  stale `paired=true` / `openConnection()`-fails dead end the fix removes.
  Stays silent (`announcePairTimeout: false`) — it's a background retry.

Cleanups (no behavior change):
- Extract the duplicated `75` body-timeout literal into a named
  `NetworkDeviceStore.handoffBodyTimeout`, documenting the cross-file
  invariant: it must exceed the 60s pair watchdog and stay <=
  IncomingConnection.idleTimeout, so neither side gives up before the
  receiver acks the real connect result.
- Explain why IncomingConnection.idleTimeout was raised 30s -> 75s.
- Comment the post-`-remove` Thread.sleep: it lets the async unbond settle
  and only stalls the background bluetoothQueue, never the UI.
@MegaManSec MegaManSec merged commit 20376bf into main Jun 18, 2026
2 checks passed
@MegaManSec MegaManSec deleted the fix/peripheral-handoff-resilient branch June 18, 2026 17:49
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.17.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants