From 5d823de6f976ea51d87d5fad8f9785505e44e46c Mon Sep 17 00:00:00 2001 From: Beaudan Date: Mon, 11 Feb 2019 13:57:22 +1100 Subject: [PATCH 1/3] Renamed lokiSnodeAPI to start with lower case for consistency, refactor snode API to use conversation controller --- js/conversation_controller.js | 8 +++--- js/models/conversations.js | 8 +++++- js/modules/loki_message_api.js | 24 ++++++++--------- js/modules/loki_snode_api.js | 48 +++++++++++++++++++++++++--------- preload.js | 2 +- 5 files changed, 58 insertions(+), 32 deletions(-) diff --git a/js/conversation_controller.js b/js/conversation_controller.js index 7a15d689a..796dd20ed 100644 --- a/js/conversation_controller.js +++ b/js/conversation_controller.js @@ -185,7 +185,6 @@ await window.Signal.Data.saveConversation(conversation.attributes, { Conversation: Whisper.Conversation, }); - window.LokiSnodeAPI.refreshSwarmNodesForPubKey(id); } catch (error) { window.log.error( 'Conversation save failed! ', @@ -200,9 +199,10 @@ return conversation; }; - conversation.initialPromise = create().then(() => - conversation.updateProfileAvatar() - ); + conversation.initialPromise = create().then(async () => { + window.lokiSnodeAPI.refreshSwarmNodesForPubKey(id); + conversation.updateProfileAvatar(); + }); return conversation; }, diff --git a/js/models/conversations.js b/js/models/conversations.js index 91c3616c1..d8709a37c 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -78,7 +78,7 @@ friendRequestStatus: FriendRequestStatusEnum.none, unlockTimestamp: null, // Timestamp used for expiring friend requests. sessionResetStatus: SessionResetEnum.none, - swarmNodes: new Set([]), + swarmNodes: [], isOnline: false, }; }, @@ -1406,6 +1406,12 @@ }, }; }, + async updateSwarmNodes(swarmNodes) { + this.set({ swarmNodes }); + await window.Signal.Data.updateConversation(this.id, this.attributes, { + Conversation: Whisper.Conversation, + }); + }, async updateLastMessage() { if (!this.id) { return; diff --git a/js/modules/loki_message_api.js b/js/modules/loki_message_api.js index e802dab13..e91812cc3 100644 --- a/js/modules/loki_message_api.js +++ b/js/modules/loki_message_api.js @@ -1,6 +1,6 @@ /* eslint-disable no-await-in-loop */ /* eslint-disable no-loop-func */ -/* global log, dcodeIO, window, callWorker, Whisper, lokiP2pAPI */ +/* global log, dcodeIO, window, callWorker, lokiP2pAPI, lokiSnodeAPI */ const nodeFetch = require('node-fetch'); const _ = require('lodash'); @@ -109,7 +109,7 @@ class LokiMessageAPI { let successfulRequests = 0; let canResolve = true; - let swarmNodes = await window.Signal.Data.getSwarmNodesByPubkey(pubKey); + let swarmNodes = await lokiSnodeAPI.getSwarmNodesForPubKey(pubKey); const nodeComplete = nodeUrl => { completedNodes.push(nodeUrl); @@ -148,7 +148,7 @@ class LokiMessageAPI { nodeComplete(nodeUrl); } else { log.error('Loki SendMessages:', e); - if (window.LokiSnodeAPI.unreachableNode(pubKey, nodeUrl)) { + if (lokiSnodeAPI.unreachableNode(pubKey, nodeUrl)) { nodeComplete(nodeUrl); } } @@ -160,7 +160,7 @@ class LokiMessageAPI { throw new window.textsecure.DNSResolutionError('Sending messages'); } if (swarmNodes.length === 0) { - const freshNodes = await window.LokiSnodeAPI.getFreshSwarmNodes(pubKey); + const freshNodes = await lokiSnodeAPI.getFreshSwarmNodes(pubKey); swarmNodes = _.difference(freshNodes, completedNodes); if (swarmNodes.length === 0) { if (successfulRequests !== 0) { @@ -172,13 +172,11 @@ class LokiMessageAPI { new Error('Ran out of swarm nodes to query') ); } - await window.Signal.Data.saveSwarmNodesForPubKey(pubKey, swarmNodes, { - Conversation: Whisper.Conversation, - }); + lokiSnodeAPI.updateSwarmNodes(pubKey, swarmNodes); } const remainingRequests = - MINIMUM_SUCCESSFUL_REQUESTS - completedNodes.length; + MINIMUM_SUCCESSFUL_REQUESTS - successfulRequests; await Promise.all( swarmNodes @@ -196,7 +194,7 @@ class LokiMessageAPI { let ourSwarmNodes; try { - ourSwarmNodes = await window.LokiSnodeAPI.getOurSwarmNodes(); + ourSwarmNodes = await lokiSnodeAPI.getOurSwarmNodes(); } catch (e) { throw new window.textsecure.EmptySwarmError(ourKey, e); } @@ -224,7 +222,7 @@ class LokiMessageAPI { nodeComplete(nodeUrl); if (result.lastHash) { - window.LokiSnodeAPI.updateLastHash(nodeUrl, result.lastHash); + lokiSnodeAPI.updateLastHash(nodeUrl, result.lastHash); callback(result.messages); } successfulRequests += 1; @@ -242,7 +240,7 @@ class LokiMessageAPI { nodeComplete(nodeUrl); } else { log.error('Loki RetrieveMessages:', e); - if (window.LokiSnodeAPI.unreachableNode(ourKey, nodeUrl)) { + if (lokiSnodeAPI.unreachableNode(ourKey, nodeUrl)) { nodeComplete(nodeUrl); } } @@ -255,7 +253,7 @@ class LokiMessageAPI { } if (Object.keys(ourSwarmNodes).length === 0) { try { - ourSwarmNodes = await window.LokiSnodeAPI.getOurSwarmNodes(); + ourSwarmNodes = await lokiSnodeAPI.getOurSwarmNodes(); // Filter out the nodes we have already got responses from completedNodes.forEach(nodeUrl => delete ourSwarmNodes[nodeUrl]); } catch (e) { @@ -277,7 +275,7 @@ class LokiMessageAPI { } const remainingRequests = - MINIMUM_SUCCESSFUL_REQUESTS - completedNodes.length; + MINIMUM_SUCCESSFUL_REQUESTS - successfulRequests; await Promise.all( Object.entries(ourSwarmNodes) diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 2fe719633..76e41e893 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -1,5 +1,5 @@ /* eslint-disable class-methods-use-this */ -/* global log, window, Whisper */ +/* global log, window, ConversationController */ const fetch = require('node-fetch'); const is = require('@sindresorhus/is'); @@ -58,17 +58,10 @@ class LokiSnodeAPI { if (this.contactSwarmNodes[nodeUrl].failureCount < FAILURE_THRESHOLD) { return false; } - const conversation = window.ConversationController.get(pubKey); + const conversation = ConversationController.get(pubKey); const swarmNodes = conversation.get('swarmNodes'); if (swarmNodes.delete(nodeUrl)) { - conversation.set({ swarmNodes }); - await window.Signal.Data.updateConversation( - conversation.id, - conversation.attributes, - { - Conversation: Whisper.Conversation, - } - ); + await conversation.updateSwarmNodes(swarmNodes); delete this.contactSwarmNodes[nodeUrl]; } return true; @@ -84,6 +77,32 @@ class LokiSnodeAPI { } } + async getSwarmNodesForPubKey(pubKey) { + let conversation; + let swarmNodes; + try { + conversation = ConversationController.get(pubKey); + swarmNodes = conversation.get('swarmNodes'); + } catch (e) { + throw new window.textsecure.ReplayableError({ + message: 'Could not get conversation', + }); + } + return swarmNodes; + } + + async updateSwarmNodes(pubKey, newNodes) { + let conversation; + try { + conversation = ConversationController.get(pubKey); + } catch (e) { + throw new window.textsecure.ReplayableError({ + message: 'Could not get conversation', + }); + } + await conversation.updateSwarmNodes(newNodes); + } + async getOurSwarmNodes() { if ( !this.ourSwarmNodes || @@ -108,9 +127,12 @@ class LokiSnodeAPI { async refreshSwarmNodesForPubKey(pubKey) { const newNodes = await this.getFreshSwarmNodes(pubKey); - await window.Signal.Data.saveSwarmNodesForPubKey(pubKey, newNodes, { - Conversation: Whisper.Conversation, - }); + try { + const conversation = ConversationController.get(pubKey); + await conversation.updateSwarmNodes(newNodes); + } catch (e) { + throw e; + } } async getFreshSwarmNodes(pubKey) { diff --git a/preload.js b/preload.js index 65a788d89..2b3e673b7 100644 --- a/preload.js +++ b/preload.js @@ -288,7 +288,7 @@ window.WebAPI = initializeWebAPI({ const LokiSnodeAPI = require('./js/modules/loki_snode_api'); -window.LokiSnodeAPI = new LokiSnodeAPI({ +window.lokiSnodeAPI = new LokiSnodeAPI({ url: config.serverUrl, swarmServerPort: config.swarmServerPort, }); From 2311bd132877928911fdf18d85579b764b799de0 Mon Sep 17 00:00:00 2001 From: Beaudan Date: Mon, 11 Feb 2019 16:32:15 +1100 Subject: [PATCH 2/3] Fix bug with swarm node reference, now we should only refresh swarm nodes when they fail --- js/conversation_controller.js | 7 ++++--- js/modules/data.js | 9 --------- js/modules/loki_message_api.js | 5 ++++- js/modules/loki_snode_api.js | 10 ++++++---- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/js/conversation_controller.js b/js/conversation_controller.js index 796dd20ed..6d3bd2bf9 100644 --- a/js/conversation_controller.js +++ b/js/conversation_controller.js @@ -199,9 +199,10 @@ return conversation; }; - conversation.initialPromise = create().then(async () => { - window.lokiSnodeAPI.refreshSwarmNodesForPubKey(id); - conversation.updateProfileAvatar(); + conversation.initialPromise = create(); + conversation.initialPromise.then(async () => { + await window.lokiSnodeAPI.refreshSwarmNodesForPubKey(id); + await conversation.updateProfileAvatar(); }); return conversation; diff --git a/js/modules/data.js b/js/modules/data.js index e850c723d..c9c3dddbb 100644 --- a/js/modules/data.js +++ b/js/modules/data.js @@ -111,7 +111,6 @@ module.exports = { removeAllSessions, getSwarmNodesByPubkey, - saveSwarmNodesForPubKey, getConversationCount, saveConversation, @@ -676,14 +675,6 @@ async function getSwarmNodesByPubkey(pubkey) { return channels.getSwarmNodesByPubkey(pubkey); } -async function saveSwarmNodesForPubKey(pubKey, swarmNodes, { Conversation }) { - const conversation = await getConversationById(pubKey, { Conversation }); - conversation.set({ swarmNodes }); - await updateConversation(conversation.id, conversation.attributes, { - Conversation, - }); -} - async function getConversationCount() { return channels.getConversationCount(); } diff --git a/js/modules/loki_message_api.js b/js/modules/loki_message_api.js index e91812cc3..5dcd82927 100644 --- a/js/modules/loki_message_api.js +++ b/js/modules/loki_message_api.js @@ -106,6 +106,7 @@ class LokiMessageAPI { throw err; } const completedNodes = []; + const failedNodes = []; let successfulRequests = 0; let canResolve = true; @@ -150,6 +151,7 @@ class LokiMessageAPI { log.error('Loki SendMessages:', e); if (lokiSnodeAPI.unreachableNode(pubKey, nodeUrl)) { nodeComplete(nodeUrl); + failedNodes.push(nodeUrl); } } } @@ -161,6 +163,8 @@ class LokiMessageAPI { } if (swarmNodes.length === 0) { const freshNodes = await lokiSnodeAPI.getFreshSwarmNodes(pubKey); + const goodNodes = _.difference(freshNodes, failedNodes); + await lokiSnodeAPI.updateSwarmNodes(pubKey, goodNodes); swarmNodes = _.difference(freshNodes, completedNodes); if (swarmNodes.length === 0) { if (successfulRequests !== 0) { @@ -172,7 +176,6 @@ class LokiMessageAPI { new Error('Ran out of swarm nodes to query') ); } - lokiSnodeAPI.updateSwarmNodes(pubKey, swarmNodes); } const remainingRequests = diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 76e41e893..209c8cd09 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -59,9 +59,10 @@ class LokiSnodeAPI { return false; } const conversation = ConversationController.get(pubKey); - const swarmNodes = conversation.get('swarmNodes'); - if (swarmNodes.delete(nodeUrl)) { - await conversation.updateSwarmNodes(swarmNodes); + const swarmNodes = [...conversation.get('swarmNodes')]; + if (nodeUrl in swarmNodes) { + const filteredNodes = swarmNodes.filter(node => node !== nodeUrl); + await conversation.updateSwarmNodes(filteredNodes); delete this.contactSwarmNodes[nodeUrl]; } return true; @@ -82,7 +83,7 @@ class LokiSnodeAPI { let swarmNodes; try { conversation = ConversationController.get(pubKey); - swarmNodes = conversation.get('swarmNodes'); + swarmNodes = [...conversation.get('swarmNodes')]; } catch (e) { throw new window.textsecure.ReplayableError({ message: 'Could not get conversation', @@ -143,6 +144,7 @@ class LokiSnodeAPI { newSwarmNodes = await this.getSwarmNodes(pubKey); } catch (e) { // TODO: Handle these errors sensibly + log.error('Failed to get new swarm nodes'); newSwarmNodes = []; } resolve(newSwarmNodes); From 2d9e6a7ac88cd902c6e3e18e9397bc074b1c5ed8 Mon Sep 17 00:00:00 2001 From: Beaudan Date: Mon, 11 Feb 2019 17:17:24 +1100 Subject: [PATCH 3/3] Review comments --- js/modules/loki_snode_api.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 209c8cd09..a93fb02ca 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -79,29 +79,26 @@ class LokiSnodeAPI { } async getSwarmNodesForPubKey(pubKey) { - let conversation; - let swarmNodes; try { - conversation = ConversationController.get(pubKey); - swarmNodes = [...conversation.get('swarmNodes')]; + const conversation = ConversationController.get(pubKey); + const swarmNodes = [...conversation.get('swarmNodes')]; + return swarmNodes; } catch (e) { throw new window.textsecure.ReplayableError({ message: 'Could not get conversation', }); } - return swarmNodes; } async updateSwarmNodes(pubKey, newNodes) { - let conversation; try { - conversation = ConversationController.get(pubKey); + const conversation = ConversationController.get(pubKey); + await conversation.updateSwarmNodes(newNodes); } catch (e) { throw new window.textsecure.ReplayableError({ message: 'Could not get conversation', }); } - await conversation.updateSwarmNodes(newNodes); } async getOurSwarmNodes() { @@ -128,12 +125,7 @@ class LokiSnodeAPI { async refreshSwarmNodesForPubKey(pubKey) { const newNodes = await this.getFreshSwarmNodes(pubKey); - try { - const conversation = ConversationController.get(pubKey); - await conversation.updateSwarmNodes(newNodes); - } catch (e) { - throw e; - } + this.updateSwarmNodes(pubKey, newNodes); } async getFreshSwarmNodes(pubKey) {