@onekeyfe/hd-transport-web-device 1.2.0-alpha.11 → 1.2.0-alpha.110
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/__tests__/electron-ble-transport.test.ts +373 -22
- package/__tests__/webusb-protocol-v2-timeout.test.ts +386 -0
- package/dist/ble-packet-capacity.d.ts +2 -0
- package/dist/ble-packet-capacity.d.ts.map +1 -0
- package/dist/electron-ble-transport.d.ts +15 -3
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +109 -12
- package/dist/index.js +339 -253
- package/dist/transportLog.d.ts +2 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/dist/webusb.d.ts +15 -10
- package/dist/webusb.d.ts.map +1 -1
- package/jest.config.js +5 -0
- package/package.json +6 -5
- package/src/ble-packet-capacity.ts +13 -0
- package/src/electron-ble-transport.ts +231 -100
- package/src/transportLog.ts +1 -0
- package/src/webusb.ts +181 -220
package/dist/index.js
CHANGED
|
@@ -51,33 +51,22 @@ const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
|
|
|
51
51
|
const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
52
52
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
53
53
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
58
|
-
return WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
59
|
-
}
|
|
60
|
-
function isLogBlockCommand$1(name) {
|
|
61
|
-
var _a, _b;
|
|
62
|
-
return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
|
|
63
|
-
}
|
|
64
|
-
function shouldBlockWebUsbCallDataLog(name) {
|
|
65
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
66
|
-
return isLogBlockCommand$1(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
67
|
-
}
|
|
54
|
+
const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
|
|
55
|
+
const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
|
|
56
|
+
const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
|
|
68
57
|
function inferProtocolHintFromDeviceName$1(name) {
|
|
69
58
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
70
59
|
}
|
|
71
|
-
class WebUsbTransport {
|
|
60
|
+
class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
72
61
|
constructor() {
|
|
62
|
+
super({
|
|
63
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
64
|
+
maxFrameBytes: transport.PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
65
|
+
logPrefix: 'ProtocolV2 WebUSB',
|
|
66
|
+
});
|
|
73
67
|
this.deviceProtocol = new Map();
|
|
74
68
|
this.deviceProtocolHints = new Map();
|
|
75
|
-
this.protocolV2Assemblers = new Map();
|
|
76
|
-
this.protocolV2Sessions = new Map();
|
|
77
|
-
this.protocolV2ReadTimeouts = new Map();
|
|
78
69
|
this.deviceEndpoints = new Map();
|
|
79
|
-
this.mockSerialPaths = new WeakMap();
|
|
80
|
-
this.mockSerialCounter = 0;
|
|
81
70
|
this.name = 'WebUsbTransport';
|
|
82
71
|
this.stopped = false;
|
|
83
72
|
this.configured = false;
|
|
@@ -101,10 +90,17 @@ class WebUsbTransport {
|
|
|
101
90
|
}
|
|
102
91
|
configureProtocolV2(signedData) {
|
|
103
92
|
var _a;
|
|
93
|
+
const schemaSource = typeof signedData === 'string'
|
|
94
|
+
? signedData
|
|
95
|
+
: (_a = JSON.stringify(signedData)) !== null && _a !== void 0 ? _a : String(signedData);
|
|
96
|
+
if (schemaSource === this.protocolV2SchemaSource)
|
|
97
|
+
return;
|
|
98
|
+
const hadProtocolV2Schema = this.protocolV2SchemaSource !== undefined;
|
|
104
99
|
this.messagesV2 = parseConfigure$1(signedData);
|
|
105
|
-
this.
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
this.protocolV2SchemaSource = schemaSource;
|
|
101
|
+
if (!hadProtocolV2Schema)
|
|
102
|
+
return;
|
|
103
|
+
this.invalidateAllProtocolV2UsbLinks('Protocol V2 schema reconfigured').catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] schema link cleanup failed:', error); });
|
|
108
104
|
}
|
|
109
105
|
promptDeviceAccess() {
|
|
110
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -126,28 +122,18 @@ class WebUsbTransport {
|
|
|
126
122
|
return this.deviceList;
|
|
127
123
|
});
|
|
128
124
|
}
|
|
129
|
-
getDevicePath(device) {
|
|
130
|
-
var _a;
|
|
131
|
-
if (typeof device.serialNumber === 'string' && device.serialNumber.length > 0) {
|
|
132
|
-
return device.serialNumber;
|
|
133
|
-
}
|
|
134
|
-
let path = this.mockSerialPaths.get(device);
|
|
135
|
-
if (!path) {
|
|
136
|
-
this.mockSerialCounter += 1;
|
|
137
|
-
path = `mock-serial:${device.vendorId.toString(16)}:${device.productId.toString(16)}:${this.mockSerialCounter}`;
|
|
138
|
-
this.mockSerialPaths.set(device, path);
|
|
139
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUSB] device has no serial number, using mock path: ${path}`);
|
|
140
|
-
}
|
|
141
|
-
return path;
|
|
142
|
-
}
|
|
143
125
|
getConnectedDevices() {
|
|
144
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
145
127
|
if (!this.usb)
|
|
146
128
|
return [];
|
|
147
129
|
const devices = yield this.usb.getDevices();
|
|
148
|
-
const onekeyDevices = devices.filter(dev =>
|
|
130
|
+
const onekeyDevices = devices.filter(dev => {
|
|
131
|
+
const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
|
|
132
|
+
const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
|
|
133
|
+
return isOneKey && hasSerialNumber && !hdShared.isKnownTrezorWebUsbDevice(dev);
|
|
134
|
+
});
|
|
149
135
|
this.deviceList = onekeyDevices.map(device => {
|
|
150
|
-
const path =
|
|
136
|
+
const path = device.serialNumber;
|
|
151
137
|
const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
|
|
152
138
|
if (protocolHint) {
|
|
153
139
|
this.deviceProtocolHints.set(path, protocolHint);
|
|
@@ -158,25 +144,22 @@ class WebUsbTransport {
|
|
|
158
144
|
commType: 'webusb',
|
|
159
145
|
};
|
|
160
146
|
});
|
|
161
|
-
for (const dev of onekeyDevices) {
|
|
162
|
-
this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
|
|
163
|
-
`VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
|
|
164
|
-
}
|
|
165
147
|
return this.deviceList;
|
|
166
148
|
});
|
|
167
149
|
}
|
|
168
150
|
acquire(input) {
|
|
169
|
-
var _a, _b, _c;
|
|
151
|
+
var _a, _b, _c, _d;
|
|
170
152
|
return __awaiter(this, void 0, void 0, function* () {
|
|
171
153
|
if (!input.path)
|
|
172
154
|
return;
|
|
173
155
|
try {
|
|
156
|
+
yield this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
|
|
174
157
|
yield this.closeOpenDevice(input.path);
|
|
175
158
|
yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
|
|
176
159
|
const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
|
|
177
160
|
const protocolHint = input.expectedProtocol
|
|
178
161
|
? undefined
|
|
179
|
-
: (_c = this.deviceProtocolHints.get(input.path)) !== null &&
|
|
162
|
+
: (_d = (_c = input.protocolHint) !== null && _c !== void 0 ? _c : this.deviceProtocolHints.get(input.path)) !== null && _d !== void 0 ? _d : inferProtocolHintFromDeviceName$1(deviceName);
|
|
180
163
|
if (protocolHint) {
|
|
181
164
|
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
182
165
|
}
|
|
@@ -185,6 +168,7 @@ class WebUsbTransport {
|
|
|
185
168
|
}
|
|
186
169
|
catch (e) {
|
|
187
170
|
this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
|
|
171
|
+
yield this.closeOpenDevice(input.path);
|
|
188
172
|
throw e;
|
|
189
173
|
}
|
|
190
174
|
});
|
|
@@ -192,32 +176,53 @@ class WebUsbTransport {
|
|
|
192
176
|
createProtocolMismatchError(expected) {
|
|
193
177
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
194
178
|
}
|
|
179
|
+
createProtocolProbeTimeoutError(expected, attempts) {
|
|
180
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, `Protocol ${expected} probe timeout after ${attempts} attempts`);
|
|
181
|
+
}
|
|
195
182
|
createProtocolDetectionError() {
|
|
196
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.
|
|
183
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
|
|
197
184
|
}
|
|
198
185
|
detectProtocol(path, expectedProtocol, protocolHint) {
|
|
186
|
+
var _a;
|
|
199
187
|
return __awaiter(this, void 0, void 0, function* () {
|
|
200
188
|
if (expectedProtocol === 'V1') {
|
|
201
189
|
if (yield this.probeProtocolV1(path)) {
|
|
202
190
|
this.deviceProtocol.set(path, 'V1');
|
|
203
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
204
191
|
return 'V1';
|
|
205
192
|
}
|
|
193
|
+
yield this.closeConnectionAfterProbe(path);
|
|
206
194
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
207
195
|
}
|
|
208
196
|
if (expectedProtocol === 'V2') {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
197
|
+
for (let attempt = 1; attempt <= EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS; attempt += 1) {
|
|
198
|
+
if (yield this.probeProtocolV2(path)) {
|
|
199
|
+
this.deviceProtocol.set(path, 'V2');
|
|
200
|
+
return 'V2';
|
|
201
|
+
}
|
|
202
|
+
if (attempt < EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS) {
|
|
203
|
+
yield this.resetConnectionAfterProbe(path);
|
|
204
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] Protocol V2 probe timed out, retrying ${attempt + 1}/${EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS}`);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
yield this.closeConnectionAfterProbe(path);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
this.deviceProtocol.delete(path);
|
|
211
|
+
throw this.createProtocolProbeTimeoutError(expectedProtocol, EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS);
|
|
212
212
|
}
|
|
213
213
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
214
|
-
for (const protocol of probeOrder) {
|
|
214
|
+
for (const [index, protocol] of probeOrder.entries()) {
|
|
215
215
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
|
|
216
216
|
if (detected) {
|
|
217
217
|
this.deviceProtocol.set(path, protocol);
|
|
218
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> ${protocol}`);
|
|
219
218
|
return protocol;
|
|
220
219
|
}
|
|
220
|
+
if (index < probeOrder.length - 1) {
|
|
221
|
+
yield this.resetConnectionAfterProbe(path);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
yield this.closeConnectionAfterProbe(path);
|
|
225
|
+
}
|
|
221
226
|
}
|
|
222
227
|
this.deviceProtocol.delete(path);
|
|
223
228
|
throw this.createProtocolDetectionError();
|
|
@@ -284,10 +289,9 @@ class WebUsbTransport {
|
|
|
284
289
|
};
|
|
285
290
|
}
|
|
286
291
|
connectToDevice(path, first) {
|
|
287
|
-
var _a
|
|
292
|
+
var _a;
|
|
288
293
|
return __awaiter(this, void 0, void 0, function* () {
|
|
289
294
|
let device = yield this.findDevice(path);
|
|
290
|
-
this.Log.debug('[WebUsbTransport] connecting to device:', device.productName, 'PID:', device.productId);
|
|
291
295
|
if (!device.opened) {
|
|
292
296
|
yield device.open();
|
|
293
297
|
}
|
|
@@ -309,33 +313,30 @@ class WebUsbTransport {
|
|
|
309
313
|
}
|
|
310
314
|
const endpoints = this.discoverEndpoints(device);
|
|
311
315
|
this.deviceEndpoints.set(path, endpoints);
|
|
312
|
-
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
313
|
-
this.protocolV2Assemblers.set(path, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES));
|
|
314
316
|
yield device.claimInterface(endpoints.interfaceNumber);
|
|
315
317
|
yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
|
|
316
318
|
yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
|
|
317
319
|
});
|
|
318
320
|
}
|
|
319
321
|
closeOpenDevice(path) {
|
|
320
|
-
var _a, _b, _c, _d
|
|
322
|
+
var _a, _b, _c, _d;
|
|
321
323
|
return __awaiter(this, void 0, void 0, function* () {
|
|
322
|
-
(_a = this.
|
|
323
|
-
const current = (_b = this.deviceList.find(device => device.path === path)) === null || _b === void 0 ? void 0 : _b.device;
|
|
324
|
+
const current = (_a = this.deviceList.find(device => device.path === path)) === null || _a === void 0 ? void 0 : _a.device;
|
|
324
325
|
if (!(current === null || current === void 0 ? void 0 : current.opened))
|
|
325
326
|
return;
|
|
326
327
|
const endpoints = this.deviceEndpoints.get(path);
|
|
327
|
-
const ifaceNum = (
|
|
328
|
+
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
328
329
|
try {
|
|
329
330
|
yield current.releaseInterface(ifaceNum);
|
|
330
331
|
}
|
|
331
332
|
catch (error) {
|
|
332
|
-
(
|
|
333
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
333
334
|
}
|
|
334
335
|
try {
|
|
335
336
|
yield current.close();
|
|
336
337
|
}
|
|
337
338
|
catch (error) {
|
|
338
|
-
(
|
|
339
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[WebUsbTransport] close before reconnect failed:', error);
|
|
339
340
|
}
|
|
340
341
|
});
|
|
341
342
|
}
|
|
@@ -497,29 +498,28 @@ class WebUsbTransport {
|
|
|
497
498
|
throw lastError;
|
|
498
499
|
});
|
|
499
500
|
}
|
|
500
|
-
|
|
501
|
-
var _a
|
|
501
|
+
transferInOnce(path, length) {
|
|
502
|
+
var _a;
|
|
502
503
|
return __awaiter(this, void 0, void 0, function* () {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
try {
|
|
507
|
-
const device = yield this.findDevice(path);
|
|
508
|
-
if (device.opened) {
|
|
509
|
-
const endpoints = this.deviceEndpoints.get(path);
|
|
510
|
-
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
511
|
-
try {
|
|
512
|
-
yield device.releaseInterface(ifaceNum);
|
|
513
|
-
}
|
|
514
|
-
catch (error) {
|
|
515
|
-
this.Log.debug('[WebUsbTransport] releaseInterface after protocol probe error:', error);
|
|
516
|
-
}
|
|
517
|
-
yield device.close();
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
catch (error) {
|
|
521
|
-
this.Log.debug('[WebUsbTransport] close after protocol probe error:', error);
|
|
504
|
+
const device = yield this.findDevice(path);
|
|
505
|
+
if (!device.opened) {
|
|
506
|
+
throw new Error('USBDevice is not open for transferIn');
|
|
522
507
|
}
|
|
508
|
+
const endpoints = this.deviceEndpoints.get(path);
|
|
509
|
+
const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
510
|
+
const result = yield device.transferIn(endpointIn, length);
|
|
511
|
+
return this.getTransferInData(result);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
closeConnectionAfterProbe(path) {
|
|
515
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
516
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'WebUSB protocol probe reset');
|
|
517
|
+
yield this.closeOpenDevice(path);
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
resetConnectionAfterProbe(path) {
|
|
521
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
522
|
+
yield this.closeConnectionAfterProbe(path);
|
|
523
523
|
yield this.getConnectedDevices();
|
|
524
524
|
yield this.connect(path, false);
|
|
525
525
|
});
|
|
@@ -542,6 +542,14 @@ class WebUsbTransport {
|
|
|
542
542
|
timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
543
543
|
timedOut = true;
|
|
544
544
|
onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
|
|
545
|
+
if (protocol === 'V1') {
|
|
546
|
+
try {
|
|
547
|
+
yield this.resetConnectionAfterProbe(path);
|
|
548
|
+
}
|
|
549
|
+
catch (error) {
|
|
550
|
+
this.Log.debug('[WebUsbTransport] reset after Protocol V1 timeout failed:', error);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
545
553
|
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
546
554
|
}), timeoutMs);
|
|
547
555
|
}),
|
|
@@ -559,11 +567,12 @@ class WebUsbTransport {
|
|
|
559
567
|
return false;
|
|
560
568
|
}
|
|
561
569
|
try {
|
|
562
|
-
yield this.callProtocolV1(path, 'Initialize', {}, {
|
|
570
|
+
yield this.callProtocolV1(path, 'Initialize', {}, {
|
|
571
|
+
timeoutMs: PROTOCOL_V1_PROBE_TIMEOUT,
|
|
572
|
+
});
|
|
563
573
|
return true;
|
|
564
574
|
}
|
|
565
|
-
catch (
|
|
566
|
-
this.Log.debug('[WebUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
575
|
+
catch (_error) {
|
|
567
576
|
return false;
|
|
568
577
|
}
|
|
569
578
|
});
|
|
@@ -575,10 +584,9 @@ class WebUsbTransport {
|
|
|
575
584
|
}
|
|
576
585
|
return transport.probeProtocolV2({
|
|
577
586
|
call: (name, data, options) => this.callProtocolV2(path, name, data, options),
|
|
578
|
-
timeoutMs:
|
|
587
|
+
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT,
|
|
579
588
|
logger: this.Log,
|
|
580
589
|
logPrefix: 'ProtocolV2 WebUSB',
|
|
581
|
-
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
582
590
|
});
|
|
583
591
|
});
|
|
584
592
|
}
|
|
@@ -595,13 +603,6 @@ class WebUsbTransport {
|
|
|
595
603
|
if (!protocol) {
|
|
596
604
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
597
605
|
}
|
|
598
|
-
if (shouldSuppressWebUsbCallLog(name)) ;
|
|
599
|
-
else if (shouldBlockWebUsbCallDataLog(name)) {
|
|
600
|
-
this.Log.debug('call-', ' name: ', name, ' protocol: ', protocol);
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
this.Log.debug('call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
604
|
-
}
|
|
605
606
|
if (protocol === 'V2') {
|
|
606
607
|
return this.callProtocolV2(path, name, data, options);
|
|
607
608
|
}
|
|
@@ -630,67 +631,8 @@ class WebUsbTransport {
|
|
|
630
631
|
});
|
|
631
632
|
}
|
|
632
633
|
callProtocolV2(path, name, data, options) {
|
|
633
|
-
var _a;
|
|
634
634
|
return __awaiter(this, void 0, void 0, function* () {
|
|
635
|
-
|
|
636
|
-
if (!this.messagesV2) {
|
|
637
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
638
|
-
}
|
|
639
|
-
if (!protocolV1Messages) {
|
|
640
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
641
|
-
}
|
|
642
|
-
let session = this.protocolV2Sessions.get(path);
|
|
643
|
-
if (!session) {
|
|
644
|
-
session = new transport.ProtocolV2Session({
|
|
645
|
-
schemas: {
|
|
646
|
-
protocolV1: protocolV1Messages,
|
|
647
|
-
protocolV2: this.messagesV2,
|
|
648
|
-
},
|
|
649
|
-
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
650
|
-
writeFrame: (frame) => this.transferOutOnce(path, frame),
|
|
651
|
-
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
652
|
-
logger: this.Log,
|
|
653
|
-
logPrefix: 'ProtocolV2 WebUSB',
|
|
654
|
-
createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
|
|
655
|
-
});
|
|
656
|
-
this.protocolV2Sessions.set(path, session);
|
|
657
|
-
}
|
|
658
|
-
this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
659
|
-
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
660
|
-
try {
|
|
661
|
-
return yield session.call(name, data, options);
|
|
662
|
-
}
|
|
663
|
-
finally {
|
|
664
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
665
|
-
}
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
receiveProtocolV2Frame(path, timeoutMs) {
|
|
669
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
670
|
-
let assembler = this.protocolV2Assemblers.get(path);
|
|
671
|
-
if (!assembler) {
|
|
672
|
-
assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
673
|
-
this.protocolV2Assemblers.set(path, assembler);
|
|
674
|
-
}
|
|
675
|
-
let frame = assembler.push(new Uint8Array(0));
|
|
676
|
-
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
677
|
-
while (!frame) {
|
|
678
|
-
const cancelToken = { cancelled: false };
|
|
679
|
-
const transferIn = this.transferInWithRetry(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES, cancelToken);
|
|
680
|
-
const dataView = deadline
|
|
681
|
-
? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2', () => {
|
|
682
|
-
cancelToken.cancelled = true;
|
|
683
|
-
})
|
|
684
|
-
: yield transferIn;
|
|
685
|
-
const bytes = new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
|
|
686
|
-
try {
|
|
687
|
-
frame = assembler.push(bytes);
|
|
688
|
-
}
|
|
689
|
-
catch (error) {
|
|
690
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
return frame;
|
|
635
|
+
return this.callProtocolV2Usb(path, name, data, options);
|
|
694
636
|
});
|
|
695
637
|
}
|
|
696
638
|
receiveData(path, timeoutMs) {
|
|
@@ -731,42 +673,71 @@ class WebUsbTransport {
|
|
|
731
673
|
});
|
|
732
674
|
}
|
|
733
675
|
release(path) {
|
|
734
|
-
var _a, _b;
|
|
735
676
|
return __awaiter(this, void 0, void 0, function* () {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
|
|
739
|
-
yield device.releaseInterface(ifaceNum);
|
|
740
|
-
yield device.close();
|
|
677
|
+
yield this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
|
|
678
|
+
yield this.closeOpenDevice(path);
|
|
741
679
|
this.deviceProtocol.delete(path);
|
|
742
680
|
this.deviceProtocolHints.delete(path);
|
|
743
|
-
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
744
|
-
this.protocolV2Assemblers.delete(path);
|
|
745
681
|
this.deviceEndpoints.delete(path);
|
|
746
682
|
});
|
|
747
683
|
}
|
|
684
|
+
getProtocolV2UsbSchemas() {
|
|
685
|
+
if (!this.messages || !this.messagesV2) {
|
|
686
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
687
|
+
}
|
|
688
|
+
return {
|
|
689
|
+
protocolV1: this.messages,
|
|
690
|
+
protocolV2: this.messagesV2,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
getProtocolV2UsbLogger() {
|
|
694
|
+
return this.Log;
|
|
695
|
+
}
|
|
696
|
+
writeProtocolV2UsbPacket(path, frame, _context) {
|
|
697
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
698
|
+
yield this.transferOutOnce(path, frame);
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
readProtocolV2UsbPacket(path, _context) {
|
|
702
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
703
|
+
const dataView = yield this.transferInOnce(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
704
|
+
return new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
resetProtocolV2UsbNativeLink(path, _reason) {
|
|
708
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
709
|
+
yield this.closeOpenDevice(path);
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
onProtocolV2UsbLinkInvalidated(path, reason) {
|
|
713
|
+
var _a;
|
|
714
|
+
this.deviceProtocol.delete(path);
|
|
715
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
|
|
716
|
+
}
|
|
717
|
+
createProtocolV2UsbTimeoutError(name, timeoutMs) {
|
|
718
|
+
return new transport.ProtocolV2LinkError('response-timeout', `Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
|
|
719
|
+
}
|
|
748
720
|
getProtocolType(path) {
|
|
749
721
|
return this.deviceProtocol.get(path);
|
|
750
722
|
}
|
|
751
723
|
}
|
|
752
724
|
|
|
753
|
-
const
|
|
754
|
-
function
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
var _a, _b;
|
|
760
|
-
return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
|
|
725
|
+
const BLE_ATT_HEADER_BYTES = 3;
|
|
726
|
+
function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapacity) {
|
|
727
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= BLE_ATT_HEADER_BYTES) {
|
|
728
|
+
return fallbackPacketCapacity;
|
|
729
|
+
}
|
|
730
|
+
return Math.min(maximumPacketCapacity, Math.floor(mtu) - BLE_ATT_HEADER_BYTES);
|
|
761
731
|
}
|
|
732
|
+
|
|
762
733
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
763
734
|
function inferProtocolHintFromDeviceName(name) {
|
|
764
735
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
765
736
|
}
|
|
766
737
|
const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
|
|
767
|
-
const
|
|
738
|
+
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
739
|
+
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
768
740
|
const BLE_WRITE_DELAY_MS = 5;
|
|
769
|
-
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
770
741
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
771
742
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
|
|
772
743
|
class ElectronBleTransport {
|
|
@@ -774,9 +745,12 @@ class ElectronBleTransport {
|
|
|
774
745
|
this.name = 'ElectronBleTransport';
|
|
775
746
|
this.configured = false;
|
|
776
747
|
this.runPromise = null;
|
|
748
|
+
this.runPromiseDeviceId = null;
|
|
777
749
|
this.connectedDevices = new Set();
|
|
778
750
|
this.deviceProtocol = new Map();
|
|
779
751
|
this.deviceProtocolHints = new Map();
|
|
752
|
+
this.deviceMtus = new Map();
|
|
753
|
+
this.devicePacketCapacities = new Map();
|
|
780
754
|
this.v1Buffers = new Map();
|
|
781
755
|
this.v2Assemblers = new Map();
|
|
782
756
|
this.v2FrameQueues = new Map();
|
|
@@ -798,11 +772,13 @@ class ElectronBleTransport {
|
|
|
798
772
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
799
773
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
800
774
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
801
|
-
yield this.
|
|
775
|
+
yield this.releaseNative(uuid);
|
|
802
776
|
}
|
|
803
777
|
}),
|
|
804
778
|
});
|
|
779
|
+
this.warnedMissingRelease = false;
|
|
805
780
|
this.notificationCleanups = new Map();
|
|
781
|
+
this.mtuCleanups = new Map();
|
|
806
782
|
this.disconnectCleanups = new Map();
|
|
807
783
|
this.notificationTokens = new Map();
|
|
808
784
|
this.nextNotificationToken = 1;
|
|
@@ -842,15 +818,27 @@ class ElectronBleTransport {
|
|
|
842
818
|
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
843
819
|
this.connectedDevices.delete(deviceId);
|
|
844
820
|
this.deviceProtocol.delete(deviceId);
|
|
821
|
+
this.deviceMtus.delete(deviceId);
|
|
822
|
+
this.devicePacketCapacities.delete(deviceId);
|
|
845
823
|
this.v1Buffers.delete(deviceId);
|
|
846
824
|
this.v2Assemblers.delete(deviceId);
|
|
847
825
|
this.resetProtocolV2Frames(deviceId);
|
|
848
826
|
this.notificationTokens.delete(deviceId);
|
|
827
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
828
|
+
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
829
|
+
this.runPromise = null;
|
|
830
|
+
this.runPromiseDeviceId = null;
|
|
831
|
+
}
|
|
849
832
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
850
833
|
if (notifyCleanup) {
|
|
851
834
|
notifyCleanup();
|
|
852
835
|
this.notificationCleanups.delete(deviceId);
|
|
853
836
|
}
|
|
837
|
+
const mtuCleanup = this.mtuCleanups.get(deviceId);
|
|
838
|
+
if (mtuCleanup) {
|
|
839
|
+
mtuCleanup();
|
|
840
|
+
this.mtuCleanups.delete(deviceId);
|
|
841
|
+
}
|
|
854
842
|
const disconnectCleanup = this.disconnectCleanups.get(deviceId);
|
|
855
843
|
if (disconnectCleanup) {
|
|
856
844
|
disconnectCleanup();
|
|
@@ -871,12 +859,18 @@ class ElectronBleTransport {
|
|
|
871
859
|
this.configured = true;
|
|
872
860
|
}
|
|
873
861
|
configureProtocolV2(signedData) {
|
|
874
|
-
|
|
862
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
863
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
875
867
|
this._messagesV2 = parseConfigure(signedData);
|
|
876
|
-
this.
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
868
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
869
|
+
if (isReconfiguration) {
|
|
870
|
+
this.protocolV2Links
|
|
871
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
872
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
|
|
873
|
+
}
|
|
880
874
|
}
|
|
881
875
|
listen() {
|
|
882
876
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -908,7 +902,7 @@ class ElectronBleTransport {
|
|
|
908
902
|
});
|
|
909
903
|
}
|
|
910
904
|
acquire(input) {
|
|
911
|
-
var _a, _b, _c, _d, _e, _f;
|
|
905
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
912
906
|
return __awaiter(this, void 0, void 0, function* () {
|
|
913
907
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
914
908
|
if (!uuid) {
|
|
@@ -920,8 +914,8 @@ class ElectronBleTransport {
|
|
|
920
914
|
if (forceCleanRunPromise && this.runPromise) {
|
|
921
915
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
922
916
|
this.runPromise.reject(error);
|
|
923
|
-
this.rejectAllProtocolV2Frames(error);
|
|
924
917
|
this.runPromise = null;
|
|
918
|
+
this.runPromiseDeviceId = null;
|
|
925
919
|
}
|
|
926
920
|
try {
|
|
927
921
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -933,7 +927,7 @@ class ElectronBleTransport {
|
|
|
933
927
|
}
|
|
934
928
|
const protocolHint = expectedProtocol
|
|
935
929
|
? undefined
|
|
936
|
-
: (_b = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
930
|
+
: (_c = (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName(device.name);
|
|
937
931
|
if (protocolHint) {
|
|
938
932
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
939
933
|
}
|
|
@@ -944,16 +938,31 @@ class ElectronBleTransport {
|
|
|
944
938
|
catch (error) {
|
|
945
939
|
this.handleBluetoothError(error);
|
|
946
940
|
}
|
|
941
|
+
const mtuCleanup = this.createMtuSubscription(uuid);
|
|
942
|
+
if (mtuCleanup) {
|
|
943
|
+
this.mtuCleanups.set(uuid, mtuCleanup);
|
|
944
|
+
}
|
|
947
945
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
948
|
-
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
946
|
+
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
949
947
|
yield window.desktopApi.nobleBle.subscribe(uuid);
|
|
948
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
950
949
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
951
950
|
this.notificationCleanups.set(uuid, cleanup);
|
|
951
|
+
const connectionToken = this.notificationTokens.get(uuid);
|
|
952
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
953
|
+
if (protocolType === 'V2') {
|
|
954
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[Electron BLE] Protocol V2 write configured', {
|
|
955
|
+
writeMode: 'withoutResponse',
|
|
956
|
+
negotiatedMtu: this.deviceMtus.get(uuid),
|
|
957
|
+
packetCapacity: (_e = this.devicePacketCapacities.get(uuid)) !== null && _e !== void 0 ? _e : BLE_PACKET_SIZE_FALLBACK,
|
|
958
|
+
});
|
|
959
|
+
}
|
|
952
960
|
const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
|
|
953
961
|
var _a;
|
|
954
|
-
if (disconnectedDevice.id === uuid
|
|
962
|
+
if (disconnectedDevice.id === uuid &&
|
|
963
|
+
this.notificationTokens.get(uuid) === connectionToken) {
|
|
955
964
|
this.cleanupDeviceState(uuid);
|
|
956
|
-
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(
|
|
965
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
957
966
|
name: disconnectedDevice.name,
|
|
958
967
|
id: disconnectedDevice.id,
|
|
959
968
|
connectId: disconnectedDevice.id,
|
|
@@ -961,35 +970,46 @@ class ElectronBleTransport {
|
|
|
961
970
|
}
|
|
962
971
|
});
|
|
963
972
|
this.disconnectCleanups.set(uuid, disconnectCleanup);
|
|
964
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
965
|
-
(_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit('device-connect', {
|
|
966
|
-
name: device.name,
|
|
967
|
-
id: device.id,
|
|
968
|
-
connectId: device.id,
|
|
969
|
-
});
|
|
970
973
|
return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
|
|
971
974
|
}
|
|
972
975
|
catch (error) {
|
|
973
|
-
(
|
|
976
|
+
(_f = this.Log) === null || _f === void 0 ? void 0 : _f.error('[Electron BLE] acquire failed:', error);
|
|
974
977
|
try {
|
|
975
|
-
if (((
|
|
978
|
+
if (((_g = window.desktopApi) === null || _g === void 0 ? void 0 : _g.nobleBle) && this.connectedDevices.has(uuid)) {
|
|
976
979
|
yield window.desktopApi.nobleBle.unsubscribe(uuid);
|
|
977
980
|
yield window.desktopApi.nobleBle.disconnect(uuid);
|
|
978
981
|
}
|
|
979
982
|
}
|
|
980
983
|
catch (cleanupError) {
|
|
981
|
-
(
|
|
984
|
+
(_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
|
|
982
985
|
}
|
|
983
986
|
this.cleanupDeviceState(uuid);
|
|
984
987
|
throw error;
|
|
985
988
|
}
|
|
986
989
|
});
|
|
987
990
|
}
|
|
988
|
-
release(id) {
|
|
989
|
-
var _a
|
|
991
|
+
release(id, _onclose, keepSession) {
|
|
992
|
+
var _a;
|
|
990
993
|
return __awaiter(this, void 0, void 0, function* () {
|
|
991
994
|
try {
|
|
992
995
|
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
996
|
+
yield this.releaseLogical(id, keepSession);
|
|
997
|
+
}
|
|
998
|
+
catch (error) {
|
|
999
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] release failed:', error);
|
|
1000
|
+
this.cleanupDeviceState(id);
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
disconnect(id) {
|
|
1005
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1006
|
+
return this.releaseNative(id);
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
releaseNative(id) {
|
|
1010
|
+
var _a, _b;
|
|
1011
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1012
|
+
try {
|
|
993
1013
|
if (this.connectedDevices.has(id)) {
|
|
994
1014
|
if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
|
|
995
1015
|
yield window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -1004,11 +1024,35 @@ class ElectronBleTransport {
|
|
|
1004
1024
|
}
|
|
1005
1025
|
});
|
|
1006
1026
|
}
|
|
1027
|
+
releaseLogical(id, keepSession) {
|
|
1028
|
+
var _a, _b, _c, _d;
|
|
1029
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1030
|
+
try {
|
|
1031
|
+
if (!this.connectedDevices.has(id))
|
|
1032
|
+
return;
|
|
1033
|
+
this.cleanupDeviceState(id);
|
|
1034
|
+
const release = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.release;
|
|
1035
|
+
if (!release) {
|
|
1036
|
+
if (!this.warnedMissingRelease) {
|
|
1037
|
+
this.warnedMissingRelease = true;
|
|
1038
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Electron BLE] desktopApi.nobleBle.release is missing from the preload bridge; ' +
|
|
1039
|
+
'keep-alive idle countdown will never start — map NOBLE_BLE_RELEASE in the desktop preload');
|
|
1040
|
+
}
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
yield release(id, keepSession);
|
|
1044
|
+
}
|
|
1045
|
+
catch (error) {
|
|
1046
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] logical release failed:', error);
|
|
1047
|
+
this.cleanupDeviceState(id);
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1007
1051
|
createProtocolMismatchError(expected) {
|
|
1008
1052
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1009
1053
|
}
|
|
1010
1054
|
createProtocolDetectionError() {
|
|
1011
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1055
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1012
1056
|
}
|
|
1013
1057
|
clearProbeProtocol(uuid, protocol) {
|
|
1014
1058
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
@@ -1027,9 +1071,12 @@ class ElectronBleTransport {
|
|
|
1027
1071
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1028
1072
|
}
|
|
1029
1073
|
if (expectedProtocol === 'V2') {
|
|
1030
|
-
this.
|
|
1031
|
-
|
|
1032
|
-
|
|
1074
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1075
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1076
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
1077
|
+
return 'V2';
|
|
1078
|
+
}
|
|
1079
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1033
1080
|
}
|
|
1034
1081
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1035
1082
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
@@ -1063,16 +1110,17 @@ class ElectronBleTransport {
|
|
|
1063
1110
|
});
|
|
1064
1111
|
}
|
|
1065
1112
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1066
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1113
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1067
1114
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1068
1115
|
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1069
1116
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1070
1117
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1071
1118
|
this.resetProtocolV2Frames(uuid);
|
|
1072
|
-
if (this.runPromise) {
|
|
1119
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1073
1120
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1074
1121
|
this.runPromise.reject(error);
|
|
1075
1122
|
this.runPromise = null;
|
|
1123
|
+
this.runPromiseDeviceId = null;
|
|
1076
1124
|
}
|
|
1077
1125
|
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1078
1126
|
if (notifyCleanup) {
|
|
@@ -1087,10 +1135,20 @@ class ElectronBleTransport {
|
|
|
1087
1135
|
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1088
1136
|
}
|
|
1089
1137
|
try {
|
|
1090
|
-
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.
|
|
1138
|
+
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.disconnect(uuid));
|
|
1139
|
+
}
|
|
1140
|
+
catch (error) {
|
|
1141
|
+
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] disconnect after Protocol ${protocol} probe failed:`, error);
|
|
1142
|
+
}
|
|
1143
|
+
this.connectedDevices.delete(uuid);
|
|
1144
|
+
try {
|
|
1145
|
+
yield ((_j = (_h = window.desktopApi) === null || _h === void 0 ? void 0 : _h.nobleBle) === null || _j === void 0 ? void 0 : _j.connect(uuid));
|
|
1146
|
+
this.connectedDevices.add(uuid);
|
|
1147
|
+
yield ((_l = (_k = window.desktopApi) === null || _k === void 0 ? void 0 : _k.nobleBle) === null || _l === void 0 ? void 0 : _l.subscribe(uuid));
|
|
1148
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
1091
1149
|
}
|
|
1092
1150
|
catch (error) {
|
|
1093
|
-
(
|
|
1151
|
+
(_m = this.Log) === null || _m === void 0 ? void 0 : _m.debug(`[Electron BLE] reconnect after Protocol ${protocol} probe failed:`, error);
|
|
1094
1152
|
throw error;
|
|
1095
1153
|
}
|
|
1096
1154
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
@@ -1105,12 +1163,12 @@ class ElectronBleTransport {
|
|
|
1105
1163
|
}
|
|
1106
1164
|
try {
|
|
1107
1165
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1108
|
-
yield this.callProtocolV1(uuid, '
|
|
1166
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1109
1167
|
return true;
|
|
1110
1168
|
}
|
|
1111
1169
|
catch (error) {
|
|
1112
1170
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1113
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1
|
|
1171
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1 GetFeatures probe failed:', error);
|
|
1114
1172
|
return false;
|
|
1115
1173
|
}
|
|
1116
1174
|
});
|
|
@@ -1140,25 +1198,6 @@ class ElectronBleTransport {
|
|
|
1140
1198
|
return detected;
|
|
1141
1199
|
});
|
|
1142
1200
|
}
|
|
1143
|
-
writeWithChunking(uuid, hexData) {
|
|
1144
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1145
|
-
const totalBytes = hexData.length / 2;
|
|
1146
|
-
if (totalBytes <= BLE_PACKET_SIZE) {
|
|
1147
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1148
|
-
yield this.writeOnce(uuid, hexData);
|
|
1149
|
-
return;
|
|
1150
|
-
}
|
|
1151
|
-
for (let offset = 0; offset < hexData.length;) {
|
|
1152
|
-
const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
|
|
1153
|
-
const chunkHex = hexData.substring(offset, offset + chunkHexLen);
|
|
1154
|
-
offset += chunkHexLen;
|
|
1155
|
-
yield this.writeOnce(uuid, chunkHex);
|
|
1156
|
-
if (offset < hexData.length) {
|
|
1157
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
1201
|
writeOnce(uuid, hexData) {
|
|
1163
1202
|
var _a;
|
|
1164
1203
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1166,7 +1205,51 @@ class ElectronBleTransport {
|
|
|
1166
1205
|
if (!nobleBle) {
|
|
1167
1206
|
throw new Error('Noble BLE API not available');
|
|
1168
1207
|
}
|
|
1169
|
-
yield nobleBle.write(uuid, hexData);
|
|
1208
|
+
yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
refreshBlePacketCapacity(uuid) {
|
|
1212
|
+
var _a, _b;
|
|
1213
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1214
|
+
const device = yield ((_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.getDevice(uuid));
|
|
1215
|
+
this.updateBlePacketCapacity(uuid, device === null || device === void 0 ? void 0 : device.mtu);
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
updateBlePacketCapacity(uuid, mtu) {
|
|
1219
|
+
const packetCapacity = resolveBlePacketCapacity(mtu, BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
1220
|
+
if (typeof mtu === 'number') {
|
|
1221
|
+
this.deviceMtus.set(uuid, mtu);
|
|
1222
|
+
}
|
|
1223
|
+
else {
|
|
1224
|
+
this.deviceMtus.delete(uuid);
|
|
1225
|
+
}
|
|
1226
|
+
this.devicePacketCapacities.set(uuid, packetCapacity);
|
|
1227
|
+
}
|
|
1228
|
+
createMtuSubscription(uuid) {
|
|
1229
|
+
var _a, _b;
|
|
1230
|
+
const onMtuChanged = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.onMtuChanged;
|
|
1231
|
+
if (!onMtuChanged)
|
|
1232
|
+
return undefined;
|
|
1233
|
+
return onMtuChanged(device => {
|
|
1234
|
+
if (device.id === uuid) {
|
|
1235
|
+
this.updateBlePacketCapacity(uuid, device.mtu);
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration) {
|
|
1240
|
+
var _a;
|
|
1241
|
+
const packetCapacity = (_a = this.devicePacketCapacities.get(uuid)) !== null && _a !== void 0 ? _a : BLE_PACKET_SIZE_FALLBACK;
|
|
1242
|
+
const shouldPace = !context.highThroughput;
|
|
1243
|
+
return transport.writeProtocolV2BleFrame({
|
|
1244
|
+
frame,
|
|
1245
|
+
packetCapacity,
|
|
1246
|
+
assertActive: assertCurrentGeneration,
|
|
1247
|
+
signal: context.signal,
|
|
1248
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1249
|
+
initialDelayMs: shouldPace && frame.length <= packetCapacity ? BLE_WRITE_DELAY_MS : 0,
|
|
1250
|
+
burstSize: shouldPace ? 1 : undefined,
|
|
1251
|
+
burstPauseMs: shouldPace ? BLE_WRITE_DELAY_MS : 0,
|
|
1252
|
+
writePacket: packet => this.writeOnce(uuid, transport.bytesToHex(packet)),
|
|
1170
1253
|
});
|
|
1171
1254
|
}
|
|
1172
1255
|
handleNotification(deviceId, hexData) {
|
|
@@ -1177,7 +1260,7 @@ class ElectronBleTransport {
|
|
|
1177
1260
|
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
1178
1261
|
this.rejectProtocolV2Frames(deviceId, error);
|
|
1179
1262
|
}
|
|
1180
|
-
else if (this.runPromise) {
|
|
1263
|
+
else if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1181
1264
|
this.runPromise.reject(error);
|
|
1182
1265
|
}
|
|
1183
1266
|
return;
|
|
@@ -1229,16 +1312,8 @@ class ElectronBleTransport {
|
|
|
1229
1312
|
}
|
|
1230
1313
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1231
1314
|
}
|
|
1232
|
-
rejectAllProtocolV2Frames(error) {
|
|
1233
|
-
this.v2FrameQueues.clear();
|
|
1234
|
-
for (const framePromise of this.v2FramePromises.values()) {
|
|
1235
|
-
framePromise.reject(error);
|
|
1236
|
-
}
|
|
1237
|
-
this.v2FramePromises.clear();
|
|
1238
|
-
}
|
|
1239
1315
|
resetProtocolV2Frames(uuid) {
|
|
1240
|
-
this.
|
|
1241
|
-
this.v2FramePromises.delete(uuid);
|
|
1316
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1242
1317
|
}
|
|
1243
1318
|
rejectProtocolV2Frames(uuid, error) {
|
|
1244
1319
|
this.v2FrameQueues.delete(uuid);
|
|
@@ -1271,17 +1346,19 @@ class ElectronBleTransport {
|
|
|
1271
1346
|
const result = this.processProtocolV1Notification(deviceId, hexData);
|
|
1272
1347
|
if (result.error) {
|
|
1273
1348
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V1 packet processing error:', result.error);
|
|
1274
|
-
if (this.runPromise) {
|
|
1349
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1275
1350
|
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
|
|
1276
1351
|
}
|
|
1277
1352
|
return;
|
|
1278
1353
|
}
|
|
1279
|
-
if (result.isComplete &&
|
|
1354
|
+
if (result.isComplete &&
|
|
1355
|
+
result.completePacket &&
|
|
1356
|
+
this.runPromise &&
|
|
1357
|
+
this.runPromiseDeviceId === deviceId) {
|
|
1280
1358
|
this.runPromise.resolve(result.completePacket);
|
|
1281
1359
|
}
|
|
1282
1360
|
}
|
|
1283
1361
|
call(uuid, name, data, options) {
|
|
1284
|
-
var _a, _b;
|
|
1285
1362
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1286
1363
|
if (!this._messages) {
|
|
1287
1364
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
@@ -1293,13 +1370,6 @@ class ElectronBleTransport {
|
|
|
1293
1370
|
if (!protocol) {
|
|
1294
1371
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1295
1372
|
}
|
|
1296
|
-
if (shouldSuppressHighVolumeCallLog(name)) ;
|
|
1297
|
-
else if (isLogBlockCommand(name)) {
|
|
1298
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
|
|
1299
|
-
}
|
|
1300
|
-
else {
|
|
1301
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
|
|
1302
|
-
}
|
|
1303
1373
|
if (protocol === 'V2') {
|
|
1304
1374
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1305
1375
|
}
|
|
@@ -1319,6 +1389,7 @@ class ElectronBleTransport {
|
|
|
1319
1389
|
const runPromise = hdShared.createDeferred();
|
|
1320
1390
|
runPromise.promise.catch(() => undefined);
|
|
1321
1391
|
this.runPromise = runPromise;
|
|
1392
|
+
this.runPromiseDeviceId = uuid;
|
|
1322
1393
|
const messages = this._messages;
|
|
1323
1394
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1324
1395
|
let timeout;
|
|
@@ -1357,6 +1428,17 @@ class ElectronBleTransport {
|
|
|
1357
1428
|
}
|
|
1358
1429
|
catch (e) {
|
|
1359
1430
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V1 call error:', e);
|
|
1431
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1432
|
+
if ((e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1433
|
+
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1434
|
+
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1435
|
+
notifyCleanup === null || notifyCleanup === void 0 ? void 0 : notifyCleanup();
|
|
1436
|
+
this.notificationCleanups.delete(uuid);
|
|
1437
|
+
this.notificationTokens.delete(uuid);
|
|
1438
|
+
if (!isProbeTimeout) {
|
|
1439
|
+
yield this.releaseNative(uuid);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1360
1442
|
throw e;
|
|
1361
1443
|
}
|
|
1362
1444
|
finally {
|
|
@@ -1364,22 +1446,23 @@ class ElectronBleTransport {
|
|
|
1364
1446
|
clearTimeout(timeout);
|
|
1365
1447
|
if (this.runPromise === runPromise) {
|
|
1366
1448
|
this.runPromise = null;
|
|
1449
|
+
this.runPromiseDeviceId = null;
|
|
1367
1450
|
}
|
|
1368
1451
|
}
|
|
1369
1452
|
});
|
|
1370
1453
|
}
|
|
1371
1454
|
callProtocolV2(uuid, name, data, options) {
|
|
1372
|
-
var _a
|
|
1455
|
+
var _a;
|
|
1373
1456
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1374
1457
|
if (!this._messages || !this._messagesV2) {
|
|
1375
1458
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1376
1459
|
}
|
|
1377
|
-
const callOptions =
|
|
1460
|
+
const callOptions = options;
|
|
1378
1461
|
try {
|
|
1379
1462
|
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1380
1463
|
}
|
|
1381
1464
|
catch (e) {
|
|
1382
|
-
(
|
|
1465
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1383
1466
|
throw e;
|
|
1384
1467
|
}
|
|
1385
1468
|
});
|
|
@@ -1394,6 +1477,7 @@ class ElectronBleTransport {
|
|
|
1394
1477
|
};
|
|
1395
1478
|
return {
|
|
1396
1479
|
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1480
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1397
1481
|
generation,
|
|
1398
1482
|
prepareCall: () => {
|
|
1399
1483
|
var _a;
|
|
@@ -1401,10 +1485,7 @@ class ElectronBleTransport {
|
|
|
1401
1485
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1402
1486
|
this.resetProtocolV2Frames(uuid);
|
|
1403
1487
|
},
|
|
1404
|
-
writeFrame: (frame) =>
|
|
1405
|
-
assertCurrentGeneration();
|
|
1406
|
-
return this.writeWithChunking(uuid, transport.bytesToHex(frame));
|
|
1407
|
-
},
|
|
1488
|
+
writeFrame: (frame, context) => this.writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration),
|
|
1408
1489
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1409
1490
|
assertCurrentGeneration();
|
|
1410
1491
|
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
@@ -1424,6 +1505,7 @@ class ElectronBleTransport {
|
|
|
1424
1505
|
};
|
|
1425
1506
|
}
|
|
1426
1507
|
processProtocolV1Notification(deviceId, hexData) {
|
|
1508
|
+
var _a;
|
|
1427
1509
|
try {
|
|
1428
1510
|
if (typeof hexData !== 'string') {
|
|
1429
1511
|
return { isComplete: false, error: 'Invalid hexData type' };
|
|
@@ -1442,6 +1524,10 @@ class ElectronBleTransport {
|
|
|
1442
1524
|
bufferState.buffer = [...data.subarray(3)];
|
|
1443
1525
|
}
|
|
1444
1526
|
else {
|
|
1527
|
+
if (bufferState.buffer.length === 0) {
|
|
1528
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Orphan continuation chunk discarded');
|
|
1529
|
+
return { isComplete: false };
|
|
1530
|
+
}
|
|
1445
1531
|
bufferState.buffer = bufferState.buffer.concat([...data]);
|
|
1446
1532
|
}
|
|
1447
1533
|
if (bufferState.buffer.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferState.bufferLength) {
|