@onekeyfe/hd-transport-react-native 1.2.0-alpha.22 → 1.2.0-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -23
- package/package.json +5 -5
- package/src/__tests__/protocolV2Link.test.ts +30 -2
- package/src/index.ts +44 -19
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ declare class ReactNativeBleTransport {
|
|
|
55
55
|
blePlxManager: BleManager | undefined;
|
|
56
56
|
_messages: ReturnType<typeof transport__default.parseConfigure> | undefined;
|
|
57
57
|
_messagesV2: ReturnType<typeof transport__default.parseConfigure> | undefined;
|
|
58
|
+
private protocolV2SchemaConfiguration;
|
|
58
59
|
name: string;
|
|
59
60
|
configured: boolean;
|
|
60
61
|
stopped: boolean;
|
|
@@ -70,6 +71,7 @@ declare class ReactNativeBleTransport {
|
|
|
70
71
|
private protocolV2FramePromises;
|
|
71
72
|
private protocolV2Links;
|
|
72
73
|
private monitorTokens;
|
|
74
|
+
private disconnectEventTokens;
|
|
73
75
|
private nextMonitorToken;
|
|
74
76
|
constructor(options: TransportOptions);
|
|
75
77
|
init(logger: any, emitter: EventEmitter): void;
|
|
@@ -79,6 +81,7 @@ declare class ReactNativeBleTransport {
|
|
|
79
81
|
getPlxManager(): Promise<BleManager>;
|
|
80
82
|
resolveCharacteristics(device: Device): Promise<ResolvedBleCharacteristics>;
|
|
81
83
|
attachDisconnectSubscription(transport: BleTransport, device: Device, uuid: string): void;
|
|
84
|
+
private emitDeviceDisconnect;
|
|
82
85
|
reconnectFirmwareUploadTransport(uuid: string, transport: BleTransport): Promise<void>;
|
|
83
86
|
/**
|
|
84
87
|
* 获取设备列表
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -427,6 +427,7 @@ class ReactNativeBleTransport {
|
|
|
427
427
|
}),
|
|
428
428
|
});
|
|
429
429
|
this.monitorTokens = new Map();
|
|
430
|
+
this.disconnectEventTokens = new Map();
|
|
430
431
|
this.nextMonitorToken = 1;
|
|
431
432
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
432
433
|
}
|
|
@@ -440,10 +441,18 @@ class ReactNativeBleTransport {
|
|
|
440
441
|
this._messages = messages;
|
|
441
442
|
}
|
|
442
443
|
configureProtocolV2(signedData) {
|
|
444
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
445
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
443
449
|
this._messagesV2 = parseConfigure(signedData);
|
|
444
|
-
this.
|
|
445
|
-
|
|
446
|
-
.
|
|
450
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
451
|
+
if (isReconfiguration) {
|
|
452
|
+
this.protocolV2Links
|
|
453
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
454
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
455
|
+
}
|
|
447
456
|
}
|
|
448
457
|
listen() {
|
|
449
458
|
}
|
|
@@ -536,8 +545,8 @@ class ReactNativeBleTransport {
|
|
|
536
545
|
attachDisconnectSubscription(transport, device, uuid) {
|
|
537
546
|
var _a;
|
|
538
547
|
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
548
|
+
const { monitorToken } = transport;
|
|
539
549
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
540
|
-
var _a;
|
|
541
550
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
542
551
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
543
552
|
return;
|
|
@@ -546,13 +555,13 @@ class ReactNativeBleTransport {
|
|
|
546
555
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
|
|
547
556
|
return;
|
|
548
557
|
}
|
|
558
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) {
|
|
559
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale generation: ', device === null || device === void 0 ? void 0 : device.id);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
549
562
|
try {
|
|
550
563
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
551
|
-
(
|
|
552
|
-
name: device === null || device === void 0 ? void 0 : device.name,
|
|
553
|
-
id: device === null || device === void 0 ? void 0 : device.id,
|
|
554
|
-
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
555
|
-
});
|
|
564
|
+
this.emitDeviceDisconnect(uuid, device === null || device === void 0 ? void 0 : device.name, monitorToken);
|
|
556
565
|
if (this.runPromise) {
|
|
557
566
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
558
567
|
this.runPromise.reject(error);
|
|
@@ -567,6 +576,22 @@ class ReactNativeBleTransport {
|
|
|
567
576
|
}
|
|
568
577
|
});
|
|
569
578
|
}
|
|
579
|
+
emitDeviceDisconnect(uuid, name, token) {
|
|
580
|
+
var _a;
|
|
581
|
+
if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (this.monitorTokens.get(uuid) !== token) {
|
|
585
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect event ignored for stale generation: ', uuid);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
this.disconnectEventTokens.set(uuid, token);
|
|
589
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
590
|
+
name,
|
|
591
|
+
id: uuid,
|
|
592
|
+
connectId: uuid,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
570
595
|
reconnectFirmwareUploadTransport(uuid, transport) {
|
|
571
596
|
var _a, _b;
|
|
572
597
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -712,7 +737,7 @@ class ReactNativeBleTransport {
|
|
|
712
737
|
});
|
|
713
738
|
}
|
|
714
739
|
acquire(input) {
|
|
715
|
-
var _a
|
|
740
|
+
var _a;
|
|
716
741
|
return __awaiter(this, void 0, void 0, function* () {
|
|
717
742
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
718
743
|
if (!uuid) {
|
|
@@ -848,11 +873,6 @@ class ReactNativeBleTransport {
|
|
|
848
873
|
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
849
874
|
}
|
|
850
875
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
851
|
-
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
852
|
-
name: device.name,
|
|
853
|
-
id: device.id,
|
|
854
|
-
connectId: device.id,
|
|
855
|
-
});
|
|
856
876
|
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
857
877
|
return { uuid, protocolType };
|
|
858
878
|
});
|
|
@@ -1232,6 +1252,7 @@ class ReactNativeBleTransport {
|
|
|
1232
1252
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1233
1253
|
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1234
1254
|
const transport = transportCache[session];
|
|
1255
|
+
const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
|
|
1235
1256
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1236
1257
|
try {
|
|
1237
1258
|
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing disconnect subscription');
|
|
@@ -1244,7 +1265,7 @@ class ReactNativeBleTransport {
|
|
|
1244
1265
|
}
|
|
1245
1266
|
if (transport === null || transport === void 0 ? void 0 : transport.notifySubscription) {
|
|
1246
1267
|
try {
|
|
1247
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (
|
|
1268
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (_b = transport.notifyCharacteristic) === null || _b === void 0 ? void 0 : _b.uuid);
|
|
1248
1269
|
transport.notifySubscription.remove();
|
|
1249
1270
|
transport.notifySubscription = undefined;
|
|
1250
1271
|
}
|
|
@@ -1254,7 +1275,7 @@ class ReactNativeBleTransport {
|
|
|
1254
1275
|
}
|
|
1255
1276
|
if (session) {
|
|
1256
1277
|
try {
|
|
1257
|
-
yield ((
|
|
1278
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
|
|
1258
1279
|
}
|
|
1259
1280
|
catch (e) {
|
|
1260
1281
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1269,7 +1290,7 @@ class ReactNativeBleTransport {
|
|
|
1269
1290
|
}
|
|
1270
1291
|
}
|
|
1271
1292
|
try {
|
|
1272
|
-
yield ((
|
|
1293
|
+
yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
|
|
1273
1294
|
}
|
|
1274
1295
|
catch (e) {
|
|
1275
1296
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1282,15 +1303,14 @@ class ReactNativeBleTransport {
|
|
|
1282
1303
|
this.protocolV2Assemblers.delete(session);
|
|
1283
1304
|
this.resetProtocolV2Frames(session);
|
|
1284
1305
|
try {
|
|
1285
|
-
(
|
|
1286
|
-
name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
|
|
1287
|
-
id: session,
|
|
1288
|
-
connectId: session,
|
|
1289
|
-
});
|
|
1306
|
+
this.emitDeviceDisconnect(session, (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name, monitorToken);
|
|
1290
1307
|
}
|
|
1291
1308
|
catch (e) {
|
|
1292
1309
|
Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
|
|
1293
1310
|
}
|
|
1311
|
+
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1312
|
+
this.monitorTokens.delete(session);
|
|
1313
|
+
}
|
|
1294
1314
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1295
1315
|
});
|
|
1296
1316
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.24",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"lint:fix": "eslint . --fix"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
23
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
22
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.24",
|
|
23
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.24",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.24",
|
|
25
25
|
"@onekeyfe/react-native-ble-utils": "^0.1.6",
|
|
26
26
|
"react-native-ble-plx": "3.5.1"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "43663337d94350430cc507c74d6eec5a076bd4e9"
|
|
29
29
|
}
|
|
@@ -2,6 +2,7 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
import transportPackage, {
|
|
3
3
|
PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
4
4
|
ProtocolV2,
|
|
5
|
+
TRANSPORT_EVENT,
|
|
5
6
|
bytesToHex,
|
|
6
7
|
} from '@onekeyfe/hd-transport';
|
|
7
8
|
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
@@ -102,6 +103,7 @@ const createHarness = () => {
|
|
|
102
103
|
characteristic: { value: string } | null
|
|
103
104
|
) => void)
|
|
104
105
|
| undefined;
|
|
106
|
+
let disconnectCallback: (() => void) | undefined;
|
|
105
107
|
const notifyCharacteristic = {
|
|
106
108
|
uuid: '0003',
|
|
107
109
|
deviceID: uuid,
|
|
@@ -140,7 +142,11 @@ const createHarness = () => {
|
|
|
140
142
|
localName: 'OneKey Pro 2',
|
|
141
143
|
serviceUUIDs: ['fffd'],
|
|
142
144
|
isConnected: jest.fn(() => Promise.resolve(true)),
|
|
143
|
-
|
|
145
|
+
cancelConnection: jest.fn(() => Promise.resolve()),
|
|
146
|
+
onDisconnected: jest.fn(callback => {
|
|
147
|
+
disconnectCallback = callback;
|
|
148
|
+
return { remove: jest.fn() };
|
|
149
|
+
}),
|
|
144
150
|
};
|
|
145
151
|
const bleManager = {
|
|
146
152
|
devices: jest.fn(() => Promise.resolve([device])),
|
|
@@ -148,16 +154,18 @@ const createHarness = () => {
|
|
|
148
154
|
cancelTransaction: jest.fn(() => Promise.resolve()),
|
|
149
155
|
};
|
|
150
156
|
const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
|
|
157
|
+
const emitter = new EventEmitter();
|
|
151
158
|
transport.blePlxManager = bleManager;
|
|
152
159
|
transport.resolveCharacteristics = jest.fn(() =>
|
|
153
160
|
Promise.resolve({ writeCharacteristic, notifyCharacteristic })
|
|
154
161
|
);
|
|
155
|
-
transport.init({ debug: jest.fn(), error: jest.fn() },
|
|
162
|
+
transport.init({ debug: jest.fn(), error: jest.fn() }, emitter);
|
|
156
163
|
transport.configure(protocolV1Schema);
|
|
157
164
|
transport.configureProtocolV2(protocolV2Schema);
|
|
158
165
|
|
|
159
166
|
return {
|
|
160
167
|
transport,
|
|
168
|
+
emitter,
|
|
161
169
|
uuid,
|
|
162
170
|
sentSeqs,
|
|
163
171
|
writeCharacteristic,
|
|
@@ -167,6 +175,9 @@ const createHarness = () => {
|
|
|
167
175
|
emitMonitorError(error: Error & { reason?: string }) {
|
|
168
176
|
notifyCallback?.(error, null);
|
|
169
177
|
},
|
|
178
|
+
emitDisconnect() {
|
|
179
|
+
disconnectCallback?.();
|
|
180
|
+
},
|
|
170
181
|
};
|
|
171
182
|
};
|
|
172
183
|
|
|
@@ -250,6 +261,23 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
250
261
|
await rejection;
|
|
251
262
|
});
|
|
252
263
|
|
|
264
|
+
test('emits one disconnect event when the physical callback races manual cleanup', async () => {
|
|
265
|
+
const harness = createHarness();
|
|
266
|
+
const disconnectListener = jest.fn();
|
|
267
|
+
harness.emitter.on(TRANSPORT_EVENT.DEVICE_DISCONNECT, disconnectListener);
|
|
268
|
+
|
|
269
|
+
await harness.transport.acquire({ uuid: harness.uuid });
|
|
270
|
+
harness.emitDisconnect();
|
|
271
|
+
await harness.transport.disconnect(harness.uuid);
|
|
272
|
+
|
|
273
|
+
expect(disconnectListener).toHaveBeenCalledTimes(1);
|
|
274
|
+
expect(disconnectListener).toHaveBeenCalledWith({
|
|
275
|
+
name: 'OneKey Pro 2',
|
|
276
|
+
id: harness.uuid,
|
|
277
|
+
connectId: harness.uuid,
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
253
281
|
test('chunks large frames and retries only transient GATT congestion', async () => {
|
|
254
282
|
const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
|
|
255
283
|
const congested = { status: 143, message: 'GATT_CONGESTED' };
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import transport, {
|
|
|
18
18
|
type ProtocolV2CallContext,
|
|
19
19
|
ProtocolV2FrameAssembler,
|
|
20
20
|
ProtocolV2LinkManager,
|
|
21
|
+
TRANSPORT_EVENT,
|
|
21
22
|
type TransportCallOptions,
|
|
22
23
|
probeProtocolV2 as probeProtocolV2Helper,
|
|
23
24
|
} from '@onekeyfe/hd-transport';
|
|
@@ -245,6 +246,8 @@ export default class ReactNativeBleTransport {
|
|
|
245
246
|
|
|
246
247
|
_messagesV2: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
247
248
|
|
|
249
|
+
private protocolV2SchemaConfiguration: string | undefined;
|
|
250
|
+
|
|
248
251
|
name = 'ReactNativeBleTransport';
|
|
249
252
|
|
|
250
253
|
configured = false;
|
|
@@ -293,6 +296,8 @@ export default class ReactNativeBleTransport {
|
|
|
293
296
|
|
|
294
297
|
private monitorTokens: Map<string, number> = new Map();
|
|
295
298
|
|
|
299
|
+
private disconnectEventTokens: Map<string, number> = new Map();
|
|
300
|
+
|
|
296
301
|
private nextMonitorToken = 1;
|
|
297
302
|
|
|
298
303
|
constructor(options: TransportOptions) {
|
|
@@ -311,10 +316,19 @@ export default class ReactNativeBleTransport {
|
|
|
311
316
|
}
|
|
312
317
|
|
|
313
318
|
configureProtocolV2(signedData: any) {
|
|
319
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
320
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
314
325
|
this._messagesV2 = parseConfigure(signedData);
|
|
315
|
-
this.
|
|
316
|
-
|
|
317
|
-
.
|
|
326
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
327
|
+
if (isReconfiguration) {
|
|
328
|
+
this.protocolV2Links
|
|
329
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
330
|
+
.catch(error => Log?.debug('Protocol V2 schema link cleanup failed:', error));
|
|
331
|
+
}
|
|
318
332
|
}
|
|
319
333
|
|
|
320
334
|
listen() {
|
|
@@ -428,6 +442,7 @@ export default class ReactNativeBleTransport {
|
|
|
428
442
|
|
|
429
443
|
attachDisconnectSubscription(transport: BleTransport, device: Device, uuid: string) {
|
|
430
444
|
transport.disconnectSubscription?.remove();
|
|
445
|
+
const { monitorToken } = transport;
|
|
431
446
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
432
447
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
433
448
|
Log?.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
@@ -437,14 +452,14 @@ export default class ReactNativeBleTransport {
|
|
|
437
452
|
Log?.debug('device disconnect ignored for stale transport: ', device?.id);
|
|
438
453
|
return;
|
|
439
454
|
}
|
|
455
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) {
|
|
456
|
+
Log?.debug('device disconnect ignored for stale generation: ', device?.id);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
440
459
|
|
|
441
460
|
try {
|
|
442
461
|
Log?.debug('device disconnect: ', device?.id);
|
|
443
|
-
this.
|
|
444
|
-
name: device?.name,
|
|
445
|
-
id: device?.id,
|
|
446
|
-
connectId: device?.id,
|
|
447
|
-
});
|
|
462
|
+
this.emitDeviceDisconnect(uuid, device?.name, monitorToken);
|
|
448
463
|
if (this.runPromise) {
|
|
449
464
|
const error = ERRORS.TypedError(HardwareErrorCode.BleConnectedError);
|
|
450
465
|
this.runPromise.reject(error);
|
|
@@ -458,6 +473,22 @@ export default class ReactNativeBleTransport {
|
|
|
458
473
|
});
|
|
459
474
|
}
|
|
460
475
|
|
|
476
|
+
private emitDeviceDisconnect(uuid: string, name: string | null | undefined, token?: number) {
|
|
477
|
+
if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (this.monitorTokens.get(uuid) !== token) {
|
|
481
|
+
Log?.debug('device disconnect event ignored for stale generation: ', uuid);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
this.disconnectEventTokens.set(uuid, token);
|
|
485
|
+
this.emitter?.emit(TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
486
|
+
name,
|
|
487
|
+
id: uuid,
|
|
488
|
+
connectId: uuid,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
461
492
|
async reconnectFirmwareUploadTransport(uuid: string, transport: BleTransport) {
|
|
462
493
|
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
463
494
|
try {
|
|
@@ -800,12 +831,6 @@ export default class ReactNativeBleTransport {
|
|
|
800
831
|
|
|
801
832
|
const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
802
833
|
|
|
803
|
-
this.emitter?.emit('device-connect', {
|
|
804
|
-
name: device.name,
|
|
805
|
-
id: device.id,
|
|
806
|
-
connectId: device.id,
|
|
807
|
-
});
|
|
808
|
-
|
|
809
834
|
this.attachDisconnectSubscription(transport, device, uuid);
|
|
810
835
|
|
|
811
836
|
return { uuid, protocolType };
|
|
@@ -1262,6 +1287,7 @@ export default class ReactNativeBleTransport {
|
|
|
1262
1287
|
async disconnect(session: string) {
|
|
1263
1288
|
await this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1264
1289
|
const transport = transportCache[session];
|
|
1290
|
+
const monitorToken = transport?.monitorToken ?? this.monitorTokens.get(session);
|
|
1265
1291
|
|
|
1266
1292
|
// Clean up disconnect subscription first to prevent onDisconnected callback
|
|
1267
1293
|
// from being triggered when we cancel the connection below
|
|
@@ -1325,14 +1351,13 @@ export default class ReactNativeBleTransport {
|
|
|
1325
1351
|
|
|
1326
1352
|
// emit the disconnect event
|
|
1327
1353
|
try {
|
|
1328
|
-
this.
|
|
1329
|
-
name: transport?.device?.name,
|
|
1330
|
-
id: session,
|
|
1331
|
-
connectId: session,
|
|
1332
|
-
});
|
|
1354
|
+
this.emitDeviceDisconnect(session, transport?.device?.name, monitorToken);
|
|
1333
1355
|
} catch (e) {
|
|
1334
1356
|
Log?.error('resetSession: emit disconnect event error: ', e);
|
|
1335
1357
|
}
|
|
1358
|
+
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1359
|
+
this.monitorTokens.delete(session);
|
|
1360
|
+
}
|
|
1336
1361
|
// eslint-disable-next-line no-promise-executor-return
|
|
1337
1362
|
await new Promise<void>(resolve => setTimeout(() => resolve(), 100));
|
|
1338
1363
|
}
|