UNPKG

@trezor/transport

Version:

Low level library facilitating protocol buffers based communication with Trezor devices

137 lines 4.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AbstractTransport = exports.isTransportInstance = void 0; const tslib_1 = require("tslib"); const protobuf_1 = require("@trezor/protobuf"); const utils_1 = require("@trezor/utils"); const constants_1 = require("../constants"); const ERRORS = tslib_1.__importStar(require("../errors")); const result_1 = require("../utils/result"); const isTransportInstance = (transport) => { const requiredMethods = [ 'init', 'enumerate', 'listen', 'acquire', 'release', 'send', 'receive', 'call', ]; if (transport && typeof transport === 'object') { return !requiredMethods.some(m => typeof transport[m] !== 'function'); } return false; }; exports.isTransportInstance = isTransportInstance; const getKey = ({ path, product }) => `${path}${product}`; class AbstractTransport extends utils_1.TypedEmitter { isOutdated = false; version = ''; stopped = true; listening = false; messages; descriptors; abortController; logger; id; deviceEvents; constructor({ messages, logger, id }) { super(); this.descriptors = []; this.messages = (0, protobuf_1.parseConfigure)(messages); this.abortController = new AbortController(); this.logger = logger; this.id = id; this.deviceEvents = new utils_1.TypedEmitter(); } ping(_params) { return Promise.resolve(false); } stop() { this.emit(constants_1.TRANSPORT.STOPPED); this.removeAllListeners(); this.deviceEvents.removeAllListeners(); this.stopped = true; this.listening = false; this.abortController.abort(); this.abortController = new AbortController(); this.descriptors = []; } handleDescriptorsChange(nextDescriptors) { if (this.stopped) { return; } const oldDescriptors = new Map(this.descriptors.map(d => [getKey(d), d])); const newDescriptors = new Map(nextDescriptors.map(d => [getKey(d), d])); this.descriptors .filter(d => !newDescriptors.has(getKey(d))) .forEach(descriptor => this.deviceEvents.emit(descriptor.path, { type: constants_1.TRANSPORT.DEVICE_DISCONNECTED })); nextDescriptors.forEach(descriptor => { const prevDescriptor = oldDescriptors.get(getKey(descriptor)); if (!prevDescriptor) { this.emit(constants_1.TRANSPORT.DEVICE_CONNECTED, descriptor); } else if (prevDescriptor.session !== descriptor.session) { this.deviceEvents.emit(descriptor.path, { type: constants_1.TRANSPORT.DEVICE_SESSION_CHANGED, descriptor, }); } }); this.descriptors = nextDescriptors; } getDescriptor(path) { return this.descriptors.find(d => d.path === path); } getMessage(message = 'GetFeatures') { return !!this.messages.get(message); } getMessages() { return this.messages; } updateMessages(messages) { this.messages = (0, protobuf_1.parseConfigure)(messages); } loadMessages(packageName, packageLoader) { return (0, protobuf_1.loadDefinitions)(this.messages, packageName, packageLoader); } success(payload) { return (0, result_1.success)(payload); } error(payload) { return (0, result_1.error)(payload); } unknownError = (err, expectedErrors = []) => { this.logger?.error(this.name, 'unexpected error: ', err); return (0, result_1.unknownError)(typeof err !== 'string' ? err : new Error(err), expectedErrors); }; mergeAbort(signal) { if (!signal) { return { signal: this.abortController.signal, clear: () => { } }; } const controller = new AbortController(); const onAbort = () => controller.abort(); signal.addEventListener('abort', onAbort); if (signal.aborted) controller.abort(signal.reason); this.abortController.signal.addEventListener('abort', onAbort); const clear = () => { signal.removeEventListener('abort', onAbort); this.abortController.signal.removeEventListener('abort', onAbort); }; return { signal: controller.signal, clear }; } scheduleAction = (action, params, errors = []) => { const { signal, clear } = this.mergeAbort(params?.signal); return (0, utils_1.scheduleAction)(action, { timeout: constants_1.ACTION_TIMEOUT, ...params, signal, }) .catch(err => (0, result_1.unknownError)(err, [ERRORS.ABORTED_BY_TIMEOUT, ERRORS.ABORTED_BY_SIGNAL, ...errors])) .finally(clear); }; } exports.AbstractTransport = AbstractTransport; //# sourceMappingURL=abstract.js.map