UNPKG

@trezor/connect

Version:

High-level javascript interface for Trezor hardware wallet.

150 lines (149 loc) 4.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TransportManager = void 0; const transport_1 = require("@trezor/transport"); const utils_1 = require("@trezor/utils"); const createOverrideLock = () => { let promise; let sequence = 0; let abort; let message; const override = async (abortMessage, action) => { message = abortMessage; const seq = ++sequence; while (promise) { abort?.abort(new Error(abortMessage)); await promise.catch(() => {}); } if (seq !== sequence) return Promise.reject(new Error(message)); abort = new AbortController(); promise = action(abort.signal).finally(() => { abort = undefined; promise = undefined; }); return promise; }; const getPending = () => promise; return { override, getPending }; }; class TransportManager extends utils_1.TypedEmitter { lock = createOverrideLock(); transports = []; activeTransport; transportReconnect = false; upgradeTimeout; startTransport; constructor(startTransport) { super(); this.startTransport = startTransport; } pending() { return this.lock.getPending(); } get() { return this.activeTransport; } init({ transports, transportReconnect = false, pendingTransportEvent = false }) { this.transports = transports; this.transportReconnect = transportReconnect; return this.lock.override('New init', signal => this.createInitPromise(pendingTransportEvent, signal)); } dispose() { this.removeAllListeners(); return this.lock.override('Disposing', () => { const { activeTransport } = this; if (activeTransport) { clearTimeout(this.upgradeTimeout); delete this.activeTransport; activeTransport.stop(); } return Promise.resolve(); }); } async selectTransport([transport, ...rest], signal) { if (signal.aborted) throw new Error(signal.reason); if (transport === this.activeTransport) return transport; const result = await transport.init({ signal }); if (result.success) return transport;else if (rest.length) return this.selectTransport(rest, signal);else throw new Error(result.error); } scheduleUpgradeCheck(pendingTransportEvent) { clearTimeout(this.upgradeTimeout); this.upgradeTimeout = setTimeout(async () => { if (!this.activeTransport || this.activeTransport === this.transports[0]) return; for (const t of this.transports) { if (t === this.activeTransport) break; if (await t.ping()) { this.lock.override('Upgrading', signal => this.createInitPromise(pendingTransportEvent, signal)).catch(() => {}); return; } } this.scheduleUpgradeCheck(pendingTransportEvent); }, 1000); } async createInitPromise(pendingTransportEvent, abortSignal) { try { const { transports, activeTransport } = this; const transport = transports.length ? await this.selectTransport(transports, abortSignal) : undefined; if (activeTransport !== transport) { if (activeTransport) { clearTimeout(this.upgradeTimeout); delete this.activeTransport; activeTransport.stop(); } if (transport) { try { await this.startTransport(transport, pendingTransportEvent, abortSignal); } catch (err) { transport.stop(); throw err; } transport.on(transport_1.TRANSPORT.ERROR, error => { this.emit(transport_1.TRANSPORT.ERROR, error); clearTimeout(this.upgradeTimeout); this.lock.override('Transport error', async signal => { delete this.activeTransport; transport.stop(); if (this.transportReconnect) { await (0, utils_1.resolveAfter)(1000, signal); await this.createInitPromise(pendingTransportEvent, signal); } }).catch(() => {}); }); this.activeTransport = transport; this.emit(transport_1.TRANSPORT.START, transport); } else { this.emit(transport_1.TRANSPORT.ERROR, 'Transport disabled'); } } if (transport && transport !== transports[0]) { this.scheduleUpgradeCheck(pendingTransportEvent); } } catch (error) { this.emit(transport_1.TRANSPORT.ERROR, error?.message); if (this.transportReconnect && !abortSignal.aborted) { this.lock.override('Reconnecting', async signal => { await (0, utils_1.resolveAfter)(1000, signal); await this.createInitPromise(pendingTransportEvent, signal); }).catch(() => {}); } } } } exports.TransportManager = TransportManager; //# sourceMappingURL=TransportManager.js.map