@trezor/transport
Version:
Low level library facilitating protocol buffers based communication with Trezor devices
137 lines • 4.99 kB
JavaScript
;
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