From ad03fbd497349709e0b2380f30dbeb381e656ed4 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 7 Oct 2022 15:35:09 +1100 Subject: [PATCH] fix: skip recent deleted message empty react changes --- .../apis/open_group_api/sogsv3/sogsApiV3.ts | 58 ++++++++----------- .../sogsv3/sogsRollingDeletions.ts | 32 ++++++++++ ts/session/utils/RingBuffer.ts | 31 ++++++++++ 3 files changed, 88 insertions(+), 33 deletions(-) create mode 100644 ts/session/apis/open_group_api/sogsv3/sogsRollingDeletions.ts create mode 100644 ts/session/utils/RingBuffer.ts diff --git a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts index 79c1880f3..b07b36f58 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts @@ -36,6 +36,7 @@ import { createSwarmMessageSentFromUs } from '../../../../models/messageFactory' import { Data } from '../../../../data/data'; import { processMessagesUsingCache } from './sogsV3MutationCache'; import { destroyMessagesAndUpdateRedux } from '../../../../util/expiringMessages'; +import { sogsRollingDeletions } from './sogsRollingDeletions'; /** * Get the convo matching those criteria and make sure it is an opengroup convo, or return null. @@ -155,29 +156,28 @@ async function filterOutMessagesInvalidSignature( return signaturesValidMessages; } -let totalDeletedMessages = 0; const handleSogsV3DeletedMessages = async ( messages: Array, serverUrl: string, roomId: string ) => { - const deletions = messages.filter(m => Boolean(m.deleted)); - const exceptDeletion = messages.filter(m => !m.deleted); - if (!deletions.length) { - return messages; + const messagesDeleted = messages.filter(m => Boolean(m.deleted)); + const messagesWithoutDeleted = messages.filter(m => !m.deleted); + if (!messagesDeleted.length) { + return messagesWithoutDeleted; } - totalDeletedMessages += deletions.length; - console.warn( - JSON.stringify({ - totalDeletedMessages, - }) - ); - const allIdsRemoved = deletions.map(m => m.id); + + const allIdsRemoved = messagesDeleted.map(m => m.id); + try { const convoId = getOpenGroupV2ConversationId(serverUrl, roomId); const convo = getConversationController().get(convoId); const messageIds = await Data.getMessageIdsFromServerIds(allIdsRemoved, convo.id); + allIdsRemoved.forEach(removedId => { + sogsRollingDeletions.addMessageDeletedId(convoId, removedId); + }); + if (messageIds && messageIds.length) { await destroyMessagesAndUpdateRedux( messageIds.map(messageId => ({ @@ -189,14 +189,9 @@ const handleSogsV3DeletedMessages = async ( } catch (e) { window?.log?.warn('handleDeletions failed:', e); } - return exceptDeletion; + return messagesWithoutDeleted; }; -// tslint:disable-next-line: one-variable-per-declaration -let totalEmptyReactions = 0, - totalMessagesWithResolvedBlindedIdsIfFound = 0, - totalMessageReactions = 0; - // tslint:disable-next-line: max-func-body-length cyclomatic-complexity const handleMessagesResponseV4 = async ( messages: Array, @@ -296,8 +291,6 @@ const handleMessagesResponseV4 = async ( const incomingMessageSeqNo = compact(messages.map(n => n.seqno)); const maxNewMessageSeqNo = Math.max(...incomingMessageSeqNo); - totalMessagesWithResolvedBlindedIdsIfFound += messagesWithResolvedBlindedIdsIfFound.length; - for (let index = 0; index < messagesWithResolvedBlindedIdsIfFound.length; index++) { const msgToHandle = messagesWithResolvedBlindedIdsIfFound[index]; try { @@ -323,25 +316,24 @@ const handleMessagesResponseV4 = async ( await OpenGroupData.saveV2OpenGroupRoom(roomInfosRefreshed); const messagesWithReactions = messages.filter(m => m.reactions !== undefined); - const messagesWithEmptyReactions = messagesWithReactions.filter(m => isEmpty(m.reactions)); - - totalMessageReactions += messagesWithReactions.length; - totalEmptyReactions += messagesWithEmptyReactions.length; - console.warn( - JSON.stringify({ - totalMessagesWithResolvedBlindedIdsIfFound, - totalMessageReactions, - totalEmptyReactions, - }) - ); if (messagesWithReactions.length > 0) { const conversationId = getOpenGroupV2ConversationId(serverUrl, roomId); const groupConvo = getConversationController().get(conversationId); if (groupConvo && groupConvo.isOpenGroupV2()) { - for (const message of messagesWithReactions) { + for (const messageWithReaction of messagesWithReactions) { + if (isEmpty(messageWithReaction.reactions)) { + /* + * When a message is deleted from the server, we get the deleted event as a data: null on the message itself + * and an update on its reactions. + * But, because we just deleted that message, we can skip trying to udpate its reactions: it's not in the DB anymore. + */ + if (sogsRollingDeletions.hasMessageDeletedId(conversationId, messageWithReaction.id)) { + continue; + } + } void groupConvo.queueJob(async () => { - await processMessagesUsingCache(serverUrl, roomId, message); + await processMessagesUsingCache(serverUrl, roomId, messageWithReaction); }); } } diff --git a/ts/session/apis/open_group_api/sogsv3/sogsRollingDeletions.ts b/ts/session/apis/open_group_api/sogsv3/sogsRollingDeletions.ts new file mode 100644 index 000000000..7b32360d8 --- /dev/null +++ b/ts/session/apis/open_group_api/sogsv3/sogsRollingDeletions.ts @@ -0,0 +1,32 @@ +import { RingBuffer } from '../../../utils/RingBuffer'; + +const rollingDeletedMessageIds: Map> = new Map(); + +// keep 2000 deleted message ids in memory +const perRoomRollingRemovedIds = 2000; + +const addMessageDeletedId = (conversationId: string, messageDeletedId: number) => { + if (!rollingDeletedMessageIds.has(conversationId)) { + rollingDeletedMessageIds.set(conversationId, new RingBuffer(perRoomRollingRemovedIds)); + } + const ringBuffer = rollingDeletedMessageIds.get(conversationId); + if (!ringBuffer) { + return; + } + ringBuffer.add(messageDeletedId); +}; + + +const hasMessageDeletedId = (conversationId: string, messageDeletedId: number) => { + if (!rollingDeletedMessageIds.has(conversationId)) { + return false; + } + + const messageIdWasDeletedRecently = rollingDeletedMessageIds + ?.get(conversationId) + ?.has(messageDeletedId); + + return messageIdWasDeletedRecently; +}; + +export const sogsRollingDeletions = { addMessageDeletedId, hasMessageDeletedId }; diff --git a/ts/session/utils/RingBuffer.ts b/ts/session/utils/RingBuffer.ts new file mode 100644 index 000000000..7a192e858 --- /dev/null +++ b/ts/session/utils/RingBuffer.ts @@ -0,0 +1,31 @@ +export class RingBuffer { + private buffer: Array = []; + private readonly capacity: number; + + constructor(capacity: number) { + this.capacity = capacity; + } + + public getCapacity(): number { + return this.capacity; + } + + public add(item: T) { + this.buffer.push(item); + this.crop(); + } + + public has(item: T) { + return this.buffer.includes(item); + } + + public clear() { + this.buffer = []; + } + + private crop() { + while (this.buffer.length > this.capacity) { + this.buffer.shift(); + } + } +}