diff --git a/lib/ops/message-store-ops.js b/lib/ops/message-store-ops.js --- a/lib/ops/message-store-ops.js +++ b/lib/ops/message-store-ops.js @@ -46,7 +46,7 @@ // MessageStore threads ops export type ReplaceMessageStoreThreadsOperation = { +type: 'replace_threads', - +payload: { +threads: MessageStoreThreads }, + +payload: { +threads: MessageStoreThreads, +isBackedUp: boolean }, }; export type RemoveMessageStoreThreadsOperation = { @@ -271,4 +271,45 @@ }; } -export { messageStoreOpsHandlers, createReplaceMessageOperation }; +function createReplaceMessageStoreThreadsOperations( + threads: MessageStoreThreads, + threadInfos: MixedRawThreadInfos, +): $ReadOnlyArray { + let backedUpThreads: MessageStoreThreads = {}; + let notBackedUpThreads: MessageStoreThreads = {}; + for (const threadID in threads) { + const threadInfo = threadInfos[threadID]; + if (!threadInfo || threadSpecs[threadInfo.type].protocol.dataIsBackedUp) { + backedUpThreads = { + ...backedUpThreads, + [threadID]: threads[threadID], + }; + } else { + notBackedUpThreads = { + ...notBackedUpThreads, + [threadID]: threads[threadID], + }; + } + } + + const ops: Array = []; + if (Object.keys(backedUpThreads).length) { + ops.push({ + type: 'replace_threads', + payload: { threads: backedUpThreads, isBackedUp: true }, + }); + } + if (Object.keys(notBackedUpThreads).length) { + ops.push({ + type: 'replace_threads', + payload: { threads: notBackedUpThreads, isBackedUp: false }, + }); + } + return ops; +} + +export { + messageStoreOpsHandlers, + createReplaceMessageOperation, + createReplaceMessageStoreThreadsOperations, +}; 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 @@ -63,6 +63,7 @@ type MessageStoreOperation, type ReplaceMessageStoreLocalMessageInfoOperation, createReplaceMessageOperation, + createReplaceMessageStoreThreadsOperations, } from '../ops/message-store-ops.js'; import { pendingToRealizedThreadIDsSelector } from '../selectors/thread-selectors.js'; import { @@ -212,10 +213,7 @@ { type: 'remove_all_local_message_infos', }, - { - type: 'replace_threads', - payload: { threads }, - }, + ...createReplaceMessageStoreThreadsOperations(threads, threadInfos), ...messageStoreReplaceOperations, ]; @@ -304,12 +302,12 @@ }); } if (Object.keys(updatedThreads).length > 0) { - messageStoreOperations.push({ - type: 'replace_threads', - payload: { - threads: updatedThreads, - }, - }); + messageStoreOperations.push( + ...createReplaceMessageStoreThreadsOperations( + updatedThreads, + threadInfos, + ), + ); } return { @@ -628,44 +626,37 @@ // is that after closing and reopening the app, we're fetching only a subset // of messages. If we read startReached = true from the DB, we won't attempt // fetching more batches of messages. + const filteredThreads = Object.fromEntries( + Object.entries(updatedThreads).map(([threadID, thread]) => { + let threadType; + if (threadInfos[threadID]) { + threadType = threadInfos[threadID].type; + } else { + const threadIDParseResult = parsePendingThreadID(threadID); + threadType = threadIDParseResult?.threadType; + } + const messagesStoredOnServer = threadType + ? threadSpecs[threadType].protocol.messagesStoredOnServer + : false; + return [ + threadID, + messagesStoredOnServer + ? thread + : { + ...thread, + startReached: thread.messageIDs.length < defaultNumberPerThread, + }, + ]; + }), + ); const dbOps = [ ...newMessageOps, - { - type: 'replace_threads', - payload: { - threads: Object.fromEntries( - Object.entries(updatedThreads).map(([threadID, thread]) => { - let threadType; - if (threadInfos[threadID]) { - threadType = threadInfos[threadID].type; - } else { - const threadIDParseResult = parsePendingThreadID(threadID); - threadType = threadIDParseResult?.threadType; - } - const messagesStoredOnServer = threadType - ? threadSpecs[threadType].protocol.messagesStoredOnServer - : false; - return [ - threadID, - messagesStoredOnServer - ? thread - : { - ...thread, - startReached: - thread.messageIDs.length < defaultNumberPerThread, - }, - ]; - }), - ), - }, - }, + ...createReplaceMessageStoreThreadsOperations(filteredThreads, threadInfos), ]; - newMessageOps.push({ - type: 'replace_threads', - payload: { - threads: updatedThreads, - }, - }); + + newMessageOps.push( + ...createReplaceMessageStoreThreadsOperations(updatedThreads, threadInfos), + ); const processedMessageStore = processMessageStoreOperations( updatedMessageStore, @@ -748,12 +739,9 @@ payload: { ids: threadsToRemoveMessagesFrom }, }); - messageStoreOperations.push({ - type: 'replace_threads', - payload: { - threads: updatedThreads, - }, - }); + messageStoreOperations.push( + ...createReplaceMessageStoreThreadsOperations(updatedThreads, threadInfos), + ); messageStoreOperations.push({ type: 'remove_messages_for_threads', @@ -1156,12 +1144,12 @@ }; } - messageStoreOperations.push({ - type: 'replace_threads', - payload: { - threads: { ...updatedThreads }, - }, - }); + messageStoreOperations.push( + ...createReplaceMessageStoreThreadsOperations( + updatedThreads, + newThreadInfos, + ), + ); const processedMessageStore = processMessageStoreOperations( messageStore, @@ -1240,10 +1228,12 @@ }, }; - messageStoreOperations.push({ - type: 'replace_threads', - payload: { threads: updatedThreads }, - }); + messageStoreOperations.push( + ...createReplaceMessageStoreThreadsOperations( + updatedThreads, + newThreadInfos, + ), + ); const processedMessageStore = processMessageStoreOperations( messageStore, @@ -1327,10 +1317,12 @@ messageIDs: newMessageIDs, }, }; - messageStoreOperations.push({ - type: 'replace_threads', - payload: { threads: updatedThreads }, - }); + messageStoreOperations.push( + ...createReplaceMessageStoreThreadsOperations( + updatedThreads, + newThreadInfos, + ), + ); const processedMessageStore = processMessageStoreOperations( messageStore, @@ -1414,12 +1406,10 @@ type: 'remove', payload: { ids: messageIDsToPrune }, }, - { - type: 'replace_threads', - payload: { - threads: updatedThreads, - }, - }, + ...createReplaceMessageStoreThreadsOperations( + updatedThreads, + newThreadInfos, + ), { type: 'remove_local_message_infos', payload: { ids: Object.keys(localMessageIDsToRemove) }, @@ -1680,12 +1670,10 @@ const messageStoreOperations = [ createReplaceMessageOperation(localID, messageInfo, newThreadInfos), - { - type: 'replace_threads', - payload: { - threads: { [(threadID: string)]: threadState }, - }, - }, + ...createReplaceMessageStoreThreadsOperations( + { [(threadID: string)]: threadState }, + newThreadInfos, + ), ]; const processedMessageStore = processMessageStoreOperations( @@ -1878,10 +1866,12 @@ messageStoreOperations, ); - messageStoreOperations.push({ - type: 'replace_threads', - payload: { threads: threadsToAdd }, - }); + messageStoreOperations.push( + ...createReplaceMessageStoreThreadsOperations( + threadsToAdd, + newThreadInfos, + ), + ); return { messageStoreOperations, diff --git a/native/redux/persist.js b/native/redux/persist.js --- a/native/redux/persist.js +++ b/native/redux/persist.js @@ -651,7 +651,11 @@ }, { type: 'replace_threads', - payload: { threads: state.messageStore.threads }, + // Adding `isBackedUp` only to support types, when this migration was + // implemented, backup was not yet supported, because of that, + // this migration should maintain the default behaviour. + // Migrating DM threads to be supported by backup is added later. + payload: { threads: state.messageStore.threads, isBackedUp: false }, }, ]); diff --git a/web/redux/initial-state-gate.js b/web/redux/initial-state-gate.js --- a/web/redux/initial-state-gate.js +++ b/web/redux/initial-state-gate.js @@ -193,7 +193,10 @@ })), { type: 'replace_threads', - payload: { threads }, + // This code is responsible for migrating keyserver message + // threads to SQLite, which means this data shouldn't be + // included in the backup because it is owned by keyserver. + payload: { threads, isBackedUp: false }, }, ]; }