@trezor/connect-common
Version:
Collection of assets and utils used by trezor-connect library.
146 lines • 4.97 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractMessageChannel = void 0;
const utils_1 = require("@trezor/utils");
class AbstractMessageChannel extends utils_1.TypedEmitter {
messagePromises = {};
messagesQueue = [];
messageID = 0;
isConnected = false;
handshakeMaxRetries = 5;
handshakeRetryInterval = 2000;
handshakeFinished;
lazyHandshake;
legacyMode;
logger;
sendFn;
channel;
constructor({ sendFn, channel, logger, lazyHandshake = false, legacyMode = false, }) {
super();
this.channel = channel;
this.sendFn = sendFn;
this.lazyHandshake = lazyHandshake;
this.legacyMode = legacyMode;
this.logger = logger;
}
init() {
if (!this.handshakeFinished) {
this.handshakeFinished = (0, utils_1.createDeferred)();
if (this.legacyMode) {
setTimeout(() => {
this.handshakeFinished?.resolve();
}, 500);
}
if (!this.lazyHandshake) {
this.handshakeWithPeer();
}
}
return this.handshakeFinished.promise;
}
handshakeWithPeer() {
this.logger?.log(this.channel.here, 'handshake');
return (0, utils_1.scheduleAction)(async () => {
this.postMessage({
type: 'channel-handshake-request',
data: { success: true, payload: undefined },
}, { usePromise: false, useQueue: false });
await this.handshakeFinished?.promise;
}, {
attempts: this.handshakeMaxRetries,
timeout: this.handshakeRetryInterval,
})
.then(() => {
this.logger?.log(this.channel.here, 'handshake confirmed');
this.messagesQueue.forEach(message => {
message.channel = this.channel;
this.sendFn(message);
});
this.messagesQueue = [];
})
.catch(() => {
this.handshakeFinished?.reject(new Error('handshake failed'));
this.handshakeFinished = undefined;
});
}
onMessage(_message) {
let message = _message;
if (this.legacyMode &&
message.type === undefined &&
'data' in message &&
typeof message.data === 'object' &&
message.data !== null &&
'type' in message.data &&
typeof message.data.type === 'string') {
message = message.data;
}
const { channel, id, type, ...data } = message;
if (!this.legacyMode) {
if (!channel?.peer || channel.peer !== this.channel.here) {
return;
}
if (!channel?.here || this.channel.peer !== channel.here) {
return;
}
}
if (type === 'channel-handshake-request') {
this.postMessage({
type: 'channel-handshake-confirm',
data: { success: true, payload: undefined },
}, { usePromise: false, useQueue: false });
if (this.lazyHandshake) {
this.handshakeWithPeer();
}
return;
}
if (type === 'channel-handshake-confirm') {
this.handshakeFinished?.resolve(undefined);
return;
}
if (this.messagePromises[id]) {
this.messagePromises[id].resolve({ id, ...data });
delete this.messagePromises[id];
}
const messagePromisesLength = Object.keys(this.messagePromises).length;
if (messagePromisesLength > 5) {
this.logger?.warn(`too many message promises (${messagePromisesLength}). this feels unexpected!`);
}
this.emit('message', message);
}
postMessage(message, { usePromise = true, useQueue = true } = {}) {
message.channel = this.channel;
if (!usePromise) {
try {
this.sendFn(message);
}
catch {
if (useQueue) {
this.messagesQueue.push(message);
}
}
return;
}
this.messageID++;
message.id = this.messageID;
this.messagePromises[message.id] = (0, utils_1.createDeferred)();
try {
this.sendFn(message);
}
catch {
if (useQueue) {
this.messagesQueue.push(message);
}
}
return this.messagePromises[message.id].promise;
}
resolveMessagePromises(resolvePayload) {
Object.keys(this.messagePromises).forEach(id => this.messagePromises[id].resolve({
id,
payload: resolvePayload,
}));
}
clear() {
this.handshakeFinished = undefined;
}
}
exports.AbstractMessageChannel = AbstractMessageChannel;
//# sourceMappingURL=abstract.js.map