Copy quotes to the archive as they're received.

This commit is contained in:
Greyson Parrelli
2026-03-11 14:04:50 -04:00
committed by jeffrey-signal
parent 456aaa54f1
commit be920148e7
4 changed files with 76 additions and 26 deletions

View File

@@ -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<AttachmentId> {
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.

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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<DatabaseAttachment> = 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<AttachmentDownloadJob> = attachments.map { AttachmentDownloadJob(messageId = messageId, attachmentId = it.attachmentId, forceDownload = it.isSticker) }
AppDependencies.jobManager.addAll(downloadJobs)
if (insertResult.insertedAttachments != null) {
val downloadJobs: List<AttachmentDownloadJob> = 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