@trezor/connect-common
Version:
Collection of assets and utils used by trezor-connect library.
168 lines (167 loc) • 4.41 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