diff --git a/js/modules/loki_message_api.js b/js/modules/loki_message_api.js index a53ead433..0264e3d0a 100644 --- a/js/modules/loki_message_api.js +++ b/js/modules/loki_message_api.js @@ -5,7 +5,8 @@ const _ = require('lodash'); const { rpc } = require('./loki_rpc'); -const DEFAULT_CONNECTIONS = 2; +const DEFAULT_CONNECTIONS = 3; +const MAX_ACCEPTABLE_FAILURES = 1; const LOKI_LONGPOLL_HEADER = 'X-Loki-Long-Poll'; function sleepFor(time) { @@ -122,9 +123,27 @@ class LokiMessageAPI { promises.push(this.openSendConnection(params)); } - let results; + // Taken from https://stackoverflow.com/questions/51160260/clean-way-to-wait-for-first-true-returned-by-promise + // The promise returned by this function will resolve true when the first promise + // in ps resolves true *or* it will resolve false when all of ps resolve false + const firstTrue = ps => { + const newPs = ps.map( + p => + new Promise( + // eslint-disable-next-line more/no-then + (resolve, reject) => p.then(v => v && resolve(true), reject) + ) + ); + // eslint-disable-next-line more/no-then + newPs.push(Promise.all(ps).then(() => false)); + return Promise.race(newPs); + }; + + let success; try { - results = await Promise.all(promises); + // eslint-disable-next-line more/no-then + Promise.all(promises).then(delete this.sendingSwarmNodes[timestamp]); + success = await firstTrue(promises); } catch (e) { if (e instanceof textsecure.WrongDifficultyError) { // Force nonce recalculation @@ -133,18 +152,13 @@ class LokiMessageAPI { } throw e; } - delete this.sendingSwarmNodes[timestamp]; - if (results.every(value => value === false)) { + if (!success) { throw new window.textsecure.EmptySwarmError( pubKey, 'Ran out of swarm nodes to query' ); } - if (results.every(value => value === true)) { - log.info(`Successful storage message to ${pubKey}`); - } else { - log.warn(`Partially successful storage message to ${pubKey}`); - } + log.info(`Successful storage message to ${pubKey}`); } async openSendConnection(params) { @@ -165,7 +179,7 @@ class LokiMessageAPI { async sendToNode(address, port, params) { let successiveFailures = 0; - while (successiveFailures < 3) { + while (successiveFailures < MAX_ACCEPTABLE_FAILURES) { await sleepFor(successiveFailures * 500); try { const result = await rpc(`https://${address}`, port, 'store', params); @@ -212,7 +226,7 @@ class LokiMessageAPI { const nodeData = this.ourSwarmNodes[address]; delete this.ourSwarmNodes[address]; let successiveFailures = 0; - while (successiveFailures < 3) { + while (successiveFailures < MAX_ACCEPTABLE_FAILURES) { await sleepFor(successiveFailures * 1000); try { diff --git a/libloki/api.js b/libloki/api.js index e092da1c2..d51031081 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -14,8 +14,7 @@ ); await Promise.all( friendKeys.map(async pubKey => { - if (pubKey === textsecure.storage.user.getNumber()) - return + if (pubKey === textsecure.storage.user.getNumber()) return; try { await sendOnlineBroadcastMessage(pubKey); } catch (e) {