diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt index 3867bf1e90..6b28944fd2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt @@ -1981,8 +1981,53 @@ class AttachmentTable( } fun createRemoteKeyIfNecessary(attachmentId: AttachmentId) { - val key = Util.getSecretBytes(64) + val dataFile = getDataFilePath(attachmentId) + if (dataFile != null) { + val duplicate = readableDatabase + .select() + .from(TABLE_NAME) + .where("$DATA_FILE = ? AND $REMOTE_KEY NOT NULL AND LENGTH($REMOTE_KEY) > 0", dataFile) + .orderBy("(CASE WHEN $REMOTE_LOCATION IS NOT NULL AND $REMOTE_DIGEST IS NOT NULL THEN 0 ELSE 1 END), $ID DESC") + .run() + .readToSingleObject { cursor -> cursor.readAttachment() to cursor.readDataFileInfo() } + + if (duplicate != null) { + val (duplicateAttachment, dataFileInfo) = duplicate + + if (duplicateAttachment.remoteLocation != null && duplicateAttachment.remoteDigest != null && dataFileInfo != null) { + Log.w(TAG, "[createRemoteKeyIfNecessary][$attachmentId] Found duplicate with full remote data. Copying all remote data.") + writableDatabase + .update(TABLE_NAME) + .values( + REMOTE_KEY to duplicateAttachment.remoteKey, + REMOTE_LOCATION to duplicateAttachment.remoteLocation, + REMOTE_DIGEST to duplicateAttachment.remoteDigest, + REMOTE_INCREMENTAL_DIGEST to duplicateAttachment.incrementalDigest?.takeIf { it.isNotEmpty() }, + REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE to duplicateAttachment.incrementalMacChunkSize, + UPLOAD_TIMESTAMP to duplicateAttachment.uploadTimestamp, + ARCHIVE_CDN to duplicateAttachment.archiveCdn, + ARCHIVE_TRANSFER_STATE to duplicateAttachment.archiveTransferState.value, + THUMBNAIL_FILE to dataFileInfo.thumbnailFile, + THUMBNAIL_RANDOM to dataFileInfo.thumbnailRandom, + THUMBNAIL_RESTORE_STATE to dataFileInfo.thumbnailRestoreState + ) + .where("$ID = ? AND ($REMOTE_KEY IS NULL OR LENGTH($REMOTE_KEY) = 0)", attachmentId.id) + .run() + } else { + Log.w(TAG, "[createRemoteKeyIfNecessary][$attachmentId] Found duplicate with key only. Copying key.") + writableDatabase + .update(TABLE_NAME) + .values(REMOTE_KEY to duplicateAttachment.remoteKey) + .where("$ID = ? AND ($REMOTE_KEY IS NULL OR LENGTH($REMOTE_KEY) = 0)", attachmentId.id) + .run() + } + return + } + } + + val key = Util.getSecretBytes(64) + Log.w(TAG, "[createRemoteKeyIfNecessary][$attachmentId] Missing key. Assigning new one.") writableDatabase .update(TABLE_NAME) .values(REMOTE_KEY to Base64.encodeWithPadding(key)) @@ -1990,24 +2035,6 @@ class AttachmentTable( .run() } - /** - * A query for a specific migration. Retrieves attachments that we'd need to create a new digest for. - * This is basically all attachments that have data and are finished downloading. - */ - fun getAttachmentsThatNeedNewDigests(): List { - return readableDatabase - .select(ID) - .from(TABLE_NAME) - .where( - """ - $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND - $DATA_FILE NOT NULL - """ - ) - .run() - .readToList { AttachmentId(it.requireLong(ID)) } - } - /** * A query for a specific migration. Retrieves attachments that we'd need to create a new digest for. * This is basically all attachments that have data and are finished downloading. diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt index 4c88129310..25b2e35284 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt @@ -42,11 +42,11 @@ class ArchiveAttachmentBackfillJob private constructor(parameters: Parameters) : return Result.success() } + SignalDatabase.attachments.createRemoteKeyForAttachmentsThatNeedArchiveUpload() + val jobs = SignalDatabase.attachments.getAttachmentsThatNeedArchiveUpload() .map { attachmentId -> UploadAttachmentToArchiveJob(attachmentId) } - SignalDatabase.attachments.createRemoteKeyForAttachmentsThatNeedArchiveUpload() - ArchiveUploadProgress.onAttachmentSectionStarted(SignalDatabase.attachments.getPendingArchiveUploadBytes()) if (!isCanceled) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt index 93ea8edf3f..437eb45b22 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt @@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob import org.thoughtcrime.securesms.jobs.StorageSyncJob import org.thoughtcrime.securesms.jobs.TrimThreadJob +import org.thoughtcrime.securesms.jobs.UploadAttachmentToArchiveJob import org.thoughtcrime.securesms.jobs.protos.GroupCallPeekJobData import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.linkpreview.LinkPreview @@ -984,6 +985,11 @@ object DataMessageProcessor { AppDependencies.jobManager.addAll(downloadJobs) } + if (insertResult.quoteAttachmentId != null && SignalStore.backup.backsUpMedia) { + SignalDatabase.attachments.createRemoteKeyIfNecessary(insertResult.quoteAttachmentId) + AppDependencies.jobManager.add(UploadAttachmentToArchiveJob(insertResult.quoteAttachmentId)) + } + AppDependencies.messageNotifier.updateNotification(context, ConversationId.forConversation(insertResult.threadId)) TrimThreadJob.enqueueAsync(insertResult.threadId) diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt index 1cbc2e6d2b..940788a055 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt @@ -70,6 +70,7 @@ import org.thoughtcrime.securesms.jobs.RefreshCallLinkDetailsJob import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob import org.thoughtcrime.securesms.jobs.StorageSyncJob +import org.thoughtcrime.securesms.jobs.UploadAttachmentToArchiveJob import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.linkpreview.LinkPreview import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.log @@ -871,7 +872,8 @@ object SyncMessageProcessor { } val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) - val messageId: Long = SignalDatabase.messages.insertMessageOutbox(mediaMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId + val insertResult = SignalDatabase.messages.insertMessageOutbox(mediaMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null) + val messageId = insertResult.messageId log(envelopeTimestamp, "Inserted sync message as messageId $messageId") if (recipient.isGroup) { @@ -882,8 +884,6 @@ object SyncMessageProcessor { SignalDatabase.messages.markAsSent(messageId, true) - val attachments: List = SignalDatabase.attachments.getAttachmentsForMessage(messageId) - if (dataMessage.expireTimerDuration > Duration.ZERO) { SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) @@ -895,8 +895,25 @@ object SyncMessageProcessor { } SignalDatabase.runPostSuccessfulTransaction { - val downloadJobs: List = attachments.map { AttachmentDownloadJob(messageId = messageId, attachmentId = it.attachmentId, forceDownload = it.isSticker) } - AppDependencies.jobManager.addAll(downloadJobs) + if (insertResult.insertedAttachments != null) { + val downloadJobs: List = insertResult.insertedAttachments.mapNotNull { (attachment, attachmentId) -> + if (attachment.isSticker) { + if (attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_DONE) { + AttachmentDownloadJob(messageId = insertResult.messageId, attachmentId = attachmentId, forceDownload = true) + } else { + null + } + } else { + AttachmentDownloadJob(messageId = insertResult.messageId, attachmentId = attachmentId, forceDownload = false) + } + } + AppDependencies.jobManager.addAll(downloadJobs) + } + + if (insertResult.quoteAttachmentId != null && SignalStore.backup.backsUpMedia) { + SignalDatabase.attachments.createRemoteKeyIfNecessary(insertResult.quoteAttachmentId) + AppDependencies.jobManager.add(UploadAttachmentToArchiveJob(insertResult.quoteAttachmentId)) + } } return threadId