@onekeyfe/hd-transport-react-native 1.2.0-alpha.129 → 1.2.0-alpha.130
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 +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -5
- package/package.json +5 -5
- package/src/__tests__/protocolV2Link.test.ts +37 -0
- package/src/index.ts +41 -4
package/dist/index.d.ts
CHANGED
|
@@ -132,6 +132,8 @@ declare class ReactNativeBleTransport {
|
|
|
132
132
|
private androidHighPriorityDevices;
|
|
133
133
|
private androidPriorityResetTimers;
|
|
134
134
|
private nextMonitorToken;
|
|
135
|
+
/** Serializes transport lifecycle changes for the same physical device. */
|
|
136
|
+
private lifecycleOperations;
|
|
135
137
|
constructor(options: TransportOptions);
|
|
136
138
|
init(logger: any, emitter: EventEmitter): void;
|
|
137
139
|
configure(signedData: any): void;
|
|
@@ -153,14 +155,18 @@ declare class ReactNativeBleTransport {
|
|
|
153
155
|
uuid: string;
|
|
154
156
|
protocolType: ProtocolType;
|
|
155
157
|
}>;
|
|
158
|
+
private acquireUnlocked;
|
|
156
159
|
_monitorCharacteristic(characteristic: Characteristic, uuid: string, monitorToken: number, notifyTransactionId: string): Subscription;
|
|
157
160
|
release(uuid: string, onclose?: boolean): Promise<boolean>;
|
|
161
|
+
private releaseUnlocked;
|
|
158
162
|
private releaseNative;
|
|
159
163
|
post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
|
|
160
164
|
call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<transport.MessageFromOneKey>;
|
|
161
165
|
private callProtocolV1;
|
|
162
166
|
stop(): void;
|
|
163
167
|
disconnect(session: string): Promise<void>;
|
|
168
|
+
private disconnectUnlocked;
|
|
169
|
+
private runLifecycleOperation;
|
|
164
170
|
cancel(): void;
|
|
165
171
|
/** Run a native connect under the JS backstop budget. */
|
|
166
172
|
private connectWithTimeout;
|
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,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAChB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AA0BhC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAgBjE,KAAK,4BAA4B,GAAG,WAAW,CAAC;AAChD,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkCF,eAAO,MAAM,+BAA+B,UACnC,OAAO,KACb,4BAA4B,GAAG,IAsBjC,CAAC;AAcF,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAOlD,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAI3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;AAsCD,eAAO,MAAM,sBAAsB,QAA2C,CAAC;AAO/E,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAQhD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,eAAO,MAAM,2CAA2C,IAAI,CAAC;AAS7D,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAqE1D,MAAM,CAAC,OAAO,OAAO,uBAAuB;IAC1C,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IAEzC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,WAAW,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAErE,OAAO,CAAC,6BAA6B,CAAqB;IAE1D,IAAI,SAA6B;IAEjC,UAAU,UAAS;IAEnB,OAAO,UAAS;IAEhB,WAAW,SAA0B;IAErC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,kBAAkB,CAAuB;IAEjD,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,8BAA8B,cAAqB;IAGnD,OAAO,CAAC,cAAc,CAAwC;IAQ9D,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,kBAAkB,CAAkC;IAG5D,OAAO,CAAC,4BAA4B,CAAkC;IAEtE,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,uBAAuB,CAAkC;IAEjE,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,uBAAuB,CAAgD;IAE/E,OAAO,CAAC,eAAe,CAmBpB;IAEH,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,qBAAqB,CAAkC;IAE/D,OAAO,CAAC,iCAAiC,CAAuC;IAEhF,OAAO,CAAC,0BAA0B,CAA0B;IAE5D,OAAO,CAAC,0BAA0B,CAAyD;IAE3F,OAAO,CAAC,gBAAgB,CAAK;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAChB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AA0BhC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAgBjE,KAAK,4BAA4B,GAAG,WAAW,CAAC;AAChD,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkCF,eAAO,MAAM,+BAA+B,UACnC,OAAO,KACb,4BAA4B,GAAG,IAsBjC,CAAC;AAcF,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAOlD,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAI3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;AAsCD,eAAO,MAAM,sBAAsB,QAA2C,CAAC;AAO/E,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAQhD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,eAAO,MAAM,2CAA2C,IAAI,CAAC;AAS7D,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAqE1D,MAAM,CAAC,OAAO,OAAO,uBAAuB;IAC1C,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IAEzC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,WAAW,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAErE,OAAO,CAAC,6BAA6B,CAAqB;IAE1D,IAAI,SAA6B;IAEjC,UAAU,UAAS;IAEnB,OAAO,UAAS;IAEhB,WAAW,SAA0B;IAErC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,kBAAkB,CAAuB;IAEjD,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,8BAA8B,cAAqB;IAGnD,OAAO,CAAC,cAAc,CAAwC;IAQ9D,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,kBAAkB,CAAkC;IAG5D,OAAO,CAAC,4BAA4B,CAAkC;IAEtE,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,uBAAuB,CAAkC;IAEjE,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,uBAAuB,CAAgD;IAE/E,OAAO,CAAC,eAAe,CAmBpB;IAEH,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,qBAAqB,CAAkC;IAE/D,OAAO,CAAC,iCAAiC,CAAuC;IAEhF,OAAO,CAAC,0BAA0B,CAA0B;IAE5D,OAAO,CAAC,0BAA0B,CAAyD;IAE3F,OAAO,CAAC,gBAAgB,CAAK;IAG7B,OAAO,CAAC,mBAAmB,CAAyC;gBAExD,OAAO,EAAE,gBAAgB;IAIrC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IAKvC,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAgBnC,MAAM;IAIN,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;IAMjC,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmFjF,4BAA4B,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAgClF,OAAO,CAAC,oBAAoB;IAgBtB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY;IAsDtE,SAAS;YA0ID,0BAA0B;IAyElC,OAAO,CAAC,KAAK,EAAE,eAAe;;;;YAUtB,eAAe;IAkL7B,sBAAsB,CACpB,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,YAAY;IAsIT,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ;YAI7B,eAAe;YAKf,aAAa;IAmErB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAajE,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA6BlB,cAAc;IAyP5B,IAAI;IAIE,UAAU,CAAC,OAAO,EAAE,MAAM;YAIlB,kBAAkB;YAiFlB,qBAAqB;IAoBnC,MAAM;YAUQ,kBAAkB;YAkClB,iCAAiC;IAwC/C,OAAO,CAAC,wBAAwB;IAgChC,OAAO,CAAC,kBAAkB;YAcZ,cAAc;IA8C5B,OAAO,CAAC,kBAAkB;IA6B1B,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;YAIX,cAAc;YAsGd,iCAAiC;YAoDjC,eAAe;YAwBf,eAAe;IA0B7B,OAAO,CAAC,4BAA4B;IA2BpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,sBAAsB;YAShB,mBAAmB;YAiBnB,qBAAqB;YA2DrB,oBAAoB;YAgCpB,cAAc;YAqEd,iCAAiC;IAiB/C,OAAO,CAAC,8BAA8B;YAQxB,mCAAmC;IAsBjD,OAAO,CAAC,yCAAyC;YAanC,gCAAgC;IAoB9C,OAAO,CAAC,uBAAuB;IAkD/B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
|
package/dist/index.js
CHANGED
|
@@ -434,6 +434,7 @@ class ReactNativeBleTransport {
|
|
|
434
434
|
this.androidHighPriorityDevices = new Set();
|
|
435
435
|
this.androidPriorityResetTimers = new Map();
|
|
436
436
|
this.nextMonitorToken = 1;
|
|
437
|
+
this.lifecycleOperations = new Map();
|
|
437
438
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
438
439
|
}
|
|
439
440
|
init(logger, emitter) {
|
|
@@ -791,12 +792,18 @@ class ReactNativeBleTransport {
|
|
|
791
792
|
});
|
|
792
793
|
}
|
|
793
794
|
acquire(input) {
|
|
794
|
-
var _a, _b;
|
|
795
795
|
return __awaiter(this, void 0, void 0, function* () {
|
|
796
|
-
const { uuid
|
|
796
|
+
const { uuid } = input;
|
|
797
797
|
if (!uuid) {
|
|
798
798
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
799
799
|
}
|
|
800
|
+
return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
acquireUnlocked(input) {
|
|
804
|
+
var _a, _b;
|
|
805
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
806
|
+
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
800
807
|
const cachedTransport = transportCache[uuid];
|
|
801
808
|
if (cachedTransport) {
|
|
802
809
|
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
@@ -808,7 +815,7 @@ class ReactNativeBleTransport {
|
|
|
808
815
|
return { uuid, protocolType: cachedProtocol };
|
|
809
816
|
}
|
|
810
817
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
811
|
-
yield this.
|
|
818
|
+
yield this.releaseUnlocked(uuid, true);
|
|
812
819
|
}
|
|
813
820
|
let device = null;
|
|
814
821
|
if (forceCleanRunPromise && this.runPromise) {
|
|
@@ -909,7 +916,7 @@ class ReactNativeBleTransport {
|
|
|
909
916
|
const protocolHint = expectedProtocol
|
|
910
917
|
? undefined
|
|
911
918
|
: (_b = (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
912
|
-
yield this.
|
|
919
|
+
yield this.releaseUnlocked(uuid, true);
|
|
913
920
|
if (protocolHint) {
|
|
914
921
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
915
922
|
}
|
|
@@ -929,7 +936,7 @@ class ReactNativeBleTransport {
|
|
|
929
936
|
return { uuid, protocolType };
|
|
930
937
|
}
|
|
931
938
|
catch (error) {
|
|
932
|
-
yield this.
|
|
939
|
+
yield this.releaseUnlocked(uuid, true);
|
|
933
940
|
throw error;
|
|
934
941
|
}
|
|
935
942
|
});
|
|
@@ -1040,6 +1047,11 @@ class ReactNativeBleTransport {
|
|
|
1040
1047
|
return subscription;
|
|
1041
1048
|
}
|
|
1042
1049
|
release(uuid, onclose = false) {
|
|
1050
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1051
|
+
return this.runLifecycleOperation(uuid, () => this.releaseUnlocked(uuid, onclose));
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
releaseUnlocked(uuid, onclose = false) {
|
|
1043
1055
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1044
1056
|
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
1045
1057
|
return this.releaseNative(uuid, onclose);
|
|
@@ -1331,6 +1343,11 @@ class ReactNativeBleTransport {
|
|
|
1331
1343
|
this.stopped = true;
|
|
1332
1344
|
}
|
|
1333
1345
|
disconnect(session) {
|
|
1346
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1347
|
+
return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
disconnectUnlocked(session) {
|
|
1334
1351
|
var _a, _b, _c, _d, _e;
|
|
1335
1352
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1336
1353
|
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
@@ -1400,6 +1417,28 @@ class ReactNativeBleTransport {
|
|
|
1400
1417
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1401
1418
|
});
|
|
1402
1419
|
}
|
|
1420
|
+
runLifecycleOperation(uuid, operation) {
|
|
1421
|
+
var _a;
|
|
1422
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1423
|
+
const previousOperation = (_a = this.lifecycleOperations.get(uuid)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
1424
|
+
let completeOperation;
|
|
1425
|
+
const operationGate = new Promise(resolve => {
|
|
1426
|
+
completeOperation = resolve;
|
|
1427
|
+
});
|
|
1428
|
+
const operationTail = previousOperation.catch(() => undefined).then(() => operationGate);
|
|
1429
|
+
this.lifecycleOperations.set(uuid, operationTail);
|
|
1430
|
+
yield previousOperation.catch(() => undefined);
|
|
1431
|
+
try {
|
|
1432
|
+
return yield operation();
|
|
1433
|
+
}
|
|
1434
|
+
finally {
|
|
1435
|
+
completeOperation();
|
|
1436
|
+
if (this.lifecycleOperations.get(uuid) === operationTail) {
|
|
1437
|
+
this.lifecycleOperations.delete(uuid);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1403
1442
|
cancel() {
|
|
1404
1443
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1405
1444
|
if (this.runPromise) ;
|
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.130",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.130",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.130",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.130",
|
|
26
26
|
"@onekeyfe/react-native-ble-utils": "^0.1.6",
|
|
27
27
|
"react-native-ble-plx": "3.5.1"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "287003096bc4df3a5824f2bea77e50f7fdc20565"
|
|
30
30
|
}
|
|
@@ -420,6 +420,43 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
420
420
|
await transport.release(uuid, true);
|
|
421
421
|
});
|
|
422
422
|
|
|
423
|
+
test('waits for an in-flight release before reacquiring the same device', async () => {
|
|
424
|
+
const { transport, uuid } = createHarness();
|
|
425
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
426
|
+
const releaseGate = createDeferred<void>();
|
|
427
|
+
const releaseStarted = createDeferred<void>();
|
|
428
|
+
const { protocolV2Links } = transport as any;
|
|
429
|
+
const invalidateLink = protocolV2Links.invalidateLink.bind(protocolV2Links);
|
|
430
|
+
jest
|
|
431
|
+
.spyOn(protocolV2Links, 'invalidateLink')
|
|
432
|
+
.mockImplementationOnce(async (...args: unknown[]) => {
|
|
433
|
+
releaseStarted.resolve();
|
|
434
|
+
await releaseGate.promise;
|
|
435
|
+
return invalidateLink(...args);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const release = transport.release(uuid, true);
|
|
439
|
+
await releaseStarted.promise;
|
|
440
|
+
let reacquired = false;
|
|
441
|
+
const acquire = transport.acquire({ uuid, expectedProtocol: 'V2' }).then(result => {
|
|
442
|
+
reacquired = true;
|
|
443
|
+
return result;
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
await Promise.resolve();
|
|
447
|
+
expect(reacquired).toBe(false);
|
|
448
|
+
|
|
449
|
+
releaseGate.resolve();
|
|
450
|
+
await release;
|
|
451
|
+
await expect(acquire).resolves.toEqual({ uuid, protocolType: 'V2' });
|
|
452
|
+
await expect(transport.call(uuid, 'Ping', { message: 'after-release' })).resolves.toMatchObject(
|
|
453
|
+
{
|
|
454
|
+
type: 'Success',
|
|
455
|
+
message: { message: 'ok' },
|
|
456
|
+
}
|
|
457
|
+
);
|
|
458
|
+
});
|
|
459
|
+
|
|
423
460
|
test('falls back to the other active probe on iOS when protocol metadata is absent', async () => {
|
|
424
461
|
const { transport, uuid } = createHarness({ deviceName: 'OneKey' });
|
|
425
462
|
const probeProtocolV1 = jest
|
package/src/index.ts
CHANGED
|
@@ -422,6 +422,9 @@ export default class ReactNativeBleTransport {
|
|
|
422
422
|
|
|
423
423
|
private nextMonitorToken = 1;
|
|
424
424
|
|
|
425
|
+
/** Serializes transport lifecycle changes for the same physical device. */
|
|
426
|
+
private lifecycleOperations: Map<string, Promise<void>> = new Map();
|
|
427
|
+
|
|
425
428
|
constructor(options: TransportOptions) {
|
|
426
429
|
this.scanTimeout = options.scanTimeout ?? DEVICE_SCAN_TIMEOUT_MS;
|
|
427
430
|
}
|
|
@@ -860,12 +863,18 @@ export default class ReactNativeBleTransport {
|
|
|
860
863
|
}
|
|
861
864
|
|
|
862
865
|
async acquire(input: BleAcquireInput) {
|
|
863
|
-
const { uuid
|
|
866
|
+
const { uuid } = input;
|
|
864
867
|
|
|
865
868
|
if (!uuid) {
|
|
866
869
|
throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
|
|
867
870
|
}
|
|
868
871
|
|
|
872
|
+
return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
private async acquireUnlocked(input: BleAcquireInput) {
|
|
876
|
+
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
877
|
+
|
|
869
878
|
const cachedTransport = transportCache[uuid];
|
|
870
879
|
if (cachedTransport) {
|
|
871
880
|
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
@@ -884,7 +893,7 @@ export default class ReactNativeBleTransport {
|
|
|
884
893
|
* connection, clean it up before creating a new transport instance.
|
|
885
894
|
*/
|
|
886
895
|
Log?.debug('transport not reusable, will release: ', uuid);
|
|
887
|
-
await this.
|
|
896
|
+
await this.releaseUnlocked(uuid, true);
|
|
888
897
|
}
|
|
889
898
|
|
|
890
899
|
let device: Device | null = null;
|
|
@@ -1010,7 +1019,7 @@ export default class ReactNativeBleTransport {
|
|
|
1010
1019
|
inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
1011
1020
|
|
|
1012
1021
|
// release transport before new transport instance
|
|
1013
|
-
await this.
|
|
1022
|
+
await this.releaseUnlocked(uuid, true);
|
|
1014
1023
|
if (protocolHint) {
|
|
1015
1024
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
1016
1025
|
}
|
|
@@ -1036,7 +1045,7 @@ export default class ReactNativeBleTransport {
|
|
|
1036
1045
|
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
1037
1046
|
return { uuid, protocolType };
|
|
1038
1047
|
} catch (error) {
|
|
1039
|
-
await this.
|
|
1048
|
+
await this.releaseUnlocked(uuid, true);
|
|
1040
1049
|
throw error;
|
|
1041
1050
|
}
|
|
1042
1051
|
}
|
|
@@ -1181,6 +1190,10 @@ export default class ReactNativeBleTransport {
|
|
|
1181
1190
|
}
|
|
1182
1191
|
|
|
1183
1192
|
async release(uuid: string, onclose = false) {
|
|
1193
|
+
return this.runLifecycleOperation(uuid, () => this.releaseUnlocked(uuid, onclose));
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
private async releaseUnlocked(uuid: string, onclose = false) {
|
|
1184
1197
|
await this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
1185
1198
|
return this.releaseNative(uuid, onclose);
|
|
1186
1199
|
}
|
|
@@ -1552,6 +1565,10 @@ export default class ReactNativeBleTransport {
|
|
|
1552
1565
|
}
|
|
1553
1566
|
|
|
1554
1567
|
async disconnect(session: string) {
|
|
1568
|
+
return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
private async disconnectUnlocked(session: string) {
|
|
1555
1572
|
await this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1556
1573
|
const transport = transportCache[session];
|
|
1557
1574
|
const monitorToken = transport?.monitorToken ?? this.monitorTokens.get(session);
|
|
@@ -1632,6 +1649,26 @@ export default class ReactNativeBleTransport {
|
|
|
1632
1649
|
await new Promise<void>(resolve => setTimeout(() => resolve(), 100));
|
|
1633
1650
|
}
|
|
1634
1651
|
|
|
1652
|
+
private async runLifecycleOperation<T>(uuid: string, operation: () => Promise<T>): Promise<T> {
|
|
1653
|
+
const previousOperation = this.lifecycleOperations.get(uuid) ?? Promise.resolve();
|
|
1654
|
+
let completeOperation!: () => void;
|
|
1655
|
+
const operationGate = new Promise<void>(resolve => {
|
|
1656
|
+
completeOperation = resolve;
|
|
1657
|
+
});
|
|
1658
|
+
const operationTail = previousOperation.catch(() => undefined).then(() => operationGate);
|
|
1659
|
+
this.lifecycleOperations.set(uuid, operationTail);
|
|
1660
|
+
|
|
1661
|
+
await previousOperation.catch(() => undefined);
|
|
1662
|
+
try {
|
|
1663
|
+
return await operation();
|
|
1664
|
+
} finally {
|
|
1665
|
+
completeOperation();
|
|
1666
|
+
if (this.lifecycleOperations.get(uuid) === operationTail) {
|
|
1667
|
+
this.lifecycleOperations.delete(uuid);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1635
1672
|
cancel() {
|
|
1636
1673
|
Log?.debug('transport-react-native transport cancel');
|
|
1637
1674
|
if (this.runPromise) {
|