Skip to content

Commit 56e5b94

Browse files
committed
πŸ‘” (webhid): Update reconnection logic
1 parent 760f6e5 commit 56e5b94

File tree

2 files changed

+35
-19
lines changed

2 files changed

+35
-19
lines changed

β€Žpackages/transport/web-hid/src/api/transport/WebHidDeviceConnection.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
import { Left, Right } from "purify-ts";
1212

1313
import { RECONNECT_DEVICE_TIMEOUT } from "@api/data/WebHidConfig";
14-
import { WebHidSendReportError } from "@api/model/Errors";
1514
import { hidDeviceStubBuilder } from "@api/model/HIDDevice.stub";
1615

1716
import { WebHidDeviceConnection } from "./WebHidDeviceConnection";
@@ -130,12 +129,14 @@ describe("WebHidDeviceConnection", () => {
130129
} as HIDInputReportEvent),
131130
),
132131
);
132+
133133
const connection = new WebHidDeviceConnection(
134134
{ device, apduSender, apduReceiver, onConnectionTerminated, deviceId },
135135
logger,
136136
);
137137

138138
let hasResolved = false;
139+
139140
const responsePromise = connection
140141
.sendApdu(Uint8Array.from([]), true)
141142
.then((response) => {
@@ -283,7 +284,12 @@ describe("WebHidDeviceConnection", () => {
283284

284285
const response = await responsePromise;
285286

286-
expect(response).toEqual(Left(new WebHidSendReportError()));
287+
expect(response).toEqual(
288+
Right({
289+
statusCode: new Uint8Array([0x55, 0x15]),
290+
data: new Uint8Array([]),
291+
}),
292+
);
287293
});
288294
});
289295
});

β€Žpackages/transport/web-hid/src/api/transport/WebHidDeviceConnection.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ export class WebHidDeviceConnection implements DeviceConnection {
4747
private waitingForReconnection = false;
4848
/** Timeout to wait for the device to reconnect */
4949
private lostConnectionTimeout: Timer | null = null;
50-
/** Time since disconnection */
51-
private timeSinceDisconnection: Maybe<number> = Nothing;
50+
/** Timestamp when the device was reconnected */
51+
private timeOfReconnection: Maybe<number> = Nothing;
5252
/** Flag to indicate if the connection is terminated */
5353
private terminated = false;
5454

@@ -133,6 +133,9 @@ export class WebHidDeviceConnection implements DeviceConnection {
133133
this._logger.debug("Sending Frame", {
134134
data: { frame: frame.getRawData() },
135135
});
136+
137+
await this.waitUntilDeviceIsReady();
138+
136139
try {
137140
await this._device.sendReport(0, frame.getRawData());
138141
} catch (error) {
@@ -144,6 +147,18 @@ export class WebHidDeviceConnection implements DeviceConnection {
144147
return resultPromise;
145148
}
146149

150+
private async waitUntilDeviceIsReady() {
151+
if (this.timeOfReconnection.isJust()) {
152+
const timeSinceReconnection =
153+
Date.now() - this.timeOfReconnection.extract();
154+
if (timeSinceReconnection < 3000) {
155+
await new Promise((res) =>
156+
setTimeout(() => res(undefined), 3000 - timeSinceReconnection),
157+
);
158+
}
159+
}
160+
}
161+
147162
private receiveHidInputReport(event: HIDInputReportEvent) {
148163
const data = new Uint8Array(event.data.buffer);
149164
this._logger.debug("Received Frame", {
@@ -178,14 +193,21 @@ export class WebHidDeviceConnection implements DeviceConnection {
178193
const sub = this.reconnectionSubject.subscribe({
179194
next: (res) => {
180195
if (waitingForDeviceResponse) {
181-
this._sendApduSubject.error(new WebHidSendReportError());
196+
this._sendApduSubject.error(
197+
new WebHidSendReportError(
198+
new Error(
199+
"Device disconnected while waiting for device repsonse",
200+
),
201+
),
202+
);
182203
}
183204

184205
if (res === "success") {
185206
resolve(Right(undefined));
186207
} else {
187208
resolve(Left(res));
188209
}
210+
189211
sub.unsubscribe();
190212
},
191213
});
@@ -198,7 +220,6 @@ export class WebHidDeviceConnection implements DeviceConnection {
198220
* */
199221
public lostConnection() {
200222
this._logger.info("⏱️ Lost connection, starting timer");
201-
this.timeSinceDisconnection = Maybe.of(Date.now());
202223
this.waitingForReconnection = true;
203224
this.lostConnectionTimeout = setTimeout(() => {
204225
this._logger.info("❌ Disconnection timeout, terminating connection");
@@ -212,24 +233,13 @@ export class WebHidDeviceConnection implements DeviceConnection {
212233
this._device.oninputreport = (event) => this.receiveHidInputReport(event);
213234

214235
if (this.lostConnectionTimeout) {
215-
this._logger.info("β±οΈπŸ”Œ Device reconnected");
216236
clearTimeout(this.lostConnectionTimeout);
217237
}
218238

219239
await device.open();
240+
this._logger.info("β±οΈπŸ”Œ Device reconnected");
220241

221-
if (this._pendingApdu.isJust()) {
222-
if (this.timeSinceDisconnection.isJust()) {
223-
const now = Date.now();
224-
const timeSinceDisconnection =
225-
now - this.timeSinceDisconnection.extract();
226-
// 3 seconds timeout
227-
if (timeSinceDisconnection > RECONNECT_DEVICE_TIMEOUT / 2) {
228-
this._sendApduSubject.error(new WebHidSendReportError());
229-
}
230-
}
231-
this.timeSinceDisconnection = Nothing;
232-
}
242+
this.timeOfReconnection = Maybe.of(Date.now());
233243

234244
this.waitingForReconnection = false;
235245
this.reconnectionSubject.next("success");

0 commit comments

Comments
Β (0)