Calculate remote backup media quota usage locally.

This commit is contained in:
Cody Henthorne
2025-06-06 10:47:32 -04:00
committed by Greyson Parrelli
parent efa9dd6ec3
commit 882a11c420
12 changed files with 119 additions and 37 deletions

View File

@@ -688,6 +688,8 @@ class AttachmentTable(
.where("$DATA_FILE = ?", dataFile)
.run()
}
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
}
/**
@@ -709,6 +711,8 @@ class AttachmentTable(
.where("$ARCHIVE_TRANSFER_STATE != ? AND $DATA_FILE = ?", ArchiveTransferState.PERMANENT_FAILURE.value, dataFile)
.run()
}
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
}
/**
@@ -2586,6 +2590,51 @@ class AttachmentTable(
.readToList { AttachmentId(it.requireLong(ID)) }
}
fun getEstimatedArchiveMediaSize(): Long {
val estimatedThumbnailCount = readableDatabase
.select("COUNT(DISTINCT $REMOTE_DIGEST)")
.from(TABLE_NAME)
.where(
"""
$DATA_FILE NOT NULL AND
$REMOTE_DIGEST NOT NULL AND
$TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND
$ARCHIVE_TRANSFER_STATE != ${ArchiveTransferState.PERMANENT_FAILURE.value} AND
($CONTENT_TYPE LIKE 'image/%' OR $CONTENT_TYPE LIKE 'video/%')
"""
)
.run()
.readToSingleLong(0L)
val uploadedAttachmentBytes = readableDatabase
.rawQuery(
"""
SELECT $DATA_SIZE
FROM (
SELECT DISTINCT $REMOTE_DIGEST, $DATA_SIZE
FROM $TABLE_NAME
WHERE
$DATA_FILE NOT NULL AND
$REMOTE_DIGEST NOT NULL AND
$TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND
$ARCHIVE_TRANSFER_STATE != ${ArchiveTransferState.PERMANENT_FAILURE.value}
)
"""
)
.readToList { it.requireLong(DATA_SIZE) }
.sumOf {
val paddedSize = PaddingInputStream.getPaddedSize(it)
val clientEncryptedSize = AttachmentCipherStreamUtil.getCiphertextLength(paddedSize)
val serverEncryptedSize = AttachmentCipherStreamUtil.getCiphertextLength(clientEncryptedSize)
serverEncryptedSize
}
val estimatedUploadedThumbnailBytes = RemoteConfig.backupMaxThumbnailFileSize.inWholeBytes * estimatedThumbnailCount
return uploadedAttachmentBytes + estimatedUploadedThumbnailBytes
}
private fun getTransferFile(db: SQLiteDatabase, attachmentId: AttachmentId): File? {
return db
.select(TRANSFER_FILE)

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.database
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
/**
* Observe attachment deletions.
*/
fun DatabaseObserver.attachmentDeletions(): Flow<Unit> {
return observe { registerAttachmentDeletedObserver(it) }
}
/**
* Observe attachment updates.
*/
fun DatabaseObserver.attachmentUpdates(): Flow<Unit> {
return observe { registerAttachmentUpdatedObserver(it) }
}
/**
* Helper to register flow-ize database observer
*/
private fun DatabaseObserver.observe(registerObserver: DatabaseObserver.(listener: DatabaseObserver.Observer) -> Unit): Flow<Unit> {
return callbackFlow {
val listener = DatabaseObserver.Observer {
trySend(Unit)
}
this@observe.registerObserver(listener)
awaitClose {
this@observe.unregisterObserver(listener)
}
}
}