From 425e63a4ce3573fa930b41eb83b10560c75db315 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 3 Apr 2024 14:05:30 +1100 Subject: [PATCH 1/6] fix: message sent status displayed for last outgoing message --- .../message/message-content/MessageStatus.tsx | 19 +++++++++---------- ts/state/selectors/conversations.ts | 10 +++++++++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/ts/components/conversation/message/message-content/MessageStatus.tsx b/ts/components/conversation/message/message-content/MessageStatus.tsx index 41bcdb42c..96f059c89 100644 --- a/ts/components/conversation/message/message-content/MessageStatus.tsx +++ b/ts/components/conversation/message/message-content/MessageStatus.tsx @@ -6,7 +6,7 @@ import { useMessageExpirationPropsById } from '../../../../hooks/useParamSelecto import { useMessageStatus } from '../../../../state/selectors'; import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext'; -import { getMostRecentMessageId } from '../../../../state/selectors/conversations'; +import { getMostRecentOutgoingMessageId } from '../../../../state/selectors/conversations'; import { useSelectedIsGroupOrCommunity } from '../../../../state/selectors/selectedConversation'; import { SpacerXS } from '../../../basic/Text'; import { SessionIcon, SessionIconType } from '../../../icon'; @@ -122,10 +122,9 @@ function useIsExpiring(messageId: string) { ); } -function useIsMostRecentMessage(messageId: string) { - const mostRecentMessageId = useSelector(getMostRecentMessageId); - const isMostRecentMessage = mostRecentMessageId === messageId; - return isMostRecentMessage; +function useIsMostRecentOutgoingMessage(messageId: string) { + const mostRecentOutgoingMessageId = useSelector(getMostRecentOutgoingMessageId); + return mostRecentOutgoingMessageId === messageId; } function MessageStatusExpireTimer(props: Pick) { @@ -180,11 +179,11 @@ function IconForExpiringMessageId({ const MessageStatusSent = ({ dataTestId, messageId }: Omit) => { const isExpiring = useIsExpiring(messageId); - const isMostRecentMessage = useIsMostRecentMessage(messageId); + const isMostRecentOutgoingMessage = useIsMostRecentOutgoingMessage(messageId); const isGroup = useSelectedIsGroupOrCommunity(); - // we hide a "sent" message status which is not expiring except for the most recent message - if (!isExpiring && !isMostRecentMessage) { + // we hide the "sent" message status for a non-expiring message unless if it's the most recent outgoing message + if (!isExpiring && !isMostRecentOutgoingMessage) { return null; } return ( @@ -208,10 +207,10 @@ const MessageStatusRead = ({ const isExpiring = useIsExpiring(messageId); const isGroup = useSelectedIsGroupOrCommunity(); - const isMostRecentMessage = useIsMostRecentMessage(messageId); + const isMostRecentOutgoingMessage = useIsMostRecentOutgoingMessage(messageId); // we hide an outgoing "read" message status which is not expiring except for the most recent message - if (!isIncoming && !isExpiring && !isMostRecentMessage) { + if (!isIncoming && !isExpiring && !isMostRecentOutgoingMessage) { return null; } diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 5babd3893..563ec03f0 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -1,6 +1,6 @@ /* eslint-disable no-restricted-syntax */ import { createSelector } from '@reduxjs/toolkit'; -import { filter, isEmpty, isFinite, isNumber, pick, sortBy, toNumber } from 'lodash'; +import { filter, first, isEmpty, isFinite, isNumber, pick, sortBy, toNumber } from 'lodash'; import { ConversationLookupType, @@ -593,6 +593,14 @@ export const getMostRecentMessageId = (state: StateType): string | null => { return state.conversations.mostRecentMessageId; }; +export const getMostRecentOutgoingMessageId = createSelector( + getSortedMessagesOfSelectedConversation, + (messages: Array): string | undefined => { + return first(messages.filter(m => m.propsForMessage.direction === 'outgoing'))?.propsForMessage + .id; + } +); + export const getOldestMessageId = createSelector( getSortedMessagesOfSelectedConversation, (messages: Array): string | undefined => { From cfcbc013e5640d2ea5521e4e04dff225b8bfeaf1 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 3 Apr 2024 14:07:16 +1100 Subject: [PATCH 2/6] fix: make sure we only try to delete data once --- ts/components/dialog/DeleteAccountModal.tsx | 11 +++++++++++ ts/mains/main_node.ts | 16 ++++++++++++++-- ts/node/sql_channel.ts | 20 ++++++++++++++++---- ts/node/tray_icon.ts | 2 +- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/ts/components/dialog/DeleteAccountModal.tsx b/ts/components/dialog/DeleteAccountModal.tsx index 9b886b97e..e9b17f912 100644 --- a/ts/components/dialog/DeleteAccountModal.tsx +++ b/ts/components/dialog/DeleteAccountModal.tsx @@ -18,11 +18,22 @@ import { SessionRadioGroup } from '../basic/SessionRadioGroup'; const deleteDbLocally = async () => { window?.log?.info('last message sent successfully. Deleting everything'); window.persistStore?.purge(); + window?.log?.info('store purged'); + await deleteAllLogs(); + window?.log?.info('ladelete logs'); + await Data.removeAll(); + window?.log?.info('data removeall'); + await Data.close(); + window?.log?.info('db closed'); await Data.removeDB(); + window?.log?.info('db removed'); + await Data.removeOtherData(); + window?.log?.info('otherdata removed'); + window.localStorage.setItem('restart-reason', 'delete-account'); }; diff --git a/ts/mains/main_node.ts b/ts/mains/main_node.ts index 2b62f04e6..2abe40d6d 100644 --- a/ts/mains/main_node.ts +++ b/ts/mains/main_node.ts @@ -790,8 +790,20 @@ async function removeDB() { try { console.error('Remove DB: removing.', userDir); - userConfig.remove(); - ephemeralConfig.remove(); + try { + userConfig.remove(); + } catch (e) { + if (e.code !== 'ENOENT') { + throw e; + } + } + try { + ephemeralConfig.remove(); + } catch (e) { + if (e.code !== 'ENOENT') { + throw e; + } + } } catch (e) { console.error('Remove DB: Failed to remove configs.', e); } diff --git a/ts/node/sql_channel.ts b/ts/node/sql_channel.ts index 1573be71b..3fbe7c0fe 100644 --- a/ts/node/sql_channel.ts +++ b/ts/node/sql_channel.ts @@ -1,7 +1,7 @@ import { app, ipcMain } from 'electron'; -import { sqlNode } from './sql'; // checked - only node -import { userConfig } from './config/user_config'; // checked - only node import { ephemeralConfig } from './config/ephemeral_config'; // checked - only node +import { userConfig } from './config/user_config'; // checked - only node +import { sqlNode } from './sql'; // checked - only node let initialized = false; @@ -31,8 +31,20 @@ export function initializeSqlChannel() { ipcMain.on(ERASE_SQL_KEY, event => { try { - userConfig.remove(); - ephemeralConfig.remove(); + try { + userConfig.remove(); + } catch (e) { + if (e.code !== 'ENOENT') { + throw e; + } + } + try { + ephemeralConfig.remove(); + } catch (e) { + if (e.code !== 'ENOENT') { + throw e; + } + } event.sender.send(`${ERASE_SQL_KEY}-done`); } catch (error) { const errorForDisplay = error && error.stack ? error.stack : error; diff --git a/ts/node/tray_icon.ts b/ts/node/tray_icon.ts index 65d158ca2..d643e3405 100644 --- a/ts/node/tray_icon.ts +++ b/ts/node/tray_icon.ts @@ -1,8 +1,8 @@ import path from 'path'; import { app, BrowserWindow, Menu, Tray } from 'electron'; -import { LocaleMessagesType } from './locale'; import { getAppRootPath } from './getRootPath'; +import { LocaleMessagesType } from './locale'; let trayContextMenu = null; let tray: Tray | null = null; From ae96936a1a520432714a7eb1d9e3980d1c2d95a2 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 3 Apr 2024 16:27:58 +1100 Subject: [PATCH 3/6] fix: add logs during polling --- ts/session/apis/snode_api/retrieveRequest.ts | 17 ++++++++--------- ts/session/apis/snode_api/swarmPolling.ts | 12 ++++++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ts/session/apis/snode_api/retrieveRequest.ts b/ts/session/apis/snode_api/retrieveRequest.ts index 31e5827f3..07d646b10 100644 --- a/ts/session/apis/snode_api/retrieveRequest.ts +++ b/ts/session/apis/snode_api/retrieveRequest.ts @@ -1,4 +1,4 @@ -import { omit } from 'lodash'; +import { isArray, omit } from 'lodash'; import { Snode } from '../../../data/data'; import { updateIsOnline } from '../../../state/ducks/onion'; import { doSnodeBatchRequest } from './batchRequest'; @@ -7,6 +7,7 @@ import { SnodeNamespace, SnodeNamespaces } from './namespaces'; import { TTL_DEFAULT } from '../../constants'; import { UserUtils } from '../../utils'; +import { sleepFor } from '../../utils/Promise'; import { RetrieveLegacyClosedGroupSubRequestType, RetrieveSubRequestType, @@ -123,14 +124,12 @@ async function retrieveNextMessages( ); // let exceptions bubble up // no retry for this one as this a call we do every few seconds while polling for messages - - const results = await doSnodeBatchRequest( - retrieveRequestsParams, - targetNode, - 4000, - associatedWith - ); - if (!results || !results.length) { + const timeOutMs = 4 * 1000; + const results = await Promise.race([ + async () => doSnodeBatchRequest(retrieveRequestsParams, targetNode, timeOutMs, associatedWith), + async () => sleepFor(timeOutMs), // just to make sure that we don't hang for more than 4s + ]); + if (!results || !isArray(results) || !results.length) { window?.log?.warn( `_retrieveNextMessages - sessionRpc could not talk to ${targetNode.ip}:${targetNode.port}` ); diff --git a/ts/session/apis/snode_api/swarmPolling.ts b/ts/session/apis/snode_api/swarmPolling.ts index 4a335dfc6..c43fce899 100644 --- a/ts/session/apis/snode_api/swarmPolling.ts +++ b/ts/session/apis/snode_api/swarmPolling.ts @@ -228,12 +228,21 @@ export class SwarmPolling { let resultsFromAllNamespaces: RetrieveMessagesResultsBatched | null; try { + // Note: always print something so we know if the polling is hanging + window.log.info( + `about to pollNodeForKey of ${ed25519Str(pubkey.key)} from snode: ${ed25519Str(toPollFrom.pubkey_ed25519)} namespaces: ${namespaces} ` + ); resultsFromAllNamespaces = await this.pollNodeForKey( toPollFrom, pubkey, namespaces, !isGroup ); + + // Note: always print something so we know if the polling is hanging + window.log.info( + `pollNodeForKey of ${ed25519Str(pubkey.key)} from snode: ${ed25519Str(toPollFrom.pubkey_ed25519)} namespaces: ${namespaces} returned: ${resultsFromAllNamespaces?.length}` + ); } catch (e) { window.log.warn( `pollNodeForKey of ${pubkey} namespaces: ${namespaces} failed with: ${e.message}` @@ -475,6 +484,9 @@ export class SwarmPolling { return last(r.messages.messages); }); + window.log.info( + `updating last hashes for ${ed25519Str(pubkey.key)}: ${ed25519Str(snodeEdkey)} ${lastMessages.map(m => m?.hash || '')}` + ); await Promise.all( lastMessages.map(async (lastMessage, index) => { if (!lastMessage) { From b5d7a0e5e5cbb589058d1995aa9b2993fd4fb23f Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 3 Apr 2024 16:36:20 +1100 Subject: [PATCH 4/6] fix: no initial focus set for focustrap --- ts/components/SessionWrapperModal.tsx | 5 +---- .../header/ConversationHeaderSelectionOverlay.tsx | 2 +- ts/state/selectors/conversations.ts | 5 ++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ts/components/SessionWrapperModal.tsx b/ts/components/SessionWrapperModal.tsx index f69d66c4d..42753784e 100644 --- a/ts/components/SessionWrapperModal.tsx +++ b/ts/components/SessionWrapperModal.tsx @@ -63,15 +63,12 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => { } }; - const fallbackFocusId = 'session-wrapper-modal'; - return ( - +