|
|
|
@ -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 {
|
|
|
|
|