fix: clear swarms from snodes not in pool on full fetch

pull/3080/head
Audric Ackermann 12 months ago
parent 52ebcfdbab
commit 7f7f0fe26c

2
.gitignore vendored

@ -53,3 +53,5 @@ stylesheets/dist/
*.LICENSE.txt *.LICENSE.txt
ts/webworker/workers/node/**/*.node ts/webworker/workers/node/**/*.node
.yarn/**/*.mjs
.yarn/**/*.cjs

@ -216,11 +216,13 @@
"afterSign": "build/notarize.js", "afterSign": "build/notarize.js",
"afterPack": "build/afterPackHook.js", "afterPack": "build/afterPackHook.js",
"artifactName": "${name}-${os}-${arch}-${version}.${ext}", "artifactName": "${name}-${os}-${arch}-${version}.${ext}",
"extraResources": [{ "extraResources": [
"from": "./build/launcher-script.sh", {
"to": "./launcher-script.sh" "from": "./build/launcher-script.sh",
}, "to": "./launcher-script.sh"
"mmdb/GeoLite2-Country.mmdb"], },
"mmdb/GeoLite2-Country.mmdb"
],
"mac": { "mac": {
"category": "public.app-category.social-networking", "category": "public.app-category.social-networking",
"icon": "build/icon-mac.icns", "icon": "build/icon-mac.icns",

@ -3,13 +3,13 @@ import { useSelector } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { useConversationUsername } from '../../hooks/useParamSelector'; import { useConversationUsername } from '../../hooks/useParamSelector';
import { ed25519Str } from '../../session/onions/onionPath';
import { CallManager } from '../../session/utils'; import { CallManager } from '../../session/utils';
import { callTimeoutMs } from '../../session/utils/calling/CallManager'; import { callTimeoutMs } from '../../session/utils/calling/CallManager';
import { getHasIncomingCall, getHasIncomingCallFrom } from '../../state/selectors/call'; import { getHasIncomingCall, getHasIncomingCallFrom } from '../../state/selectors/call';
import { Avatar, AvatarSize } from '../avatar/Avatar'; import { Avatar, AvatarSize } from '../avatar/Avatar';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionWrapperModal } from '../SessionWrapperModal';
import { ed25519Str } from '../../session/utils/String';
export const CallWindow = styled.div` export const CallWindow = styled.div`
position: absolute; position: absolute;

@ -1,7 +1,7 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { SnodeAPI } from '../../session/apis/snode_api/SNodeAPI'; import { SnodeAPI } from '../../session/apis/snode_api/SNodeAPI';
import { ed25519Str } from '../../session/onions/onionPath';
import { forceSyncConfigurationNowIfNeeded } from '../../session/utils/sync/syncUtils'; import { forceSyncConfigurationNowIfNeeded } from '../../session/utils/sync/syncUtils';
import { updateConfirmModal, updateDeleteAccountModal } from '../../state/ducks/modalDialog'; import { updateConfirmModal, updateDeleteAccountModal } from '../../state/ducks/modalDialog';
import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionWrapperModal } from '../SessionWrapperModal';
@ -14,6 +14,7 @@ import { deleteAllLogs } from '../../node/logs';
import { clearInbox } from '../../session/apis/open_group_api/sogsv3/sogsV3ClearInbox'; import { clearInbox } from '../../session/apis/open_group_api/sogsv3/sogsV3ClearInbox';
import { getAllValidOpenGroupV2ConversationRoomInfos } from '../../session/apis/open_group_api/utils/OpenGroupUtils'; import { getAllValidOpenGroupV2ConversationRoomInfos } from '../../session/apis/open_group_api/utils/OpenGroupUtils';
import { SessionRadioGroup } from '../basic/SessionRadioGroup'; import { SessionRadioGroup } from '../basic/SessionRadioGroup';
import { ed25519Str } from '../../session/utils/String';
const deleteDbLocally = async () => { const deleteDbLocally = async () => {
window?.log?.info('last message sent successfully. Deleting everything'); window?.log?.info('last message sent successfully. Deleting everything');

@ -109,6 +109,10 @@ async function updateSwarmNodesForPubkey(
await channels.updateSwarmNodesForPubkey(pubkey, snodeEdKeys); await channels.updateSwarmNodesForPubkey(pubkey, snodeEdKeys);
} }
async function clearOutAllSnodesNotInPool(edKeysOfSnodePool: Array<string>): Promise<void> {
await channels.clearOutAllSnodesNotInPool(edKeysOfSnodePool);
}
// Closed group // Closed group
/** /**
@ -802,6 +806,7 @@ export const Data = {
generateAttachmentKeyIfEmpty, generateAttachmentKeyIfEmpty,
getSwarmNodesForPubkey, getSwarmNodesForPubkey,
updateSwarmNodesForPubkey, updateSwarmNodesForPubkey,
clearOutAllSnodesNotInPool,
getAllEncryptionKeyPairsForGroup, getAllEncryptionKeyPairsForGroup,
getLatestClosedGroupEncryptionKeyPair, getLatestClosedGroupEncryptionKeyPair,
addClosedGroupEncryptionKeyPair, addClosedGroupEncryptionKeyPair,

@ -24,6 +24,7 @@ const channelsToMake = new Set([
'removeItemById', 'removeItemById',
'getSwarmNodesForPubkey', 'getSwarmNodesForPubkey',
'updateSwarmNodesForPubkey', 'updateSwarmNodesForPubkey',
'clearOutAllSnodesNotInPool',
'saveConversation', 'saveConversation',
'fetchConvoMemoryDetails', 'fetchConvoMemoryDetails',
'getConversationById', 'getConversationById',

@ -9,12 +9,12 @@ import { SnodeAPI } from '../../session/apis/snode_api/SNodeAPI';
import { SnodeNamespaces } from '../../session/apis/snode_api/namespaces'; import { SnodeNamespaces } from '../../session/apis/snode_api/namespaces';
import { getConversationController } from '../../session/conversations'; import { getConversationController } from '../../session/conversations';
import { UnsendMessage } from '../../session/messages/outgoing/controlMessage/UnsendMessage'; import { UnsendMessage } from '../../session/messages/outgoing/controlMessage/UnsendMessage';
import { ed25519Str } from '../../session/onions/onionPath';
import { PubKey } from '../../session/types'; import { PubKey } from '../../session/types';
import { ToastUtils, UserUtils } from '../../session/utils'; import { ToastUtils, UserUtils } from '../../session/utils';
import { closeRightPanel, resetSelectedMessageIds } from '../../state/ducks/conversations'; import { closeRightPanel, resetSelectedMessageIds } from '../../state/ducks/conversations';
import { updateConfirmModal } from '../../state/ducks/modalDialog'; import { updateConfirmModal } from '../../state/ducks/modalDialog';
import { resetRightOverlayMode } from '../../state/ducks/section'; import { resetRightOverlayMode } from '../../state/ducks/section';
import { ed25519Str } from '../../session/utils/String';
/** /**
* Deletes messages for everyone in a 1-1 or everyone in a closed group conversation. * Deletes messages for everyone in a 1-1 or everyone in a closed group conversation.

@ -42,7 +42,7 @@ import {
VisibleMessageParams, VisibleMessageParams,
} from '../session/messages/outgoing/visibleMessage/VisibleMessage'; } from '../session/messages/outgoing/visibleMessage/VisibleMessage';
import { perfEnd, perfStart } from '../session/utils/Performance'; import { perfEnd, perfStart } from '../session/utils/Performance';
import { toHex } from '../session/utils/String'; import { ed25519Str, toHex } from '../session/utils/String';
import { createTaskWithTimeout } from '../session/utils/TaskWithTimeout'; import { createTaskWithTimeout } from '../session/utils/TaskWithTimeout';
import { import {
actions as conversationActions, actions as conversationActions,
@ -74,7 +74,6 @@ import {
MessageRequestResponse, MessageRequestResponse,
MessageRequestResponseParams, MessageRequestResponseParams,
} from '../session/messages/outgoing/controlMessage/MessageRequestResponse'; } from '../session/messages/outgoing/controlMessage/MessageRequestResponse';
import { ed25519Str } from '../session/onions/onionPath';
import { ConfigurationSync } from '../session/utils/job_runners/jobs/ConfigurationSyncJob'; import { ConfigurationSync } from '../session/utils/job_runners/jobs/ConfigurationSyncJob';
import { SessionUtilContact } from '../session/utils/libsession/libsession_utils_contacts'; import { SessionUtilContact } from '../session/utils/libsession/libsession_utils_contacts';
import { SessionUtilConvoInfoVolatile } from '../session/utils/libsession/libsession_utils_convo_info_volatile'; import { SessionUtilConvoInfoVolatile } from '../session/utils/libsession/libsession_utils_convo_info_volatile';

@ -12,6 +12,7 @@ import {
differenceBy, differenceBy,
forEach, forEach,
fromPairs, fromPairs,
intersection,
isArray, isArray,
isEmpty, isEmpty,
isNumber, isNumber,
@ -78,6 +79,7 @@ import {
initDbInstanceWith, initDbInstanceWith,
isInstanceInitialized, isInstanceInitialized,
} from './sqlInstance'; } from './sqlInstance';
import { ed25519Str } from '../session/utils/String';
// eslint:disable: function-name non-literal-fs-path // eslint:disable: function-name non-literal-fs-path
@ -398,6 +400,32 @@ function updateSwarmNodesForPubkey(pubkey: string, snodeEdKeys: Array<string>) {
}); });
} }
function clearOutAllSnodesNotInPool(edKeysOfSnodePool: Array<string>) {
const allSwarms = assertGlobalInstance()
.prepare(`SELECT * FROM ${NODES_FOR_PUBKEY_TABLE};`)
.all();
allSwarms.forEach(swarm => {
try {
const json = JSON.parse(swarm.json);
if (isArray(json)) {
const intersect = intersection(json, edKeysOfSnodePool);
if (intersect.length !== json.length) {
updateSwarmNodesForPubkey(swarm.pubkey, intersect);
console.info(
`clearOutAllSnodesNotInPool: updating swarm of ${ed25519Str(swarm.pubkey)} to `,
intersect
);
}
}
} catch (e) {
console.warn(
`Failed to parse swarm while iterating in clearOutAllSnodesNotInPool for pk: ${ed25519Str(swarm?.pubkey)}`
);
}
});
}
function getConversationCount() { function getConversationCount() {
const row = assertGlobalInstance().prepare(`SELECT count(*) from ${CONVERSATIONS_TABLE};`).get(); const row = assertGlobalInstance().prepare(`SELECT count(*) from ${CONVERSATIONS_TABLE};`).get();
if (!row) { if (!row) {
@ -2449,6 +2477,7 @@ export const sqlNode = {
getSwarmNodesForPubkey, getSwarmNodesForPubkey,
updateSwarmNodesForPubkey, updateSwarmNodesForPubkey,
clearOutAllSnodesNotInPool,
getGuardNodes, getGuardNodes,
updateGuardNodes, updateGuardNodes,

@ -4,9 +4,8 @@ import { compact, sample } from 'lodash';
import pRetry from 'p-retry'; import pRetry from 'p-retry';
import { Snode } from '../../../data/data'; import { Snode } from '../../../data/data';
import { getSodiumRenderer } from '../../crypto'; import { getSodiumRenderer } from '../../crypto';
import { ed25519Str } from '../../onions/onionPath';
import { StringUtils, UserUtils } from '../../utils'; import { StringUtils, UserUtils } from '../../utils';
import { fromBase64ToArray, fromHexToArray } from '../../utils/String'; import { ed25519Str, fromBase64ToArray, fromHexToArray } from '../../utils/String';
import { doSnodeBatchRequest } from './batchRequest'; import { doSnodeBatchRequest } from './batchRequest';
import { getSwarmFor } from './snodePool'; import { getSwarmFor } from './snodePool';
import { SnodeSignature } from './snodeSignatures'; import { SnodeSignature } from './snodeSignatures';

@ -11,8 +11,8 @@ import { AbortSignal as AbortSignalNode } from 'node-fetch/externals';
import { dropSnodeFromSnodePool, dropSnodeFromSwarmIfNeeded, updateSwarmFor } from './snodePool'; import { dropSnodeFromSnodePool, dropSnodeFromSwarmIfNeeded, updateSwarmFor } from './snodePool';
import { OnionPaths } from '../../onions'; import { OnionPaths } from '../../onions';
import { ed25519Str, incrementBadPathCountOrDrop } from '../../onions/onionPath'; import { incrementBadPathCountOrDrop } from '../../onions/onionPath';
import { toHex } from '../../utils/String'; import { ed25519Str, toHex } from '../../utils/String';
import { Snode } from '../../../data/data'; import { Snode } from '../../../data/data';
import { callUtilsWorker } from '../../../webworker/workers/browser/util_worker_interface'; import { callUtilsWorker } from '../../../webworker/workers/browser/util_worker_interface';

@ -124,7 +124,7 @@ async function retrieveNextMessages(
); );
// let exceptions bubble up // let exceptions bubble up
// no retry for this one as this a call we do every few seconds while polling for messages // no retry for this one as this a call we do every few seconds while polling for messages
const timeOutMs = 4 * 1000; const timeOutMs = 10 * 1000; // yes this is a long timeout for just messages, but 4s timeout way to often...
const timeoutPromise = async () => sleepFor(timeOutMs); const timeoutPromise = async () => sleepFor(timeOutMs);
const fetchPromise = async () => const fetchPromise = async () =>
doSnodeBatchRequest(retrieveRequestsParams, targetNode, timeOutMs, associatedWith); doSnodeBatchRequest(retrieveRequestsParams, targetNode, timeOutMs, associatedWith);

@ -3,12 +3,12 @@ import pRetry from 'p-retry';
import { Data, Snode } from '../../../data/data'; import { Data, Snode } from '../../../data/data';
import { ed25519Str } from '../../onions/onionPath';
import { OnionPaths } from '../../onions'; import { OnionPaths } from '../../onions';
import { Onions, SnodePool } from '.'; import { Onions, SnodePool } from '.';
import { SeedNodeAPI } from '../seed_node_api'; import { SeedNodeAPI } from '../seed_node_api';
import { requestSnodesForPubkeyFromNetwork } from './getSwarmFor'; import { requestSnodesForPubkeyFromNetwork } from './getSwarmFor';
import { ServiceNodesList } from './getServiceNodesList'; import { ServiceNodesList } from './getServiceNodesList';
import { ed25519Str } from '../../utils/String';
/** /**
* If we get less than this snode in a swarm, we fetch new snodes for this pubkey * If we get less than this snode in a swarm, we fetch new snodes for this pubkey
@ -204,6 +204,18 @@ export async function TEST_fetchFromSeedWithRetriesAndWriteToDb() {
} }
} }
async function clearOutAllSnodesNotInPool(snodePool: Array<Snode>) {
if (snodePool.length <= 10) {
return;
}
const edKeysOfSnodePool = snodePool.map(m => m.pubkey_ed25519);
await Data.clearOutAllSnodesNotInPool(edKeysOfSnodePool);
// just remove all the cached entries, we will refetch them as needed from the DB
swarmCache.clear();
}
/** /**
* This function retries a few times to get a consensus between 3 snodes of at least 24 snodes in the snode pool. * This function retries a few times to get a consensus between 3 snodes of at least 24 snodes in the snode pool.
* *
@ -230,6 +242,7 @@ async function tryToGetConsensusWithSnodesWithRetries() {
); );
randomSnodePool = commonNodes; randomSnodePool = commonNodes;
await Data.updateSnodePoolOnDb(JSON.stringify(randomSnodePool)); await Data.updateSnodePoolOnDb(JSON.stringify(randomSnodePool));
await clearOutAllSnodesNotInPool(randomSnodePool);
OnionPaths.resetPathFailureCount(); OnionPaths.resetPathFailureCount();
Onions.resetSnodeFailureCount(); Onions.resetSnodeFailureCount();

@ -22,12 +22,12 @@ import {
import { DURATION, SWARM_POLLING_TIMEOUT } from '../../constants'; import { DURATION, SWARM_POLLING_TIMEOUT } from '../../constants';
import { getConversationController } from '../../conversations'; import { getConversationController } from '../../conversations';
import { IncomingMessage } from '../../messages/incoming/IncomingMessage'; import { IncomingMessage } from '../../messages/incoming/IncomingMessage';
import { ed25519Str } from '../../onions/onionPath';
import { StringUtils, UserUtils } from '../../utils'; import { StringUtils, UserUtils } from '../../utils';
import { LibSessionUtil } from '../../utils/libsession/libsession_utils'; import { LibSessionUtil } from '../../utils/libsession/libsession_utils';
import { SnodeNamespace, SnodeNamespaces } from './namespaces'; import { SnodeNamespace, SnodeNamespaces } from './namespaces';
import { SnodeAPIRetrieve } from './retrieveRequest'; import { SnodeAPIRetrieve } from './retrieveRequest';
import { RetrieveMessageItem, RetrieveMessagesResultsBatched } from './types'; import { RetrieveMessageItem, RetrieveMessagesResultsBatched } from './types';
import { ed25519Str } from '../../utils/String';
export function extractWebSocketContent( export function extractWebSocketContent(
message: string, message: string,

@ -14,6 +14,7 @@ import { updateOnionPaths } from '../../state/ducks/onion';
import { ERROR_CODE_NO_CONNECT } from '../apis/snode_api/SNodeAPI'; import { ERROR_CODE_NO_CONNECT } from '../apis/snode_api/SNodeAPI';
import { OnionPaths } from '.'; import { OnionPaths } from '.';
import { APPLICATION_JSON } from '../../types/MIME'; import { APPLICATION_JSON } from '../../types/MIME';
import { ed25519Str } from '../utils/String';
const desiredGuardCount = 3; const desiredGuardCount = 3;
const minimumGuardCount = 2; const minimumGuardCount = 2;
@ -63,8 +64,6 @@ const pathFailureThreshold = 3;
// some naming issue here it seems) // some naming issue here it seems)
export let guardNodes: Array<Snode> = []; export let guardNodes: Array<Snode> = [];
export const ed25519Str = (ed25519Key: string) => `(...${ed25519Key.substr(58)})`;
export async function buildNewOnionPathsOneAtATime() { export async function buildNewOnionPathsOneAtATime() {
// this function may be called concurrently make sure we only have one inflight // this function may be called concurrently make sure we only have one inflight
return allowOnlyOneAtATime('buildNewOnionPaths', async () => { return allowOnlyOneAtATime('buildNewOnionPaths', async () => {

@ -32,11 +32,10 @@ import { SharedConfigMessage } from '../messages/outgoing/controlMessage/SharedC
import { UnsendMessage } from '../messages/outgoing/controlMessage/UnsendMessage'; import { UnsendMessage } from '../messages/outgoing/controlMessage/UnsendMessage';
import { ClosedGroupNewMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupNewMessage'; import { ClosedGroupNewMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupNewMessage';
import { OpenGroupVisibleMessage } from '../messages/outgoing/visibleMessage/OpenGroupVisibleMessage'; import { OpenGroupVisibleMessage } from '../messages/outgoing/visibleMessage/OpenGroupVisibleMessage';
import { ed25519Str } from '../onions/onionPath';
import { PubKey } from '../types'; import { PubKey } from '../types';
import { RawMessage } from '../types/RawMessage'; import { RawMessage } from '../types/RawMessage';
import { UserUtils } from '../utils'; import { UserUtils } from '../utils';
import { fromUInt8ArrayToBase64 } from '../utils/String'; import { ed25519Str, fromUInt8ArrayToBase64 } from '../utils/String';
import { EmptySwarmError } from '../utils/errors'; import { EmptySwarmError } from '../utils/errors';
// ================ SNODE STORE ================ // ================ SNODE STORE ================

@ -71,3 +71,5 @@ export const sanitizeSessionUsername = (inputName: string) => {
return validChars; return validChars;
}; };
export const ed25519Str = (ed25519Key: string) => `(...${ed25519Key.substr(58)})`;

@ -18,7 +18,6 @@ import {
import { openConversationWithMessages } from '../../../state/ducks/conversations'; import { openConversationWithMessages } from '../../../state/ducks/conversations';
import { getConversationController } from '../../conversations'; import { getConversationController } from '../../conversations';
import { CallMessage } from '../../messages/outgoing/controlMessage/CallMessage'; import { CallMessage } from '../../messages/outgoing/controlMessage/CallMessage';
import { ed25519Str } from '../../onions/onionPath';
import { PubKey } from '../../types'; import { PubKey } from '../../types';
import { getMessageQueue } from '../..'; import { getMessageQueue } from '../..';
@ -35,6 +34,7 @@ import { ReadyToDisappearMsgUpdate } from '../../disappearing_messages/types';
import { MessageSender } from '../../sending'; import { MessageSender } from '../../sending';
import { getIsRinging } from '../RingingManager'; import { getIsRinging } from '../RingingManager';
import { getBlackSilenceMediaStream } from './Silence'; import { getBlackSilenceMediaStream } from './Silence';
import { ed25519Str } from '../String';
export type InputItem = { deviceId: string; label: string }; export type InputItem = { deviceId: string; label: string };
@ -415,8 +415,10 @@ async function createOfferAndSendIt(recipient: string, msgIdentifier: string | n
if (offer && offer.sdp) { if (offer && offer.sdp) {
const lines = offer.sdp.split(/\r?\n/); const lines = offer.sdp.split(/\r?\n/);
const lineWithFtmpIndex = lines.findIndex(f => f.startsWith('a=fmtp:111')); const lineWithFtmpIndex = lines.findIndex(f => f.startsWith('a=fmtp:111'));
const partBeforeComma = lines[lineWithFtmpIndex].split(';'); if (lineWithFtmpIndex > -1) {
lines[lineWithFtmpIndex] = `${partBeforeComma[0]};cbr=1`; const partBeforeComma = lines[lineWithFtmpIndex].split(';');
lines[lineWithFtmpIndex] = `${partBeforeComma[0]};cbr=1`;
}
let overridenSdps = lines.join('\n'); let overridenSdps = lines.join('\n');
overridenSdps = overridenSdps.replace( overridenSdps = overridenSdps.replace(
// eslint-disable-next-line prefer-regex-literals // eslint-disable-next-line prefer-regex-literals

Loading…
Cancel
Save