Support for local deletes synced to all your devices

This commit is contained in:
Scott Nonnenberg 2024-05-29 01:56:00 +10:00 committed by GitHub
parent 06f71a7ef8
commit 11eb1782a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 2094 additions and 72 deletions

View file

@ -165,6 +165,12 @@ import OS from '../util/os/osMain';
import { getMessageAuthorText } from '../util/getMessageAuthorText';
import { downscaleOutgoingAttachment } from '../util/attachments';
import { MessageRequestResponseEvent } from '../types/MessageRequestResponseEvent';
import type { MessageToDelete } from '../textsecure/messageReceiverEvents';
import {
getConversationToDelete,
getMessageToDelete,
} from '../util/deleteForMe';
import { isEnabled } from '../RemoteConfig';
import { getCallHistorySelector } from '../state/selectors/callHistory';
/* eslint-disable more/no-then */
@ -186,6 +192,7 @@ const {
getOlderMessagesByConversation,
getMessageMetricsForConversation,
getMessageById,
getMostRecentAddressableMessages,
getNewerMessagesByConversation,
} = window.Signal.Data;
@ -2234,7 +2241,7 @@ export class ConversationModel extends window.Backbone
}
if (isDelete) {
await this.destroyMessages();
await this.destroyMessages({ source: 'message-request' });
void this.updateLastMessage();
}
@ -4449,7 +4456,6 @@ export class ConversationModel extends window.Backbone
source: providedSource,
fromSync = false,
isInitialSync = false,
fromGroupUpdate = false,
}: {
reason: string;
receivedAt?: number;
@ -4458,7 +4464,6 @@ export class ConversationModel extends window.Backbone
source?: string;
fromSync?: boolean;
isInitialSync?: boolean;
fromGroupUpdate?: boolean;
}
): Promise<boolean | null | MessageModel | void> {
const isSetByOther = providedSource || providedSentAt !== undefined;
@ -4554,7 +4559,7 @@ export class ConversationModel extends window.Backbone
(isInitialSync && isFromSyncOperation) || isFromMe || isNoteToSelf;
const id = generateGuid();
const model = new window.Whisper.Message({
const attributes = {
id,
conversationId: this.id,
expirationTimerUpdate: {
@ -4562,7 +4567,6 @@ export class ConversationModel extends window.Backbone
source,
sourceServiceId,
fromSync,
fromGroupUpdate,
},
flags: Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
readStatus: shouldBeRead ? ReadStatus.Read : ReadStatus.Unread,
@ -4570,18 +4574,18 @@ export class ConversationModel extends window.Backbone
received_at: receivedAt ?? incrementMessageCounter(),
seenStatus: shouldBeRead ? SeenStatus.Seen : SeenStatus.Unseen,
sent_at: sentAt,
type: 'timer-notification',
// TODO: DESKTOP-722
} as unknown as MessageAttributesType);
timestamp: sentAt,
type: 'timer-notification' as const,
};
await window.Signal.Data.saveMessage(model.attributes, {
await window.Signal.Data.saveMessage(attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
const message = window.MessageCache.__DEPRECATED$register(
id,
model,
new window.Whisper.Message(attributes),
'updateExpirationTimer'
);
@ -4589,7 +4593,7 @@ export class ConversationModel extends window.Backbone
void this.updateUnread();
log.info(
`${logId}: added a notification received_at=${model.get('received_at')}`
`${logId}: added a notification received_at=${message.get('received_at')}`
);
return message;
@ -4978,7 +4982,29 @@ export class ConversationModel extends window.Backbone
this.contactCollection!.reset(members);
}
async destroyMessages(): Promise<void> {
async destroyMessages({
source,
}: {
source: 'message-request' | 'local-delete-sync' | 'local-delete';
}): Promise<void> {
const logId = `destroyMessages(${this.idForLogging()})/${source}`;
log.info(`${logId}: Queuing job on conversation`);
await this.queueJob(logId, async () => {
log.info(`${logId}: Starting...`);
await this.destroyMessagesInner({ logId, source });
});
}
async destroyMessagesInner({
logId,
source,
}: {
logId: string;
source: 'message-request' | 'local-delete-sync' | 'local-delete';
}): Promise<void> {
this.set({
lastMessage: null,
lastMessageAuthor: null,
@ -4988,9 +5014,50 @@ export class ConversationModel extends window.Backbone
});
window.Signal.Data.updateConversation(this.attributes);
await window.Signal.Data.removeAllMessagesInConversation(this.id, {
if (source === 'local-delete' && isEnabled('desktop.deleteSync.send')) {
log.info(`${logId}: Preparing sync message`);
const timestamp = Date.now();
const addressableMessages = await getMostRecentAddressableMessages(
this.id
);
const mostRecentMessages: Array<MessageToDelete> = addressableMessages
.map(getMessageToDelete)
.filter(isNotNil)
.slice(0, 5);
if (mostRecentMessages.length > 0) {
await singleProtoJobQueue.add(
MessageSender.getDeleteForMeSyncMessage([
{
type: 'delete-conversation',
conversation: getConversationToDelete(this.attributes),
isFullDelete: true,
mostRecentMessages,
timestamp,
},
])
);
} else {
await singleProtoJobQueue.add(
MessageSender.getDeleteForMeSyncMessage([
{
type: 'delete-local-conversation',
conversation: getConversationToDelete(this.attributes),
timestamp,
},
])
);
}
log.info(`${logId}: Sync message queue complete`);
}
log.info(`${logId}: Starting delete`);
await window.Signal.Data.removeMessagesInConversation(this.id, {
logId: this.idForLogging(),
});
log.info(`${logId}: Delete complete`);
}
getTitle(options?: { isShort?: boolean }): string {