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..2041da741 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,18 @@ 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((_error) => { + console.log("sendApduUseCase:Got error", _error); 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..6a9466241 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,7 +91,15 @@ export class WebHidDeviceConnection implements DeviceConnection { (resolve) => { this._sendApduSubject.subscribe({ next: async (r) => { + this._logger.info("Received APDU Response", { + data: { response: r }, + }); + this._pendingApdu = Nothing; + this._logger.info("Next: Setting pending apdu to Nothing"); if (triggersDisconnection && CommandUtils.isSuccessResponse(r)) { + this._logger.info( + "Triggers disconnection, waiting for reconnection", + ); // Anticipate the disconnection and wait for the reconnection before resolving const reconnectionRes = await this.waitForReconnection(); reconnectionRes.caseOf({ @@ -102,14 +111,30 @@ export class WebHidDeviceConnection implements DeviceConnection { } }, error: (err) => { + this._pendingApdu = Nothing; + this._logger.info("Error: Setting pending apdu to Nothing"); resolve(Left(err)); }, }); }, ); + this._logger.info("sendApdu:Waiting for reconnection", { + data: { waitingForReconnection: this.waitingForReconnection }, + }); + this._logger.info("sendApdu:Device opened", { + data: { opened: this.device.opened }, + }); + if (this.waitingForReconnection || !this.device.opened) { - const reconnectionRes = await this.waitForReconnection(); + this._logger.info("sendApdu:Waiting for reconnection"); + const waitingForDeviceResponse = + this.device.opened && this._pendingApdu.isJust(); + + const reconnectionRes = await this.waitForReconnection( + waitingForDeviceResponse, + ); + if (reconnectionRes.isLeft()) { return reconnectionRes; } @@ -154,12 +179,37 @@ export class WebHidDeviceConnection implements DeviceConnection { }); } - private waitForReconnection(): Promise> { - if (this.terminated) + private waitForReconnection( + waitingForDeviceResponse: boolean = false, + ): Promise> { + this._logger.info("waitForReconnection:Started", { + data: { waitingForDeviceResponse }, + }); + if (this.terminated) { return Promise.resolve(Left(new ReconnectionFailedError())); + } + return new Promise>((resolve) => { const sub = this.reconnectionSubject.subscribe({ - next: (res) => { + next: async (res) => { + this._logger.info("waitForReconnection:Waiting for device response", { + data: { + waitingForDeviceResponse, + pendingApdu: this._pendingApdu.extract(), + }, + }); + + if (waitingForDeviceResponse) { + this._sendApduSubject.error(new WebHidSendReportError()); + } + + if (this._pendingApdu.isJust()) { + this._logger.info( + "waitForReconnection:Pending apdu is just, resending APDU", + ); + await this.sendApdu(this._pendingApdu.extract()); + } + if (res === "success") { resolve(Right(undefined)); } else {