Move receipts and view/read syncs to new syncTasks system

Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
automated-signal 2024-06-17 19:36:57 -05:00 committed by GitHub
parent 949104c316
commit b95dd1a70f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 1242 additions and 612 deletions

View file

@ -1,7 +1,8 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { AciString } from '../types/ServiceId';
import { z } from 'zod';
import type { MessageModel } from '../models/messages';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
@ -15,35 +16,38 @@ import { markViewed } from '../services/MessageUpdater';
import { notificationService } from '../services/notifications';
import { queueAttachmentDownloads } from '../util/queueAttachmentDownloads';
import { queueUpdateMessage } from '../util/messageBatcher';
import { generateCacheKey } from './generateCacheKey';
import { AttachmentDownloadUrgency } from '../jobs/AttachmentDownloadManager';
import { isAciString } from '../util/isAciString';
import dataInterface from '../sql/Client';
const { removeSyncTaskById } = dataInterface;
export const viewSyncTaskSchema = z.object({
type: z.literal('ViewSync').readonly(),
senderAci: z.string().refine(isAciString),
senderE164: z.string().optional(),
senderId: z.string(),
timestamp: z.number(),
viewedAt: z.number(),
});
export type ViewSyncTaskType = z.infer<typeof viewSyncTaskSchema>;
export type ViewSyncAttributesType = {
envelopeId: string;
removeFromMessageReceiverCache: () => unknown;
senderAci: AciString;
senderE164?: string;
senderId: string;
timestamp: number;
viewedAt: number;
syncTaskId: string;
viewSync: ViewSyncTaskType;
};
const viewSyncs = new Map<string, ViewSyncAttributesType>();
function remove(sync: ViewSyncAttributesType): void {
viewSyncs.delete(
generateCacheKey({
sender: sync.senderId,
timestamp: sync.timestamp,
type: 'viewsync',
})
);
sync.removeFromMessageReceiverCache();
async function remove(sync: ViewSyncAttributesType): Promise<void> {
await removeSyncTaskById(sync.syncTaskId);
}
export function forMessage(
export async function forMessage(
message: MessageModel
): Array<ViewSyncAttributesType> {
): Promise<Array<ViewSyncAttributesType>> {
const logId = `ViewSyncs.forMessage(${getMessageIdForLogging(
message.attributes
)})`;
@ -60,7 +64,11 @@ export function forMessage(
const viewSyncValues = Array.from(viewSyncs.values());
const matchingSyncs = viewSyncValues.filter(item => {
return item.senderId === sender?.id && item.timestamp === messageTimestamp;
const { viewSync } = item;
return (
viewSync.senderId === sender?.id &&
viewSync.timestamp === messageTimestamp
);
});
if (matchingSyncs.length > 0) {
@ -68,28 +76,24 @@ export function forMessage(
`${logId}: Found ${matchingSyncs.length} early view sync(s) for message ${messageTimestamp}`
);
}
matchingSyncs.forEach(sync => {
remove(sync);
});
await Promise.all(
matchingSyncs.map(async sync => {
await remove(sync);
})
);
return matchingSyncs;
}
export async function onSync(sync: ViewSyncAttributesType): Promise<void> {
viewSyncs.set(
generateCacheKey({
sender: sync.senderId,
timestamp: sync.timestamp,
type: 'viewsync',
}),
sync
);
viewSyncs.set(sync.syncTaskId, sync);
const { viewSync } = sync;
const logId = `ViewSyncs.onSync(timestamp=${sync.timestamp})`;
const logId = `ViewSyncs.onSync(timestamp=${viewSync.timestamp})`;
try {
const messages = await window.Signal.Data.getMessagesBySentAt(
sync.timestamp
viewSync.timestamp
);
const found = messages.find(item => {
@ -99,15 +103,15 @@ export async function onSync(sync: ViewSyncAttributesType): Promise<void> {
reason: logId,
});
return sender?.id === sync.senderId;
return sender?.id === viewSync.senderId;
});
if (!found) {
log.info(
`${logId}: nothing found`,
sync.senderId,
sync.senderE164,
sync.senderAci
viewSync.senderId,
viewSync.senderE164,
viewSync.senderAci
);
return;
}
@ -123,7 +127,7 @@ export async function onSync(sync: ViewSyncAttributesType): Promise<void> {
if (message.get('readStatus') !== ReadStatus.Viewed) {
didChangeMessage = true;
message.set(markViewed(message.attributes, sync.viewedAt));
message.set(markViewed(message.attributes, viewSync.viewedAt));
const attachments = message.get('attachments');
if (!attachments?.every(isDownloaded)) {
@ -154,9 +158,9 @@ export async function onSync(sync: ViewSyncAttributesType): Promise<void> {
queueUpdateMessage(message.attributes);
}
remove(sync);
await remove(sync);
} catch (error) {
remove(sync);
log.error(`${logId} error:`, Errors.toLogFormat(error));
await remove(sync);
}
}