diff --git a/lib/shared/dm-ops/create-entry-spec.js b/lib/shared/dm-ops/create-entry-spec.js --- a/lib/shared/dm-ops/create-entry-spec.js +++ b/lib/shared/dm-ops/create-entry-spec.js @@ -79,6 +79,18 @@ dmOperation: DMCreateEntryOperation, utilities: ProcessDMOperationUtilities, ) => { + if (utilities.entryInfos[dmOperation.entryID]) { + console.log( + 'Discarded a CREATE_ENTRY operation because entry with ' + + `the same ID ${dmOperation.entryID} already exists in the store`, + ); + return { + isProcessingPossible: false, + reason: { + type: 'invalid', + }, + }; + } if (utilities.threadInfos[dmOperation.threadID]) { return { isProcessingPossible: true }; } diff --git a/lib/shared/dm-ops/create-sidebar-spec.js b/lib/shared/dm-ops/create-sidebar-spec.js --- a/lib/shared/dm-ops/create-sidebar-spec.js +++ b/lib/shared/dm-ops/create-sidebar-spec.js @@ -188,6 +188,19 @@ dmOperation: DMCreateSidebarOperation, utilities: ProcessDMOperationUtilities, ) => { + if (utilities.threadInfos[dmOperation.threadID]) { + console.log( + 'Discarded a CREATE_SIDEBAR operation because thread ' + + `with the same ID ${dmOperation.threadID} already exists ` + + 'in the store', + ); + return { + isProcessingPossible: false, + reason: { + type: 'invalid', + }, + }; + } const sourceMessage = await utilities.fetchMessage( dmOperation.sourceMessageID, ); diff --git a/lib/shared/dm-ops/create-thread-spec.js b/lib/shared/dm-ops/create-thread-spec.js --- a/lib/shared/dm-ops/create-thread-spec.js +++ b/lib/shared/dm-ops/create-thread-spec.js @@ -289,7 +289,23 @@ blobOps: [], }; }, - canBeProcessed: async () => { + canBeProcessed: async ( + dmOperation: DMCreateThreadOperation, + utilities: ProcessDMOperationUtilities, + ) => { + if (utilities.threadInfos[dmOperation.threadID]) { + console.log( + 'Discarded a CREATE_THREAD operation because thread ' + + `with the same ID ${dmOperation.threadID} already exists ` + + 'in the store', + ); + return { + isProcessingPossible: false, + reason: { + type: 'invalid', + }, + }; + } return { isProcessingPossible: true }; }, supportsAutoRetry: true, diff --git a/lib/shared/dm-ops/dm-op-spec.js b/lib/shared/dm-ops/dm-op-spec.js --- a/lib/shared/dm-ops/dm-op-spec.js +++ b/lib/shared/dm-ops/dm-op-spec.js @@ -18,7 +18,7 @@ ) => Promise, }; -type ProcessingPossibilityCheckResult = +export type ProcessingPossibilityCheckResult = | { +isProcessingPossible: true } | { +isProcessingPossible: false, diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js --- a/lib/shared/dm-ops/dm-op-utils.js +++ b/lib/shared/dm-ops/dm-op-utils.js @@ -5,7 +5,10 @@ import * as React from 'react'; import uuid from 'uuid'; -import { type ProcessDMOperationUtilities } from './dm-op-spec.js'; +import { + type ProcessDMOperationUtilities, + type ProcessingPossibilityCheckResult, +} from './dm-op-spec.js'; import { dmOpSpecs } from './dm-op-specs.js'; import { useProcessAndSendDMOperation } from './process-dm-ops.js'; import { mergeUpdatesWithMessageInfos } from '../../reducers/message-reducer.js'; @@ -15,6 +18,10 @@ DMAddViewerToThreadMembersOperation, DMOperation, ComposableDMOperation, + DMSendTextMessageOperation, + DMSendEditMessageOperation, + DMSendMultimediaMessageOperation, + DMSendReactionMessageOperation, } from '../../types/dm-ops.js'; import type { RawMessageInfo } from '../../types/message-types.js'; import type { @@ -359,9 +366,37 @@ return newUpdateInfos; } +async function checkMessageIDConflict( + dmOperation: + | DMSendTextMessageOperation + | DMSendEditMessageOperation + | DMSendMultimediaMessageOperation + | DMSendReactionMessageOperation, + utilities: ProcessDMOperationUtilities, +): Promise { + const message = await utilities.fetchMessage(dmOperation.messageID); + if (message) { + console.log( + `Discarded a ${dmOperation.type} operation because ` + + `message with the same ID ${dmOperation.messageID} already exists ` + + 'in the store', + ); + return { + isProcessingPossible: false, + reason: { + type: 'invalid', + }, + }; + } + return { + isProcessingPossible: true, + }; +} + export { createMessagesToPeersFromDMOp, useAddDMThreadMembers, getCreateThickRawThreadInfoInputFromThreadInfo, getThreadUpdatesForNewMessages, + checkMessageIDConflict, }; diff --git a/lib/shared/dm-ops/send-edit-message-spec.js b/lib/shared/dm-ops/send-edit-message-spec.js --- a/lib/shared/dm-ops/send-edit-message-spec.js +++ b/lib/shared/dm-ops/send-edit-message-spec.js @@ -4,6 +4,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { checkMessageIDConflict } from './dm-op-utils.js'; import type { DMSendEditMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { rawMessageInfoFromMessageData } from '../message-utils.js'; @@ -51,8 +52,17 @@ dmOperation: DMSendEditMessageOperation, utilities: ProcessDMOperationUtilities, ) => { - const message = await utilities.fetchMessage(dmOperation.targetMessageID); - if (!message) { + const conflictCheckResult = await checkMessageIDConflict( + dmOperation, + utilities, + ); + if (!conflictCheckResult.isProcessingPossible) { + return conflictCheckResult; + } + const targetMessage = await utilities.fetchMessage( + dmOperation.targetMessageID, + ); + if (!targetMessage) { return { isProcessingPossible: false, reason: { diff --git a/lib/shared/dm-ops/send-multimedia-message-spec.js b/lib/shared/dm-ops/send-multimedia-message-spec.js --- a/lib/shared/dm-ops/send-multimedia-message-spec.js +++ b/lib/shared/dm-ops/send-multimedia-message-spec.js @@ -4,6 +4,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { checkMessageIDConflict } from './dm-op-utils.js'; import { encryptedMediaBlobURI, encryptedVideoThumbnailBlobURI, @@ -89,16 +90,23 @@ dmOperation: DMSendMultimediaMessageOperation, utilities: ProcessDMOperationUtilities, ) => { - if (utilities.threadInfos[dmOperation.threadID]) { - return { isProcessingPossible: true }; + const conflictCheckResult = await checkMessageIDConflict( + dmOperation, + utilities, + ); + if (!conflictCheckResult.isProcessingPossible) { + return conflictCheckResult; } - return { - isProcessingPossible: false, - reason: { - type: 'missing_thread', - threadID: dmOperation.threadID, - }, - }; + if (!utilities.threadInfos[dmOperation.threadID]) { + return { + isProcessingPossible: false, + reason: { + type: 'missing_thread', + threadID: dmOperation.threadID, + }, + }; + } + return { isProcessingPossible: true }; }, supportsAutoRetry: false, }); diff --git a/lib/shared/dm-ops/send-reaction-message-spec.js b/lib/shared/dm-ops/send-reaction-message-spec.js --- a/lib/shared/dm-ops/send-reaction-message-spec.js +++ b/lib/shared/dm-ops/send-reaction-message-spec.js @@ -4,6 +4,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { checkMessageIDConflict } from './dm-op-utils.js'; import type { DMSendReactionMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { rawMessageInfoFromMessageData } from '../message-utils.js'; @@ -59,8 +60,17 @@ dmOperation: DMSendReactionMessageOperation, utilities: ProcessDMOperationUtilities, ) => { - const message = await utilities.fetchMessage(dmOperation.targetMessageID); - if (!message) { + const conflictCheckResult = await checkMessageIDConflict( + dmOperation, + utilities, + ); + if (!conflictCheckResult.isProcessingPossible) { + return conflictCheckResult; + } + const targetMessage = await utilities.fetchMessage( + dmOperation.targetMessageID, + ); + if (!targetMessage) { return { isProcessingPossible: false, reason: { diff --git a/lib/shared/dm-ops/send-text-message-spec.js b/lib/shared/dm-ops/send-text-message-spec.js --- a/lib/shared/dm-ops/send-text-message-spec.js +++ b/lib/shared/dm-ops/send-text-message-spec.js @@ -4,6 +4,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { checkMessageIDConflict } from './dm-op-utils.js'; import type { DMSendTextMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { ClientUpdateInfo } from '../../types/update-types.js'; @@ -50,16 +51,23 @@ dmOperation: DMSendTextMessageOperation, utilities: ProcessDMOperationUtilities, ) => { - if (utilities.threadInfos[dmOperation.threadID]) { - return { isProcessingPossible: true }; + const conflictCheckResult = await checkMessageIDConflict( + dmOperation, + utilities, + ); + if (!conflictCheckResult.isProcessingPossible) { + return conflictCheckResult; } - return { - isProcessingPossible: false, - reason: { - type: 'missing_thread', - threadID: dmOperation.threadID, - }, - }; + if (!utilities.threadInfos[dmOperation.threadID]) { + return { + isProcessingPossible: false, + reason: { + type: 'missing_thread', + threadID: dmOperation.threadID, + }, + }; + } + return { isProcessingPossible: true }; }, supportsAutoRetry: false, });