diff --git a/lib/reducers/master-reducer.js b/lib/reducers/master-reducer.js --- a/lib/reducers/master-reducer.js +++ b/lib/reducers/master-reducer.js @@ -86,7 +86,12 @@ // Only allow checkpoints to increase if we are connected // or if the action is a STATE_SYNC const { messageStoreOperations, messageStore: reducedMessageStore } = - reduceMessageStore(state.messageStore, action, threadInfos); + reduceMessageStore( + state.messageStore, + action, + threadInfos, + onStateDifferenceForStaff, + ); let messageStore = reducedMessageStore; let { keyserverStore, keyserverStoreOperations } = reduceKeyserverStore( diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js --- a/lib/reducers/message-reducer.js +++ b/lib/reducers/message-reducer.js @@ -110,7 +110,9 @@ type ClientUpdateInfo, processUpdatesActionType, } from '../types/update-types.js'; +import { getMessageForException } from '../utils/errors.js'; import { translateClientDBThreadMessageInfos } from '../utils/message-ops-utils.js'; +import { assertObjectsAreEqual } from '../utils/objects.js'; const _mapValuesWithKeys = _mapValues.convert({ cap: false }); @@ -143,6 +145,31 @@ ); } +function assertMessageStoreLocalMessageInfosAreEqual( + processedMessageStore: MessageStore, + expectedMessageStore: MessageStore, + location: string, + onStateDifference?: (message: string) => mixed, +) { + try { + assertObjectsAreEqual( + processedMessageStore.local, + expectedMessageStore.local, + `MessageStore.local - ${location}`, + ); + } catch (e) { + console.log( + 'Error processing MessageStore local ops', + processedMessageStore.local, + expectedMessageStore.local, + ); + const message = `Error processing MessageStore local ops ${ + getMessageForException(e) ?? '{no exception message}' + }`; + onStateDifference?.(message); + } +} + const newThread = (): ThreadMessageInfo => ({ messageIDs: [], startReached: false, @@ -751,6 +778,7 @@ messageStore: MessageStore, action: BaseAction, newThreadInfos: RawThreadInfos, + onStateDifference?: (message: string) => mixed, ): ReduceMessageStoreResult { if ( action.type === legacyLogInActionTypes.success || @@ -1656,6 +1684,19 @@ action.payload.messageStoreThreads ?? [], ); + const actionPayloadMessageStoreLocalMessageInfos = + action.payload.messageStoreLocalMessageInfos ?? {}; + + assertMessageStoreLocalMessageInfosAreEqual( + { + ...messageStore, + local: actionPayloadMessageStoreLocalMessageInfos, + }, + messageStore, + action.type, + onStateDifference, + ); + const newThreads: { [threadID: string]: ThreadMessageInfo, } = { ...messageStore.threads }; diff --git a/lib/utils/message-ops-utils.js b/lib/utils/message-ops-utils.js --- a/lib/utils/message-ops-utils.js +++ b/lib/utils/message-ops-utils.js @@ -25,6 +25,8 @@ type RawMessageInfo, type ClientDBThreadMessageInfo, type ThreadMessageInfo, + type ClientDBLocalMessageInfo, + type MessageStoreLocalMessageInfos, } from '../types/message-types.js'; import type { MediaMessageServerDBContent } from '../types/messages/media.js'; @@ -272,6 +274,19 @@ }; } +function translateClientDBLocalMessageInfos( + clientDBLocalMessageInfos: $ReadOnlyArray, +): MessageStoreLocalMessageInfos { + return Object.fromEntries( + clientDBLocalMessageInfos.map( + (localMessageInfo: ClientDBLocalMessageInfo) => [ + localMessageInfo.id, + JSON.parse(localMessageInfo.localMessageInfo), + ], + ), + ); +} + function getPinnedContentFromClientDBMessageInfo( clientDBMessageInfo: ClientDBMessageInfo, ): string { @@ -295,4 +310,5 @@ getPinnedContentFromClientDBMessageInfo, translateClientDBThreadMessageInfos, translateThreadMessageInfoToClientDBThreadMessageInfo, + translateClientDBLocalMessageInfos, }; diff --git a/native/data/sqlite-data-handler.js b/native/data/sqlite-data-handler.js --- a/native/data/sqlite-data-handler.js +++ b/native/data/sqlite-data-handler.js @@ -26,6 +26,7 @@ type RecoveryFromDataHandlerActionSource, } from 'lib/types/account-types.js'; import { getMessageForException } from 'lib/utils/errors.js'; +import { translateClientDBLocalMessageInfos } from 'lib/utils/message-ops-utils.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import { supportingMultipleKeyservers } from 'lib/utils/services-utils.js'; @@ -244,6 +245,7 @@ auxUserInfos, threadActivityEntries, entries, + messageStoreLocalMessageInfos, } = await commCoreModule.getClientDBStore(); const threadInfosFromDB = threadStoreOpsHandlers.translateClientDBData(threads); @@ -268,6 +270,9 @@ ); const entriesFromDB = entryStoreOpsHandlers.translateClientDBData(entries); + const localMessageInfosFromDB = translateClientDBLocalMessageInfos( + messageStoreLocalMessageInfos, + ); dispatch({ type: setClientDBStoreActionType, payload: { @@ -285,6 +290,7 @@ auxUserInfos: auxUserInfosFromDB, threadActivityStore: threadActivityStoreFromDB, entries: entriesFromDB, + messageStoreLocalMessageInfos: localMessageInfosFromDB, }, }); } catch (setStoreException) { diff --git a/web/shared-worker/utils/store.js b/web/shared-worker/utils/store.js --- a/web/shared-worker/utils/store.js +++ b/web/shared-worker/utils/store.js @@ -16,6 +16,7 @@ ClientStore, StoreOperations, } from 'lib/types/store-ops-types.js'; +import { translateClientDBLocalMessageInfos } from 'lib/utils/message-ops-utils.js'; import { entries } from 'lib/utils/objects.js'; import { defaultWebState } from '../../redux/default-state.js'; @@ -145,6 +146,18 @@ entries: entryStoreOpsHandlers.translateClientDBData(data.store.entries), }; } + + if ( + data?.store?.messageStoreLocalMessageInfos && + data.store.messageStoreLocalMessageInfos.length > 0 + ) { + result = { + ...result, + messageStoreLocalMessageInfos: translateClientDBLocalMessageInfos( + data.store.messageStoreLocalMessageInfos, + ), + }; + } return result; }