Skip to content

Commit 9c67dcf

Browse files
committed
fix: stop waiting discovery once the target is claimed
1 parent ba2f184 commit 9c67dcf

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

src/transport/ReactNativeBleTransport.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,36 @@ describe('ReactNativeBleTransport', () => {
745745
await transport.disconnect();
746746
});
747747

748+
it('does not drain waiting probes while preparing a claimed target', async () => {
749+
let callback!: (error: Error | null, value: Device | null) => void;
750+
let releaseMtu!: () => void;
751+
const releases: (() => void)[] = [];
752+
const target = device({ id: 'target', requestMTU: jest.fn(() => new Promise<Device>((resolve) => {
753+
releaseMtu = () => resolve(target);
754+
})) });
755+
const others = Array.from({ length: 3 }, (_, index) => device({
756+
id: `other-${index}`, discoverAllServicesAndCharacteristics: jest.fn(() => new Promise<Device>((resolve) => {
757+
releases.push(() => resolve(device()));
758+
})),
759+
}));
760+
const queued = device({ id: 'queued' });
761+
const transport = new ReactNativeBleTransport(manager({ startDeviceScan: jest.fn((_u, _o, cb) => { callback = cb; }) }), 'android');
762+
const result = transport.resolveAndConnect('pc-1');
763+
await waitFor(() => !!callback);
764+
others.forEach((peer) => callback(null, peer));
765+
callback(null, target);
766+
callback(null, queued);
767+
await waitFor(() => !!releaseMtu && releases.length === 3);
768+
releases.forEach((release) => release());
769+
await waitFor(() => others.every((peer) => (peer.readCharacteristicForService as jest.Mock).mock.calls.length === 1));
770+
callback(null, queued);
771+
expect(queued.isConnected).not.toHaveBeenCalled();
772+
releaseMtu();
773+
await result;
774+
expect(queued.isConnected).not.toHaveBeenCalled();
775+
await transport.disconnect();
776+
});
777+
748778
it('waits for cancelled discovery probe cleanup before a real connection', async () => {
749779
let scanCallback!: (error: Error | null, value: Device | null) => void;
750780
let releaseDiscovery!: (value: Device) => void;

src/transport/ReactNativeBleTransport.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export class ReactNativeBleTransport implements BleTransport {
150150
this.#resolutionCancel = cancel;
151151
const timer = setTimeout(() => { void cancel(new Error('Saved PC discovery timed out.'), 'timed_out'); }, this.nativeTimeoutMs);
152152
const onAdvertisement = (error: Error | null, device: Device | null) => {
153-
if (!active || operation !== this.#operation) return;
153+
if (!active || operation !== this.#operation || claimedDeviceId !== null) return;
154154
if (error) { void cancel(new Error('Saved PC discovery failed.')); return; }
155155
if (!device || this.#scanDevices.has(device.id) || this.#scanKeys.has(this.#scanKey(device))) return;
156156
if (this.#scanDevices.size >= 4) {
@@ -165,6 +165,7 @@ export class ReactNativeBleTransport implements BleTransport {
165165
this.#recordStage('selected_match', desktop.desktopId === desktopId ? 'succeeded' : 'not_matched', operation);
166166
if (desktop.desktopId !== desktopId || claimedDeviceId !== null) return false;
167167
claimedDeviceId = device.id;
168+
waiting.clear();
168169
return true;
169170
}).then(async (desktop) => {
170171
if (!active || operation !== this.#operation || desktop?.desktopId !== desktopId || claimedDeviceId !== device.id) return;

0 commit comments

Comments
 (0)