diff --git a/packages/hw-transport-node-hid-singleton/src/TransportNodeHid.ts b/packages/hw-transport-node-hid-singleton/src/TransportNodeHid.ts index ecfa18ccd..30dbb4e54 100644 --- a/packages/hw-transport-node-hid-singleton/src/TransportNodeHid.ts +++ b/packages/hw-transport-node-hid-singleton/src/TransportNodeHid.ts @@ -12,6 +12,22 @@ import { identifyUSBProductId } from "@ledgerhq/devices"; import { CantOpenDevice } from "@ledgerhq/errors"; import { listenDevices } from "./listenDevices"; let transportInstance; + +const DISCONNECT_TIMEOUT = 5000; +let disconnectTimeout; +const clearDisconnectTimeout = () => { + if (disconnectTimeout) { + clearTimeout(disconnectTimeout); + } +}; + +const setDisconnectTimeout = () => { + disconnectTimeout = setTimeout( + () => TransportNodeHidSingleton.disconnect(), + DISCONNECT_TIMEOUT + ); +}; + /** * node-hid Transport implementation * @example @@ -97,12 +113,14 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents transportInstance.emit("disconnect"); transportInstance = null; } + clearDisconnectTimeout(); } /** * if path="" is not provided, the library will take the first device */ static open(): Promise { + clearDisconnectTimeout(); return Promise.resolve().then(() => { if (transportInstance) { log("hid-verbose", "reusing opened transport instance"); @@ -138,7 +156,19 @@ export default class TransportNodeHidSingleton extends TransportNodeHidNoEvents }); } - close() { + /** + * Exchange with the device using APDU protocol. + * @param apdu + * @returns a promise of apdu response + */ + async exchange(apdu: Buffer): Promise { + clearDisconnectTimeout(); + const result = await super.exchange(apdu); + setDisconnectTimeout(); + return result; + } + + close(): Promise { // intentionally, a close will not effectively close the hid connection return Promise.resolve(); }