From 0b08fc9e1f54cb14e9c9968dad6decc38e9f052e Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Thu, 2 Nov 2023 06:28:49 -0700 Subject: [PATCH] Use sender+timestamp to cache receipts and read syncs --- ts/messageModifiers/MessageReceipts.ts | 16 ++++++++++++++-- ts/messageModifiers/ReadSyncs.ts | 18 +++++++++++++++--- ts/messageModifiers/generateCacheKey.ts | 16 ++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 ts/messageModifiers/generateCacheKey.ts diff --git a/ts/messageModifiers/MessageReceipts.ts b/ts/messageModifiers/MessageReceipts.ts index f3ba1564e00..f3ca3fb0857 100644 --- a/ts/messageModifiers/MessageReceipts.ts +++ b/ts/messageModifiers/MessageReceipts.ts @@ -24,6 +24,7 @@ import { getSourceServiceId } from '../messages/helpers'; import { queueUpdateMessage } from '../util/messageBatcher'; import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp'; import { getMessageIdForLogging } from '../util/idForLogging'; +import { generateCacheKey } from './generateCacheKey'; const { deleteSentProtoRecipient } = dataInterface; @@ -78,7 +79,12 @@ const deleteSentProtoBatcher = createWaitBatcher({ }); function remove(receipt: MessageReceiptAttributesType): void { - receipts.delete(receipt.envelopeId); + receipts.delete( + generateCacheKey({ + sender: receipt.sourceServiceId, + timestamp: receipt.messageSentAt, + }) + ); receipt.removeFromMessageReceiverCache(); } @@ -341,7 +347,13 @@ async function updateMessageSendState( export async function onReceipt( receipt: MessageReceiptAttributesType ): Promise { - receipts.set(receipt.envelopeId, receipt); + receipts.set( + generateCacheKey({ + sender: receipt.sourceServiceId, + timestamp: receipt.messageSentAt, + }), + receipt + ); const { messageSentAt, sourceConversationId, sourceServiceId, type } = receipt; diff --git a/ts/messageModifiers/ReadSyncs.ts b/ts/messageModifiers/ReadSyncs.ts index 17f81756788..39e75411b50 100644 --- a/ts/messageModifiers/ReadSyncs.ts +++ b/ts/messageModifiers/ReadSyncs.ts @@ -14,6 +14,7 @@ import { isMessageUnread } from '../util/isMessageUnread'; import { notificationService } from '../services/notifications'; import { queueUpdateMessage } from '../util/messageBatcher'; import { strictAssert } from '../util/assert'; +import { generateCacheKey } from './generateCacheKey'; export type ReadSyncAttributesType = { envelopeId: string; @@ -25,10 +26,15 @@ export type ReadSyncAttributesType = { timestamp: number; }; -const readSyncs = new Map(); +const readSyncs = new Map(); function remove(sync: ReadSyncAttributesType): void { - readSyncs.delete(sync.timestamp); + readSyncs.delete( + generateCacheKey({ + sender: sync.senderId, + timestamp: sync.timestamp, + }) + ); sync.removeFromMessageReceiverCache(); } @@ -99,7 +105,13 @@ export function forMessage( } export async function onSync(sync: ReadSyncAttributesType): Promise { - readSyncs.set(sync.timestamp, sync); + readSyncs.set( + generateCacheKey({ + sender: sync.senderId, + timestamp: sync.timestamp, + }), + sync + ); const logId = `ReadSyncs.onSync(timestamp=${sync.timestamp})`; diff --git a/ts/messageModifiers/generateCacheKey.ts b/ts/messageModifiers/generateCacheKey.ts new file mode 100644 index 00000000000..87b0f0e4d18 --- /dev/null +++ b/ts/messageModifiers/generateCacheKey.ts @@ -0,0 +1,16 @@ +// Copyright 2016 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +// This function is necessary because the only thing we can guarantee will be unique is +// three pieces of data: sender, deviceId, and timestamp. +// Because we don't care which device interacted with our message, we collapse this down +// to: sender + timestamp. +export function generateCacheKey({ + sender, + timestamp, +}: { + sender: string; + timestamp: number; +}): string { + return `cacheKey-${sender}-${timestamp}`; +}