@onekeyfe/hd-transport-react-native 1.2.0-alpha.8 → 1.2.0-alpha.9

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 CHANGED
@@ -69,8 +69,7 @@ declare class ReactNativeBleTransport {
69
69
  private protocolV2Assemblers;
70
70
  private protocolV2FrameQueues;
71
71
  private protocolV2FramePromises;
72
- private activeProtocolV2Call;
73
- private nextProtocolV2CallToken;
72
+ private protocolV2Links;
74
73
  private monitorTokens;
75
74
  private nextMonitorToken;
76
75
  constructor(options: TransportOptions);
@@ -108,10 +107,11 @@ declare class ReactNativeBleTransport {
108
107
  private resolveProtocolV2Frame;
109
108
  private rejectAllProtocolV2Frames;
110
109
  private resetProtocolV2Frames;
111
- private isActiveProtocolV2Call;
110
+ private rejectProtocolV2Frames;
112
111
  private readProtocolV2Frame;
113
112
  private writeProtocolV2Frame;
114
113
  private callProtocolV2;
114
+ private createProtocolV2Adapter;
115
115
  getProtocolType(path: string): ProtocolType | undefined;
116
116
  }
117
117
 
@@ -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,EAGzB,KAAK,YAAY,EAGjB,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;AAmBhC,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;AAkBjE,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkDF,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC,CAAC;AAqBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QA0B5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;;;;;EAErC;AA4BD,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;AA2D1D,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,IAAI,SAA6B;IAEjC,UAAU,UAAS;IAEnB,OAAO,UAAS;IAEhB,WAAW,SAA0B;IAErC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,8BAA8B,cAAqB;IAGnD,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,uBAAuB,CAAgD;IAE/E,OAAO,CAAC,oBAAoB,CAAgD;IAE5E,OAAO,CAAC,uBAAuB,CAAK;IAEpC,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,gBAAgB,CAAK;gBAEjB,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;IAKnC,MAAM;IAIN,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;IAMjC,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmGjF,4BAA4B,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAgC5E,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY;IAuDtE,SAAS;IAkIT,OAAO,CAAC,KAAK,EAAE,eAAe;;;;IAkLpC,sBAAsB,CACpB,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,YAAY;IA4GT,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ;IAiErC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjE,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YAoDlB,cAAc;IA+M5B,IAAI;IAIE,UAAU,CAAC,OAAO,EAAE,MAAM;IAiFhC,MAAM;IAQN,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;YAMZ,cAAc;YA+Cd,iCAAiC;YAmDjC,eAAe;YAgBf,eAAe;IAwB7B,OAAO,CAAC,4BAA4B;IAwBpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,sBAAsB;YAIhB,mBAAmB;YAiBnB,oBAAoB;YA6CpB,cAAc;IAyG5B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -414,8 +414,27 @@ class ReactNativeBleTransport {
414
414
  this.protocolV2Assemblers = new Map();
415
415
  this.protocolV2FrameQueues = new Map();
416
416
  this.protocolV2FramePromises = new Map();
417
- this.activeProtocolV2Call = null;
418
- this.nextProtocolV2CallToken = 1;
417
+ this.protocolV2Links = new transport.ProtocolV2LinkManager({
418
+ getSchemas: () => {
419
+ if (!this._messages || !this._messagesV2) {
420
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
421
+ }
422
+ return {
423
+ protocolV1: this._messages,
424
+ protocolV2: this._messagesV2,
425
+ };
426
+ },
427
+ classifyError: () => 'link-fatal',
428
+ onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
429
+ var _b;
430
+ (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
431
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
432
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
433
+ if (reason.startsWith('Protocol V2 link-fatal error:')) {
434
+ yield this.release(uuid, true);
435
+ }
436
+ }),
437
+ });
419
438
  this.monitorTokens = new Map();
420
439
  this.nextMonitorToken = 1;
421
440
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
@@ -431,6 +450,9 @@ class ReactNativeBleTransport {
431
450
  }
432
451
  configureProtocolV2(signedData) {
433
452
  this._messagesV2 = parseConfigure(signedData);
453
+ this.protocolV2Links
454
+ .invalidateAllLinks('Protocol V2 schema reconfigured')
455
+ .catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
434
456
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
435
457
  }
436
458
  listen() {
@@ -729,7 +751,6 @@ class ReactNativeBleTransport {
729
751
  this.runPromise.reject(error);
730
752
  this.rejectAllProtocolV2Frames(error);
731
753
  this.runPromise = null;
732
- this.activeProtocolV2Call = null;
733
754
  Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
734
755
  }
735
756
  const blePlxManager = yield this.getPlxManager();
@@ -854,7 +875,7 @@ class ReactNativeBleTransport {
854
875
  let bufferLength = 0;
855
876
  let buffer$1 = [];
856
877
  const subscription = characteristic.monitor((error, c) => {
857
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
878
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
858
879
  const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
859
880
  if (error) {
860
881
  Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
@@ -866,19 +887,37 @@ class ReactNativeBleTransport {
866
887
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
867
888
  return;
868
889
  }
869
- if (this.runPromise) {
870
- let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
890
+ if (this.deviceProtocol.get(uuid) === 'V2') {
891
+ let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
871
892
  if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
872
- ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
893
+ errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
873
894
  }
874
- if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
875
- ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
895
+ else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
896
+ errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
876
897
  }
877
- if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
898
+ else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
878
899
  ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
879
900
  ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
880
901
  ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
881
902
  ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
903
+ errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
904
+ }
905
+ this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
906
+ return;
907
+ }
908
+ if (this.runPromise) {
909
+ let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
910
+ if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
911
+ ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
912
+ }
913
+ if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
914
+ ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
915
+ }
916
+ if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
917
+ ((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
918
+ ((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
919
+ ((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
920
+ ((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
882
921
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
883
922
  this.runPromise.reject(notifyError);
884
923
  this.rejectAllProtocolV2Frames(notifyError);
@@ -907,7 +946,7 @@ class ReactNativeBleTransport {
907
946
  return;
908
947
  }
909
948
  if (protocol === 'V2') {
910
- this.handleProtocolV2Notification(uuid, new Uint8Array(data));
949
+ this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
911
950
  return;
912
951
  }
913
952
  if (isHeaderChunk(data)) {
@@ -921,28 +960,32 @@ class ReactNativeBleTransport {
921
960
  const value = buffer.Buffer.from(buffer$1);
922
961
  bufferLength = 0;
923
962
  buffer$1 = [];
924
- (_h = this.runPromise) === null || _h === void 0 ? void 0 : _h.resolve(value.toString('hex'));
963
+ (_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
925
964
  }
926
965
  }
927
966
  catch (error) {
928
967
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
929
968
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
930
- (_j = this.runPromise) === null || _j === void 0 ? void 0 : _j.reject(notifyError);
931
- this.rejectAllProtocolV2Frames(notifyError);
969
+ if (this.deviceProtocol.get(uuid) === 'V2') {
970
+ this.rejectProtocolV2Frames(uuid, notifyError);
971
+ }
972
+ else {
973
+ (_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
974
+ }
932
975
  }
933
976
  }, notifyTransactionId);
934
977
  return subscription;
935
978
  }
936
979
  release(uuid, onclose = false) {
937
- var _a, _b, _c, _d, _e, _f, _g, _h;
980
+ var _a, _b, _c, _d, _e, _f, _g;
938
981
  return __awaiter(this, void 0, void 0, function* () {
939
982
  const transport = transportCache[uuid];
983
+ yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
940
984
  if (this.runPromise) {
941
985
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
942
986
  this.runPromise.reject(error);
943
987
  this.runPromise = null;
944
988
  this.rejectAllProtocolV2Frames(error);
945
- this.activeProtocolV2Call = null;
946
989
  }
947
990
  else {
948
991
  this.resetProtocolV2Frames(uuid);
@@ -950,9 +993,6 @@ class ReactNativeBleTransport {
950
993
  if (reactNative.Platform.OS === 'android' && !onclose && transport) {
951
994
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
952
995
  this.resetProtocolV2Frames(uuid);
953
- if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
954
- this.activeProtocolV2Call = null;
955
- }
956
996
  return Promise.resolve(true);
957
997
  }
958
998
  if (transport) {
@@ -960,14 +1000,14 @@ class ReactNativeBleTransport {
960
1000
  this.monitorTokens.delete(uuid);
961
1001
  }
962
1002
  Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
963
- (_c = transport.disconnectSubscription) === null || _c === void 0 ? void 0 : _c.remove();
1003
+ (_b = transport.disconnectSubscription) === null || _b === void 0 ? void 0 : _b.remove();
964
1004
  transport.disconnectSubscription = undefined;
965
- Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_d = transport.notifyCharacteristic) === null || _d === void 0 ? void 0 : _d.uuid);
966
- (_e = transport.notifySubscription) === null || _e === void 0 ? void 0 : _e.remove();
1005
+ Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_c = transport.notifyCharacteristic) === null || _c === void 0 ? void 0 : _c.uuid);
1006
+ (_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
967
1007
  transport.notifySubscription = undefined;
968
1008
  if (transport.notifyTransactionId) {
969
1009
  try {
970
- yield ((_f = this.blePlxManager) === null || _f === void 0 ? void 0 : _f.cancelTransaction(transport.notifyTransactionId));
1010
+ yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
971
1011
  }
972
1012
  catch (e) {
973
1013
  Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel notify transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
@@ -976,12 +1016,11 @@ class ReactNativeBleTransport {
976
1016
  delete transportCache[uuid];
977
1017
  }
978
1018
  this.deviceProtocol.delete(uuid);
979
- this.deviceProtocolHints.delete(uuid);
980
- (_g = this.protocolV2Assemblers.get(uuid)) === null || _g === void 0 ? void 0 : _g.reset();
1019
+ (_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
981
1020
  this.protocolV2Assemblers.delete(uuid);
982
1021
  this.resetProtocolV2Frames(uuid);
983
1022
  try {
984
- yield ((_h = this.blePlxManager) === null || _h === void 0 ? void 0 : _h.cancelTransaction(uuid));
1023
+ yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
985
1024
  }
986
1025
  catch (e) {
987
1026
  Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
@@ -1002,11 +1041,6 @@ class ReactNativeBleTransport {
1002
1041
  if (this._messages == null) {
1003
1042
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1004
1043
  }
1005
- const forceRun = name === 'Initialize' || name === 'Cancel';
1006
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
1007
- if (this.runPromise && !forceRun) {
1008
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1009
- }
1010
1044
  const protocol = this.getProtocolType(uuid);
1011
1045
  if (!protocol) {
1012
1046
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
@@ -1026,6 +1060,11 @@ class ReactNativeBleTransport {
1026
1060
  if (protocol === 'V2') {
1027
1061
  return this.callProtocolV2(uuid, name, data, options);
1028
1062
  }
1063
+ const forceRun = name === 'Initialize' || name === 'Cancel';
1064
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
1065
+ if (this.runPromise && !forceRun) {
1066
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1067
+ }
1029
1068
  return this.callProtocolV1(uuid, name, data, options);
1030
1069
  });
1031
1070
  }
@@ -1216,9 +1255,10 @@ class ReactNativeBleTransport {
1216
1255
  this.stopped = true;
1217
1256
  }
1218
1257
  disconnect(session) {
1219
- var _a, _b, _c, _d, _e, _f;
1258
+ var _a, _b, _c, _d, _e;
1220
1259
  return __awaiter(this, void 0, void 0, function* () {
1221
1260
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport resetSession: ', session);
1261
+ yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
1222
1262
  const transport = transportCache[session];
1223
1263
  if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
1224
1264
  try {
@@ -1269,12 +1309,9 @@ class ReactNativeBleTransport {
1269
1309
  this.deviceProtocolHints.delete(session);
1270
1310
  this.protocolV2Assemblers.delete(session);
1271
1311
  this.resetProtocolV2Frames(session);
1272
- if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
1273
- this.activeProtocolV2Call = null;
1274
- }
1275
1312
  try {
1276
- (_e = this.emitter) === null || _e === void 0 ? void 0 : _e.emit('device-disconnect', {
1277
- name: (_f = transport === null || transport === void 0 ? void 0 : transport.device) === null || _f === void 0 ? void 0 : _f.name,
1313
+ (_d = this.emitter) === null || _d === void 0 ? void 0 : _d.emit('device-disconnect', {
1314
+ name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
1278
1315
  id: session,
1279
1316
  connectId: session,
1280
1317
  });
@@ -1341,14 +1378,12 @@ class ReactNativeBleTransport {
1341
1378
  });
1342
1379
  }
1343
1380
  resetProbeStateAfterProtocolProbe(uuid, protocol) {
1344
- var _a, _b, _c, _d;
1381
+ var _a, _b, _c;
1345
1382
  return __awaiter(this, void 0, void 0, function* () {
1346
1383
  const transport = transportCache[uuid];
1384
+ yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
1347
1385
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1348
1386
  this.resetProtocolV2Frames(uuid);
1349
- if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
1350
- this.activeProtocolV2Call = null;
1351
- }
1352
1387
  if (this.runPromise) {
1353
1388
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1354
1389
  this.runPromise.reject(error);
@@ -1360,11 +1395,11 @@ class ReactNativeBleTransport {
1360
1395
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
1361
1396
  this.monitorTokens.delete(uuid);
1362
1397
  }
1363
- (_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
1398
+ (_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
1364
1399
  transport.notifySubscription = undefined;
1365
1400
  if (previousNotifyTransactionId) {
1366
1401
  try {
1367
- yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelTransaction(previousNotifyTransactionId));
1402
+ yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(previousNotifyTransactionId));
1368
1403
  }
1369
1404
  catch (error) {
1370
1405
  Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] cancel notify after Protocol ${protocol} probe failed:`, (error === null || error === void 0 ? void 0 : error.message) || error);
@@ -1426,14 +1461,10 @@ class ReactNativeBleTransport {
1426
1461
  return detected;
1427
1462
  });
1428
1463
  }
1429
- handleProtocolV2Notification(uuid, data) {
1430
- var _a, _b, _c;
1464
+ handleProtocolV2Notification(uuid, monitorToken, data) {
1431
1465
  try {
1432
- if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== uuid) {
1433
- (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
1434
- this.resetProtocolV2Frames(uuid);
1466
+ if (this.monitorTokens.get(uuid) !== monitorToken)
1435
1467
  return;
1436
- }
1437
1468
  if (data.length === 0)
1438
1469
  return;
1439
1470
  const assembler = this.protocolV2Assemblers.get(uuid);
@@ -1446,8 +1477,10 @@ class ReactNativeBleTransport {
1446
1477
  catch (error) {
1447
1478
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
1448
1479
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1449
- (_c = this.runPromise) === null || _c === void 0 ? void 0 : _c.reject(notifyError);
1450
- this.rejectAllProtocolV2Frames(notifyError);
1480
+ this.rejectProtocolV2Frames(uuid, notifyError);
1481
+ this.protocolV2Links
1482
+ .invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
1483
+ .catch(invalidateError => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notify cleanup failed:', invalidateError));
1451
1484
  }
1452
1485
  }
1453
1486
  getProtocolV2FrameQueue(uuid) {
@@ -1478,9 +1511,13 @@ class ReactNativeBleTransport {
1478
1511
  this.protocolV2FrameQueues.delete(uuid);
1479
1512
  this.protocolV2FramePromises.delete(uuid);
1480
1513
  }
1481
- isActiveProtocolV2Call(uuid, token) {
1482
- var _a;
1483
- return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
1514
+ rejectProtocolV2Frames(uuid, error) {
1515
+ this.protocolV2FrameQueues.delete(uuid);
1516
+ const framePromise = this.protocolV2FramePromises.get(uuid);
1517
+ if (framePromise) {
1518
+ this.protocolV2FramePromises.delete(uuid);
1519
+ framePromise.reject(error);
1520
+ }
1484
1521
  }
1485
1522
  readProtocolV2Frame(uuid) {
1486
1523
  return __awaiter(this, void 0, void 0, function* () {
@@ -1535,32 +1572,12 @@ class ReactNativeBleTransport {
1535
1572
  });
1536
1573
  }
1537
1574
  callProtocolV2(uuid, name, data, options) {
1538
- var _a, _b, _c, _d;
1575
+ var _a;
1539
1576
  return __awaiter(this, void 0, void 0, function* () {
1540
1577
  if (!this._messages || !this._messagesV2) {
1541
1578
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1542
1579
  }
1543
- const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
1544
- if (this.runPromise) {
1545
- if (!forceRun) {
1546
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1547
- }
1548
- const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1549
- this.runPromise.reject(error);
1550
- this.rejectAllProtocolV2Frames(error);
1551
- this.runPromise = null;
1552
- this.activeProtocolV2Call = null;
1553
- }
1554
- const transport$1 = this.getCachedTransport(uuid);
1555
- const runPromise = hdShared.createDeferred();
1556
- runPromise.promise.catch(() => undefined);
1557
- this.runPromise = runPromise;
1558
- const callToken = this.nextProtocolV2CallToken++;
1559
- this.activeProtocolV2Call = { uuid, token: callToken };
1560
- (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1561
- this.resetProtocolV2Frames(uuid);
1562
- let completed = false;
1563
- const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
1580
+ const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : BLE_RESPONSE_TIMEOUT_MS });
1564
1581
  const highVolumeWrite = transport.LogBlockCommand.has(name);
1565
1582
  if (highVolumeWrite) {
1566
1583
  const tuning = getProtocolV2BleTuning();
@@ -1573,54 +1590,57 @@ class ReactNativeBleTransport {
1573
1590
  });
1574
1591
  }
1575
1592
  try {
1576
- const session = new transport.ProtocolV2Session({
1577
- schemas: {
1578
- protocolV1: this._messages,
1579
- protocolV2: this._messagesV2,
1580
- },
1581
- router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1582
- writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
1583
- yield this.writeProtocolV2Frame(transport$1, frame, {
1584
- highVolume: highVolumeWrite,
1585
- });
1586
- }),
1587
- readFrame: () => __awaiter(this, void 0, void 0, function* () {
1588
- const rxFrame = yield this.readProtocolV2Frame(uuid);
1589
- if (!(rxFrame instanceof Uint8Array)) {
1590
- throw new Error('Protocol V2 response is not Uint8Array');
1591
- }
1592
- return rxFrame;
1593
- }),
1594
- logger: Log,
1595
- logPrefix: 'ProtocolV2 RN-BLE',
1596
- createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
1597
- });
1598
- const result = yield session.call(name, data, callOptions);
1599
- completed = true;
1600
- return result;
1593
+ return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
1601
1594
  }
1602
1595
  catch (e) {
1603
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1604
- (_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
1605
- this.resetProtocolV2Frames(uuid);
1606
- }
1607
1596
  Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
1608
1597
  throw e;
1609
1598
  }
1610
- finally {
1611
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1612
- if (!completed) {
1613
- (_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
1614
- }
1615
- this.resetProtocolV2Frames(uuid);
1616
- this.activeProtocolV2Call = null;
1617
- }
1618
- if (this.runPromise === runPromise) {
1619
- this.runPromise = null;
1620
- }
1621
- }
1622
1599
  });
1623
1600
  }
1601
+ createProtocolV2Adapter(uuid) {
1602
+ var _a;
1603
+ const generation = (_a = this.monitorTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
1604
+ const assertCurrentGeneration = () => {
1605
+ if (this.monitorTokens.get(uuid) !== generation) {
1606
+ throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
1607
+ }
1608
+ };
1609
+ return {
1610
+ router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1611
+ maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
1612
+ generation,
1613
+ prepareCall: () => {
1614
+ var _a;
1615
+ assertCurrentGeneration();
1616
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1617
+ this.resetProtocolV2Frames(uuid);
1618
+ },
1619
+ writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
1620
+ assertCurrentGeneration();
1621
+ const currentTransport = this.getCachedTransport(uuid);
1622
+ yield this.writeProtocolV2Frame(currentTransport, frame, {
1623
+ highVolume: context.highVolume,
1624
+ });
1625
+ }),
1626
+ readFrame: () => __awaiter(this, void 0, void 0, function* () {
1627
+ assertCurrentGeneration();
1628
+ const rxFrame = yield this.readProtocolV2Frame(uuid);
1629
+ if (!(rxFrame instanceof Uint8Array)) {
1630
+ throw new Error('Protocol V2 response is not Uint8Array');
1631
+ }
1632
+ return rxFrame;
1633
+ }),
1634
+ reset: (reason) => {
1635
+ var _a;
1636
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1637
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
1638
+ },
1639
+ logger: Log,
1640
+ logPrefix: 'ProtocolV2 RN-BLE',
1641
+ createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
1642
+ };
1643
+ }
1624
1644
  getProtocolType(path) {
1625
1645
  return this.deviceProtocol.get(path);
1626
1646
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.0-alpha.8",
3
+ "version": "1.2.0-alpha.9",
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.8",
23
- "@onekeyfe/hd-shared": "1.2.0-alpha.8",
24
- "@onekeyfe/hd-transport": "1.2.0-alpha.8",
22
+ "@onekeyfe/hd-core": "1.2.0-alpha.9",
23
+ "@onekeyfe/hd-shared": "1.2.0-alpha.9",
24
+ "@onekeyfe/hd-transport": "1.2.0-alpha.9",
25
25
  "@onekeyfe/react-native-ble-utils": "^0.1.4",
26
26
  "react-native-ble-plx": "3.5.1"
27
27
  },
28
- "gitHead": "d2b1323e5ad9c373e72d4d092f35c9f274c1fd74"
28
+ "gitHead": "f90ef9921b742f68cce9f4e7a0425e45e8ae7ec9"
29
29
  }
@@ -0,0 +1,237 @@
1
+ import { EventEmitter } from 'events';
2
+ import transportPackage, {
3
+ PROTOCOL_V2_CHANNEL_BLE_UART,
4
+ ProtocolV2,
5
+ bytesToHex,
6
+ } from '@onekeyfe/hd-transport';
7
+ import { HardwareErrorCode } from '@onekeyfe/hd-shared';
8
+
9
+ import ReactNativeBleTransport from '../index';
10
+
11
+ jest.mock(
12
+ 'react-native',
13
+ () => ({
14
+ PermissionsAndroid: {},
15
+ Platform: { OS: 'ios' },
16
+ }),
17
+ { virtual: true }
18
+ );
19
+
20
+ jest.mock('react-native-ble-plx', () => ({
21
+ BleATTErrorCode: { UnlikelyError: 14 },
22
+ BleError: class BleError extends Error {},
23
+ BleErrorCode: {
24
+ DeviceAlreadyConnected: 203,
25
+ DeviceDisconnected: 205,
26
+ DeviceMTUChangeFailed: 206,
27
+ OperationCancelled: 2,
28
+ CharacteristicNotFound: 404,
29
+ },
30
+ BleManager: jest.fn(),
31
+ ScanMode: { LowLatency: 2 },
32
+ }));
33
+
34
+ jest.mock('../BleManager', () => ({
35
+ getConnectedDeviceIds: jest.fn(() => Promise.resolve([])),
36
+ onDeviceBondState: jest.fn(() => Promise.resolve()),
37
+ pairDevice: jest.fn(() => Promise.resolve({ bonded: true, bonding: false })),
38
+ }));
39
+
40
+ jest.mock('../subscribeBleOn', () => ({
41
+ subscribeBleOn: jest.fn(() => Promise.resolve()),
42
+ }));
43
+
44
+ const { parseConfigure } = transportPackage;
45
+
46
+ const protocolV1Schema = {
47
+ nested: {
48
+ Initialize: { fields: {} },
49
+ Success: {
50
+ fields: {
51
+ message: { type: 'string', id: 1 },
52
+ },
53
+ },
54
+ MessageType: {
55
+ values: {
56
+ MessageType_Initialize: 1,
57
+ MessageType_Success: 2,
58
+ },
59
+ },
60
+ },
61
+ };
62
+
63
+ const protocolV2Schema = {
64
+ nested: {
65
+ Ping: {
66
+ fields: {
67
+ message: { type: 'string', id: 1 },
68
+ },
69
+ },
70
+ FileWrite: { fields: {} },
71
+ Success: {
72
+ fields: {
73
+ message: { type: 'string', id: 1 },
74
+ },
75
+ },
76
+ MessageType: {
77
+ values: {
78
+ MessageType_Ping: 60206,
79
+ MessageType_Success: 60207,
80
+ MessageType_FileWrite: 60805,
81
+ },
82
+ },
83
+ },
84
+ };
85
+
86
+ const schemas = {
87
+ protocolV1: parseConfigure(protocolV1Schema),
88
+ protocolV2: parseConfigure(protocolV2Schema),
89
+ };
90
+
91
+ const createHarness = () => {
92
+ const uuid = 'rn-pro2-id';
93
+ const sentSeqs: number[] = [];
94
+ let shouldRespond = true;
95
+ let notifyCallback:
96
+ | ((
97
+ error: (Error & { reason?: string }) | null,
98
+ characteristic: { value: string } | null
99
+ ) => void)
100
+ | undefined;
101
+ const notifyCharacteristic = {
102
+ uuid: '0003',
103
+ deviceID: uuid,
104
+ isNotifiable: true,
105
+ monitor: jest.fn(callback => {
106
+ notifyCallback = callback;
107
+ return { remove: jest.fn() };
108
+ }),
109
+ };
110
+ const writeCharacteristic = {
111
+ uuid: '0002',
112
+ deviceID: uuid,
113
+ isWritableWithResponse: true,
114
+ isWritableWithoutResponse: true,
115
+ writeWithResponse: jest.fn((base64: string) => {
116
+ const frame = Buffer.from(base64, 'base64');
117
+ sentSeqs.push(frame[6]);
118
+ if (shouldRespond) {
119
+ const response = ProtocolV2.encodeFrame(
120
+ schemas,
121
+ 'Success',
122
+ { message: 'ok' },
123
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
124
+ );
125
+ notifyCallback?.(null, { value: Buffer.from(response).toString('base64') });
126
+ }
127
+ return Promise.resolve();
128
+ }),
129
+ writeWithoutResponse: jest.fn(async (base64: string) => {
130
+ await writeCharacteristic.writeWithResponse(base64);
131
+ }),
132
+ };
133
+ const device = {
134
+ id: uuid,
135
+ name: 'OneKey Pro 2',
136
+ localName: 'OneKey Pro 2',
137
+ serviceUUIDs: ['fffd'],
138
+ isConnected: jest.fn(() => Promise.resolve(true)),
139
+ onDisconnected: jest.fn(() => ({ remove: jest.fn() })),
140
+ };
141
+ const bleManager = {
142
+ devices: jest.fn(() => Promise.resolve([device])),
143
+ connectedDevices: jest.fn(() => Promise.resolve([])),
144
+ cancelTransaction: jest.fn(() => Promise.resolve()),
145
+ };
146
+ const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
147
+ transport.blePlxManager = bleManager;
148
+ transport.resolveCharacteristics = jest.fn(() =>
149
+ Promise.resolve({ writeCharacteristic, notifyCharacteristic })
150
+ );
151
+ transport.init({ debug: jest.fn(), error: jest.fn() }, new EventEmitter());
152
+ transport.configure(protocolV1Schema);
153
+ transport.configureProtocolV2(protocolV2Schema);
154
+
155
+ return {
156
+ transport,
157
+ uuid,
158
+ sentSeqs,
159
+ setShouldRespond(value: boolean) {
160
+ shouldRespond = value;
161
+ },
162
+ emitMonitorError(error: Error & { reason?: string }) {
163
+ notifyCallback?.(error, null);
164
+ },
165
+ };
166
+ };
167
+
168
+ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
169
+ test('keeps the Protocol V2 sequence across probe and the next call', async () => {
170
+ const { transport, uuid, sentSeqs } = createHarness();
171
+
172
+ await transport.acquire({ uuid });
173
+ await transport.call(uuid, 'Ping', { message: 'after-probe' });
174
+
175
+ expect(sentSeqs).toEqual([1, 2]);
176
+ expect(bytesToHex(new Uint8Array([sentSeqs[0], sentSeqs[1]]))).toBe('0102');
177
+ await transport.release(uuid, true);
178
+ });
179
+
180
+ test('rejects the active Protocol V2 reader when the current monitor errors', async () => {
181
+ const harness = createHarness();
182
+ const { transport, uuid, sentSeqs } = harness;
183
+ await transport.acquire({ uuid });
184
+ harness.setShouldRespond(false);
185
+
186
+ const call = transport.call(uuid, 'Ping', { message: 'wait-for-monitor' }, { timeoutMs: 50 });
187
+ while (sentSeqs.length < 2) {
188
+ await Promise.resolve();
189
+ }
190
+ await new Promise(resolve => {
191
+ setTimeout(resolve, 0);
192
+ });
193
+ harness.emitMonitorError(Object.assign(new Error('monitor failed'), { reason: 'link lost' }));
194
+
195
+ await expect(call).rejects.toMatchObject({
196
+ errorCode: HardwareErrorCode.BleCharacteristicNotifyError,
197
+ });
198
+ });
199
+
200
+ test('retains the sequence cursor when a new monitor generation is acquired', async () => {
201
+ const { transport, uuid, sentSeqs } = createHarness();
202
+
203
+ await transport.acquire({ uuid });
204
+ await transport.release(uuid, true);
205
+ await transport.acquire({ uuid });
206
+
207
+ expect(sentSeqs).toEqual([1, 2]);
208
+ await transport.release(uuid, true);
209
+ });
210
+
211
+ test('passes high-volume context to the persistent link adapter', async () => {
212
+ const { transport, uuid } = createHarness();
213
+ const writeSpy = jest.spyOn(transport as any, 'writeProtocolV2Frame');
214
+
215
+ await transport.acquire({ uuid });
216
+ await transport.call(uuid, 'FileWrite', {});
217
+
218
+ expect(writeSpy.mock.calls.map(([, , options]) => options?.highVolume)).toEqual([false, true]);
219
+ await transport.release(uuid, true);
220
+ });
221
+
222
+ test('rejects an active Protocol V2 reader when disconnect resets the link', async () => {
223
+ const harness = createHarness();
224
+ const { transport, uuid, sentSeqs } = harness;
225
+ await transport.acquire({ uuid });
226
+ harness.setShouldRespond(false);
227
+
228
+ const call = transport.call(uuid, 'Ping', { message: 'disconnect' }, { timeoutMs: 50 });
229
+ while (sentSeqs.length < 2) {
230
+ await Promise.resolve();
231
+ }
232
+
233
+ const rejection = expect(call).rejects.toThrow('React Native BLE transport disconnected');
234
+ await transport.disconnect(uuid);
235
+ await rejection;
236
+ });
237
+ });
package/src/index.ts CHANGED
@@ -12,10 +12,11 @@ import transport, {
12
12
  LogBlockCommand,
13
13
  type OneKeyDeviceInfoBase,
14
14
  PROTOCOL_V1_MESSAGE_HEADER_SIZE,
15
+ PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
15
16
  PROTOCOL_V2_CHANNEL_BLE_UART,
16
17
  type ProtocolType,
17
18
  ProtocolV2FrameAssembler,
18
- ProtocolV2Session,
19
+ ProtocolV2LinkManager,
19
20
  type TransportCallOptions,
20
21
  probeProtocolV2 as probeProtocolV2Helper,
21
22
  } from '@onekeyfe/hd-transport';
@@ -297,9 +298,26 @@ export default class ReactNativeBleTransport {
297
298
 
298
299
  private protocolV2FramePromises: Map<string, Deferred<Uint8Array>> = new Map();
299
300
 
300
- private activeProtocolV2Call: { uuid: string; token: number } | null = null;
301
-
302
- private nextProtocolV2CallToken = 1;
301
+ private protocolV2Links = new ProtocolV2LinkManager<string>({
302
+ getSchemas: () => {
303
+ if (!this._messages || !this._messagesV2) {
304
+ throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
305
+ }
306
+ return {
307
+ protocolV1: this._messages,
308
+ protocolV2: this._messagesV2,
309
+ };
310
+ },
311
+ classifyError: () => 'link-fatal',
312
+ onLinkInvalidated: async (uuid, reason) => {
313
+ this.protocolV2Assemblers.get(uuid)?.reset();
314
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
315
+ Log?.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
316
+ if (reason.startsWith('Protocol V2 link-fatal error:')) {
317
+ await this.release(uuid, true);
318
+ }
319
+ },
320
+ });
303
321
 
304
322
  private monitorTokens: Map<string, number> = new Map();
305
323
 
@@ -322,6 +340,9 @@ export default class ReactNativeBleTransport {
322
340
 
323
341
  configureProtocolV2(signedData: any) {
324
342
  this._messagesV2 = parseConfigure(signedData);
343
+ this.protocolV2Links
344
+ .invalidateAllLinks('Protocol V2 schema reconfigured')
345
+ .catch(error => Log?.debug('Protocol V2 schema link cleanup failed:', error));
325
346
  Log?.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
326
347
  }
327
348
 
@@ -686,7 +707,6 @@ export default class ReactNativeBleTransport {
686
707
  this.runPromise.reject(error);
687
708
  this.rejectAllProtocolV2Frames(error);
688
709
  this.runPromise = null;
689
- this.activeProtocolV2Call = null;
690
710
  Log?.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
691
711
  }
692
712
 
@@ -853,6 +873,29 @@ export default class ReactNativeBleTransport {
853
873
  Log?.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
854
874
  return;
855
875
  }
876
+ if (this.deviceProtocol.get(uuid) === 'V2') {
877
+ let errorCode:
878
+ | typeof HardwareErrorCode.BleDeviceBondError
879
+ | typeof HardwareErrorCode.BleCharacteristicNotifyError
880
+ | typeof HardwareErrorCode.BleCharacteristicNotifyChangeFailure
881
+ | typeof HardwareErrorCode.BleTimeoutError =
882
+ HardwareErrorCode.BleCharacteristicNotifyError;
883
+ if (error.reason?.includes('The connection has timed out unexpectedly')) {
884
+ errorCode = HardwareErrorCode.BleTimeoutError;
885
+ } else if (error.reason?.includes('Encryption is insufficient')) {
886
+ errorCode = HardwareErrorCode.BleDeviceBondError;
887
+ } else if (
888
+ error.reason?.includes('Cannot write client characteristic config descriptor') ||
889
+ error.reason?.includes('Cannot find client characteristic config descriptor') ||
890
+ error.reason?.includes('The handle is invalid') ||
891
+ error.reason?.includes('Writing is not permitted') ||
892
+ error.reason?.includes('notify change failed for device')
893
+ ) {
894
+ errorCode = HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
895
+ }
896
+ this.rejectProtocolV2Frames(uuid, ERRORS.TypedError(errorCode));
897
+ return;
898
+ }
856
899
  if (this.runPromise) {
857
900
  let ERROR:
858
901
  | typeof HardwareErrorCode.BleDeviceBondError
@@ -908,7 +951,7 @@ export default class ReactNativeBleTransport {
908
951
  return;
909
952
  }
910
953
  if (protocol === 'V2') {
911
- this.handleProtocolV2Notification(uuid, new Uint8Array(data));
954
+ this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
912
955
  return;
913
956
  }
914
957
  // console.log('[hd-transport-react-native] Received a packet, ', 'buffer: ', data);
@@ -934,8 +977,11 @@ export default class ReactNativeBleTransport {
934
977
  } catch (error) {
935
978
  Log?.debug('monitor data error: ', error);
936
979
  const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
937
- this.runPromise?.reject(notifyError);
938
- this.rejectAllProtocolV2Frames(notifyError);
980
+ if (this.deviceProtocol.get(uuid) === 'V2') {
981
+ this.rejectProtocolV2Frames(uuid, notifyError);
982
+ } else {
983
+ this.runPromise?.reject(notifyError);
984
+ }
939
985
  }
940
986
  }, notifyTransactionId);
941
987
 
@@ -944,12 +990,12 @@ export default class ReactNativeBleTransport {
944
990
 
945
991
  async release(uuid: string, onclose = false) {
946
992
  const transport = transportCache[uuid];
993
+ await this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
947
994
  if (this.runPromise) {
948
995
  const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
949
996
  this.runPromise.reject(error);
950
997
  this.runPromise = null;
951
998
  this.rejectAllProtocolV2Frames(error);
952
- this.activeProtocolV2Call = null;
953
999
  } else {
954
1000
  this.resetProtocolV2Frames(uuid);
955
1001
  }
@@ -957,9 +1003,6 @@ export default class ReactNativeBleTransport {
957
1003
  if (Platform.OS === 'android' && !onclose && transport) {
958
1004
  this.protocolV2Assemblers.get(uuid)?.reset();
959
1005
  this.resetProtocolV2Frames(uuid);
960
- if (this.activeProtocolV2Call?.uuid === uuid) {
961
- this.activeProtocolV2Call = null;
962
- }
963
1006
  return Promise.resolve(true);
964
1007
  }
965
1008
 
@@ -993,7 +1036,7 @@ export default class ReactNativeBleTransport {
993
1036
  }
994
1037
 
995
1038
  this.deviceProtocol.delete(uuid);
996
- this.deviceProtocolHints.delete(uuid);
1039
+ // 设备名称提示不依赖当前连接;保留它可让重连优先探测 V2。
997
1040
  this.protocolV2Assemblers.get(uuid)?.reset();
998
1041
  this.protocolV2Assemblers.delete(uuid);
999
1042
  this.resetProtocolV2Frames(uuid);
@@ -1025,13 +1068,6 @@ export default class ReactNativeBleTransport {
1025
1068
  throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
1026
1069
  }
1027
1070
 
1028
- const forceRun = name === 'Initialize' || name === 'Cancel';
1029
-
1030
- Log?.debug('transport-react-native call this.runPromise', this.runPromise);
1031
- if (this.runPromise && !forceRun) {
1032
- throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
1033
- }
1034
-
1035
1071
  const protocol = this.getProtocolType(uuid);
1036
1072
  if (!protocol) {
1037
1073
  throw ERRORS.TypedError(
@@ -1064,6 +1100,12 @@ export default class ReactNativeBleTransport {
1064
1100
  return this.callProtocolV2(uuid, name, data, options);
1065
1101
  }
1066
1102
 
1103
+ const forceRun = name === 'Initialize' || name === 'Cancel';
1104
+ Log?.debug('transport-react-native call this.runPromise', this.runPromise);
1105
+ if (this.runPromise && !forceRun) {
1106
+ throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
1107
+ }
1108
+
1067
1109
  return this.callProtocolV1(uuid, name, data, options);
1068
1110
  }
1069
1111
 
@@ -1280,6 +1322,7 @@ export default class ReactNativeBleTransport {
1280
1322
 
1281
1323
  async disconnect(session: string) {
1282
1324
  Log?.debug('transport-react-native transport resetSession: ', session);
1325
+ await this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
1283
1326
  const transport = transportCache[session];
1284
1327
 
1285
1328
  // Clean up disconnect subscription first to prevent onDisconnected callback
@@ -1341,9 +1384,6 @@ export default class ReactNativeBleTransport {
1341
1384
  this.deviceProtocolHints.delete(session);
1342
1385
  this.protocolV2Assemblers.delete(session);
1343
1386
  this.resetProtocolV2Frames(session);
1344
- if (this.activeProtocolV2Call?.uuid === session) {
1345
- this.activeProtocolV2Call = null;
1346
- }
1347
1387
 
1348
1388
  // emit the disconnect event
1349
1389
  try {
@@ -1444,11 +1484,12 @@ export default class ReactNativeBleTransport {
1444
1484
 
1445
1485
  private async resetProbeStateAfterProtocolProbe(uuid: string, protocol: ProtocolType) {
1446
1486
  const transport = transportCache[uuid];
1487
+ await this.protocolV2Links.invalidateLink(
1488
+ uuid,
1489
+ `Reset notify state after Protocol ${protocol} probe`
1490
+ );
1447
1491
  this.protocolV2Assemblers.get(uuid)?.reset();
1448
1492
  this.resetProtocolV2Frames(uuid);
1449
- if (this.activeProtocolV2Call?.uuid === uuid) {
1450
- this.activeProtocolV2Call = null;
1451
- }
1452
1493
  if (this.runPromise) {
1453
1494
  const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
1454
1495
  this.runPromise.reject(error);
@@ -1533,13 +1574,9 @@ export default class ReactNativeBleTransport {
1533
1574
  return detected;
1534
1575
  }
1535
1576
 
1536
- private handleProtocolV2Notification(uuid: string, data: Uint8Array) {
1577
+ private handleProtocolV2Notification(uuid: string, monitorToken: number, data: Uint8Array) {
1537
1578
  try {
1538
- if (!this.runPromise || this.activeProtocolV2Call?.uuid !== uuid) {
1539
- this.protocolV2Assemblers.get(uuid)?.reset();
1540
- this.resetProtocolV2Frames(uuid);
1541
- return;
1542
- }
1579
+ if (this.monitorTokens.get(uuid) !== monitorToken) return;
1543
1580
 
1544
1581
  if (data.length === 0) return;
1545
1582
 
@@ -1552,8 +1589,15 @@ export default class ReactNativeBleTransport {
1552
1589
  } catch (error) {
1553
1590
  Log?.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
1554
1591
  const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
1555
- this.runPromise?.reject(notifyError);
1556
- this.rejectAllProtocolV2Frames(notifyError);
1592
+ this.rejectProtocolV2Frames(uuid, notifyError);
1593
+ this.protocolV2Links
1594
+ .invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
1595
+ .catch(invalidateError =>
1596
+ Log?.debug(
1597
+ '[ReactNativeBleTransport] Protocol V2 notify cleanup failed:',
1598
+ invalidateError
1599
+ )
1600
+ );
1557
1601
  }
1558
1602
  }
1559
1603
 
@@ -1589,8 +1633,13 @@ export default class ReactNativeBleTransport {
1589
1633
  this.protocolV2FramePromises.delete(uuid);
1590
1634
  }
1591
1635
 
1592
- private isActiveProtocolV2Call(uuid: string, token: number) {
1593
- return this.activeProtocolV2Call?.uuid === uuid && this.activeProtocolV2Call.token === token;
1636
+ private rejectProtocolV2Frames(uuid: string, error: Error) {
1637
+ this.protocolV2FrameQueues.delete(uuid);
1638
+ const framePromise = this.protocolV2FramePromises.get(uuid);
1639
+ if (framePromise) {
1640
+ this.protocolV2FramePromises.delete(uuid);
1641
+ framePromise.reject(error);
1642
+ }
1594
1643
  }
1595
1644
 
1596
1645
  private async readProtocolV2Frame(uuid: string) {
@@ -1665,27 +1714,6 @@ export default class ReactNativeBleTransport {
1665
1714
  throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
1666
1715
  }
1667
1716
 
1668
- const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
1669
- if (this.runPromise) {
1670
- if (!forceRun) {
1671
- throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
1672
- }
1673
- const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
1674
- this.runPromise.reject(error);
1675
- this.rejectAllProtocolV2Frames(error);
1676
- this.runPromise = null;
1677
- this.activeProtocolV2Call = null;
1678
- }
1679
-
1680
- const transport = this.getCachedTransport(uuid);
1681
- const runPromise = createDeferred<Uint8Array>();
1682
- runPromise.promise.catch(() => undefined);
1683
- this.runPromise = runPromise;
1684
- const callToken = this.nextProtocolV2CallToken++;
1685
- this.activeProtocolV2Call = { uuid, token: callToken };
1686
- this.protocolV2Assemblers.get(uuid)?.reset();
1687
- this.resetProtocolV2Frames(uuid);
1688
- let completed = false;
1689
1717
  const callOptions = {
1690
1718
  ...options,
1691
1719
  timeoutMs: options?.timeoutMs ?? BLE_RESPONSE_TIMEOUT_MS,
@@ -1709,57 +1737,65 @@ export default class ReactNativeBleTransport {
1709
1737
  }
1710
1738
 
1711
1739
  try {
1712
- const session = new ProtocolV2Session({
1713
- schemas: {
1714
- protocolV1: this._messages,
1715
- protocolV2: this._messagesV2,
1716
- },
1717
- router: PROTOCOL_V2_CHANNEL_BLE_UART,
1718
- writeFrame: async (frame: Uint8Array) => {
1719
- await this.writeProtocolV2Frame(transport, frame, {
1720
- highVolume: highVolumeWrite,
1721
- });
1722
- },
1723
- readFrame: async () => {
1724
- const rxFrame = await this.readProtocolV2Frame(uuid);
1725
- if (!(rxFrame instanceof Uint8Array)) {
1726
- throw new Error('Protocol V2 response is not Uint8Array');
1727
- }
1728
- return rxFrame;
1729
- },
1730
- logger: Log,
1731
- logPrefix: 'ProtocolV2 RN-BLE',
1732
- createTimeoutError: (_messageName: string, timeout: number) =>
1733
- ERRORS.TypedError(
1734
- HardwareErrorCode.BleTimeoutError,
1735
- `BLE response timeout after ${timeout}ms for ${name}`
1736
- ),
1737
- });
1738
-
1739
- const result = await session.call(name, data, callOptions);
1740
- completed = true;
1741
- return result;
1740
+ return await this.protocolV2Links.call(
1741
+ uuid,
1742
+ () => this.createProtocolV2Adapter(uuid),
1743
+ name,
1744
+ data,
1745
+ callOptions
1746
+ );
1742
1747
  } catch (e) {
1743
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1744
- this.protocolV2Assemblers.get(uuid)?.reset();
1745
- this.resetProtocolV2Frames(uuid);
1746
- }
1747
1748
  Log?.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
1748
1749
  throw e;
1749
- } finally {
1750
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1751
- if (!completed) {
1752
- this.protocolV2Assemblers.get(uuid)?.reset();
1753
- }
1754
- this.resetProtocolV2Frames(uuid);
1755
- this.activeProtocolV2Call = null;
1756
- }
1757
- if (this.runPromise === runPromise) {
1758
- this.runPromise = null;
1759
- }
1760
1750
  }
1761
1751
  }
1762
1752
 
1753
+ private createProtocolV2Adapter(uuid: string) {
1754
+ const generation = this.monitorTokens.get(uuid) ?? 0;
1755
+ const assertCurrentGeneration = () => {
1756
+ if (this.monitorTokens.get(uuid) !== generation) {
1757
+ throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
1758
+ }
1759
+ };
1760
+
1761
+ return {
1762
+ router: PROTOCOL_V2_CHANNEL_BLE_UART,
1763
+ maxFrameBytes: PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
1764
+ generation,
1765
+ prepareCall: () => {
1766
+ assertCurrentGeneration();
1767
+ this.protocolV2Assemblers.get(uuid)?.reset();
1768
+ this.resetProtocolV2Frames(uuid);
1769
+ },
1770
+ writeFrame: async (frame: Uint8Array, context: { highVolume: boolean }) => {
1771
+ assertCurrentGeneration();
1772
+ const currentTransport = this.getCachedTransport(uuid);
1773
+ await this.writeProtocolV2Frame(currentTransport, frame, {
1774
+ highVolume: context.highVolume,
1775
+ });
1776
+ },
1777
+ readFrame: async () => {
1778
+ assertCurrentGeneration();
1779
+ const rxFrame = await this.readProtocolV2Frame(uuid);
1780
+ if (!(rxFrame instanceof Uint8Array)) {
1781
+ throw new Error('Protocol V2 response is not Uint8Array');
1782
+ }
1783
+ return rxFrame;
1784
+ },
1785
+ reset: (reason: string) => {
1786
+ this.protocolV2Assemblers.get(uuid)?.reset();
1787
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
1788
+ },
1789
+ logger: Log,
1790
+ logPrefix: 'ProtocolV2 RN-BLE',
1791
+ createTimeoutError: (messageName: string, timeout: number) =>
1792
+ ERRORS.TypedError(
1793
+ HardwareErrorCode.BleTimeoutError,
1794
+ `BLE response timeout after ${timeout}ms for ${messageName}`
1795
+ ),
1796
+ };
1797
+ }
1798
+
1763
1799
  getProtocolType(path: string): ProtocolType | undefined {
1764
1800
  return this.deviceProtocol.get(path);
1765
1801
  }