From 09e9d517ac8fb3e13d65adec5d16fef0a3ae333c Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 31 Dec 2024 14:19:58 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=94=20(dmk):=20DeviceSession=20fix=20+?= =?UTF-8?q?=20WebHidTransport=20reconnection=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/grumpy-tables-taste.md | 5 +++ .changeset/ten-lions-report.md | 5 +++ .../device-session/model/DeviceSession.ts | 16 +++++---- .../api/transport/WebHidDeviceConnection.ts | 33 ++++++++++++++++--- 4 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 .changeset/grumpy-tables-taste.md create mode 100644 .changeset/ten-lions-report.md diff --git a/.changeset/grumpy-tables-taste.md b/.changeset/grumpy-tables-taste.md new file mode 100644 index 000000000..aacdc98fd --- /dev/null +++ b/.changeset/grumpy-tables-taste.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/device-transport-kit-web-hid": patch +--- + +Update WebHidDeviceConnection to throw an error in case of a reconnect diff --git a/.changeset/ten-lions-report.md b/.changeset/ten-lions-report.md new file mode 100644 index 000000000..db56a55e5 --- /dev/null +++ b/.changeset/ten-lions-report.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/device-management-kit": patch +--- + +Update DeviceSession to change the state of the device in case of an error diff --git a/packages/device-management-kit/src/internal/device-session/model/DeviceSession.ts b/packages/device-management-kit/src/internal/device-session/model/DeviceSession.ts index 0b9d22996..b83cc3927 100644 --- a/packages/device-management-kit/src/internal/device-session/model/DeviceSession.ts +++ b/packages/device-management-kit/src/internal/device-session/model/DeviceSession.ts @@ -120,13 +120,17 @@ export class DeviceSession { options.triggersDisconnection, ); - return errorOrResponse.ifRight((response: ApduResponse) => { - if (CommandUtils.isLockedDeviceResponse(response)) { - this.updateDeviceStatus(DeviceStatus.LOCKED); - } else { + return errorOrResponse + .ifRight((response: ApduResponse) => { + if (CommandUtils.isLockedDeviceResponse(response)) { + this.updateDeviceStatus(DeviceStatus.LOCKED); + } else { + this.updateDeviceStatus(DeviceStatus.CONNECTED); + } + }) + .ifLeft(() => { this.updateDeviceStatus(DeviceStatus.CONNECTED); - } - }); + }); } async sendCommand( diff --git a/packages/transport/web-hid/src/api/transport/WebHidDeviceConnection.ts b/packages/transport/web-hid/src/api/transport/WebHidDeviceConnection.ts index 1fb09cea9..fd0da7e4c 100644 --- a/packages/transport/web-hid/src/api/transport/WebHidDeviceConnection.ts +++ b/packages/transport/web-hid/src/api/transport/WebHidDeviceConnection.ts @@ -9,7 +9,7 @@ import { type LoggerPublisherService, ReconnectionFailedError, } from "@ledgerhq/device-management-kit"; -import { type Either, Left, Right } from "purify-ts"; +import { type Either, Left, Maybe, Nothing, Right } from "purify-ts"; import { Subject } from "rxjs"; import { RECONNECT_DEVICE_TIMEOUT } from "@api/data/WebHidConfig"; @@ -35,6 +35,7 @@ export class WebHidDeviceConnection implements DeviceConnection { private readonly _apduReceiver: ApduReceiverService; private _sendApduSubject: Subject = new Subject(); private readonly _logger: LoggerPublisherService; + private _pendingApdu: Maybe = Nothing; /** Callback to notify the connection termination */ private _onConnectionTerminated: () => void; @@ -80,7 +81,7 @@ export class WebHidDeviceConnection implements DeviceConnection { triggersDisconnection?: boolean, ): Promise> { this._sendApduSubject = new Subject(); - + this._pendingApdu = Maybe.of(apdu); this._logger.debug("Sending APDU", { data: { apdu }, tag: "apdu-sender", @@ -90,6 +91,7 @@ export class WebHidDeviceConnection implements DeviceConnection { (resolve) => { this._sendApduSubject.subscribe({ next: async (r) => { + this._pendingApdu = Nothing; if (triggersDisconnection && CommandUtils.isSuccessResponse(r)) { // Anticipate the disconnection and wait for the reconnection before resolving const reconnectionRes = await this.waitForReconnection(); @@ -102,6 +104,7 @@ export class WebHidDeviceConnection implements DeviceConnection { } }, error: (err) => { + this._pendingApdu = Nothing; resolve(Left(err)); }, }); @@ -109,7 +112,13 @@ export class WebHidDeviceConnection implements DeviceConnection { ); if (this.waitingForReconnection || !this.device.opened) { - const reconnectionRes = await this.waitForReconnection(); + const waitingForDeviceResponse = + this.device.opened && this._pendingApdu.isJust(); + + const reconnectionRes = await this.waitForReconnection( + waitingForDeviceResponse, + ); + if (reconnectionRes.isLeft()) { return reconnectionRes; } @@ -154,12 +163,20 @@ export class WebHidDeviceConnection implements DeviceConnection { }); } - private waitForReconnection(): Promise> { - if (this.terminated) + private waitForReconnection( + waitingForDeviceResponse: boolean = false, + ): Promise> { + if (this.terminated) { return Promise.resolve(Left(new ReconnectionFailedError())); + } + return new Promise>((resolve) => { const sub = this.reconnectionSubject.subscribe({ next: (res) => { + if (waitingForDeviceResponse) { + this._sendApduSubject.error(new WebHidSendReportError()); + } + if (res === "success") { resolve(Right(undefined)); } else { @@ -193,7 +210,13 @@ export class WebHidDeviceConnection implements DeviceConnection { this._logger.info("⏱️🔌 Device reconnected"); clearTimeout(this.lostConnectionTimeout); } + await device.open(); + + if (this._pendingApdu.isJust()) { + this._sendApduSubject.error(new WebHidSendReportError()); + } + this.waitingForReconnection = false; this.reconnectionSubject.next("success"); }