Refactor backup creation failures, add case for file too large.

This commit is contained in:
Greyson Parrelli
2025-11-07 13:52:37 -05:00
committed by Michelle Tang
parent ad0b240550
commit 945453cb81
12 changed files with 154 additions and 177 deletions

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import okio.withLock
import org.signal.core.util.LongSerializer
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.backup.DeletionState
import org.thoughtcrime.securesms.backup.RestoreState
@@ -67,7 +68,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
private const val KEY_BACKUP_UPLOADED = "backup.backupUploaded"
private const val KEY_SUBSCRIPTION_STATE_MISMATCH = "backup.subscriptionStateMismatch"
private const val KEY_BACKUP_FAIL = "backup.failed"
private const val KEY_BACKUP_CREATION_ERROR = "backup.creationError"
private const val KEY_BACKUP_FAIL_ACKNOWLEDGED_SNOOZE_TIME = "backup.failed.acknowledged.snooze.time"
private const val KEY_BACKUP_FAIL_ACKNOWLEDGED_SNOOZE_COUNT = "backup.failed.acknowledged.snooze.count"
private const val KEY_BACKUP_FAIL_SHEET_SNOOZE_TIME = "backup.failed.sheet.snooze"
@@ -77,7 +78,6 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
private const val KEY_NOT_ENOUGH_REMOTE_STORAGE_SPACE = "backup.not.enough.remote.storage.space"
private const val KEY_NOT_ENOUGH_REMOTE_STORAGE_SPACE_DISPLAY_SHEET = "backup.not.enough.remote.storage.space.display.sheet"
private const val KEY_MANUAL_NO_BACKUP_NOTIFIED = "backup.manual.no.backup.notified"
private const val KEY_VALIDATION_ERROR = "backup.validation.error"
private const val KEY_USER_MANUALLY_SKIPPED_MEDIA_RESTORE = "backup.user.manually.skipped.media.restore"
private const val KEY_BACKUP_EXPIRED_AND_DOWNGRADED = "backup.expired.and.downgraded"
@@ -259,7 +259,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
if (storedValue != value) {
clearNotEnoughRemoteStorageSpace()
clearMessageBackupFailure()
clearBackupCreationFailed()
clearMessageBackupFailureSheetWatermark()
}
@@ -302,10 +302,8 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
/** True if we believe we have successfully uploaded a backup, otherwise false. */
var hasBackupBeenUploaded: Boolean by booleanValue(KEY_BACKUP_UPLOADED, false)
/** Set when we fail to validate a user's backup during the export process */
var hasValidationError: Boolean by booleanValue(KEY_VALIDATION_ERROR, false)
val hasBackupFailure: Boolean get() = getBoolean(KEY_BACKUP_FAIL, false)
val hasBackupCreationError: Boolean get() = backupCreationError != null
val backupCreationError: BackupCreationError? by enumValue(KEY_BACKUP_CREATION_ERROR, null, BackupCreationError.serializer)
val nextBackupFailureSnoozeTime: Duration get() = getLong(KEY_BACKUP_FAIL_ACKNOWLEDGED_SNOOZE_TIME, 0L).milliseconds
val nextBackupFailureSheetSnoozeTime: Duration get() = getLong(KEY_BACKUP_FAIL_SHEET_SNOOZE_TIME, getNextBackupFailureSheetSnoozeTime(lastBackupTime.milliseconds).inWholeMilliseconds).milliseconds
@@ -343,11 +341,6 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
backupDownloadNotifierState = null
}
fun internalSetBackupFailedErrorState() {
markMessageBackupFailure()
putLong(KEY_BACKUP_FAIL_SHEET_SNOOZE_TIME, 0)
}
/**
* Call when the user disables backups. Clears/resets all relevant fields.
*/
@@ -458,9 +451,9 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
.apply()
}
fun markMessageBackupFailure() {
fun markBackupCreationFailed(error: BackupCreationError) {
store.beginWrite()
.putBoolean(KEY_BACKUP_FAIL, true)
.putLong(KEY_BACKUP_CREATION_ERROR, error.value)
.putLong(KEY_BACKUP_FAIL_ACKNOWLEDGED_SNOOZE_TIME, System.currentTimeMillis())
.putLong(KEY_BACKUP_FAIL_ACKNOWLEDGED_SNOOZE_COUNT, 0)
.putLong(KEY_BACKUP_FAIL_SHEET_SNOOZE_TIME, System.currentTimeMillis())
@@ -468,7 +461,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
}
fun updateMessageBackupFailureWatermark() {
if (!hasBackupFailure) {
if (!hasBackupCreationError) {
return
}
@@ -485,8 +478,8 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
.apply()
}
fun clearMessageBackupFailure() {
putBoolean(KEY_BACKUP_FAIL, false)
fun clearBackupCreationFailed() {
putLong(KEY_BACKUP_CREATION_ERROR, -1)
}
fun updateMessageBackupFailureSheetWatermark() {
@@ -587,4 +580,28 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
putLong(cdnTimestampKey, System.currentTimeMillis())
}
}
enum class BackupCreationError(val value: Long) {
/** A temporary failure, usually cause by poor network. */
TRANSIENT(1),
/** The validation of the backup file failed. This likely cannot be fixed without an app update. */
VALIDATION(2),
/** The backup file itself is too large. The only resolution would be for the user to delete some number of messages. */
BACKUP_FILE_TOO_LARGE(3);
companion object {
val serializer = object : LongSerializer<BackupCreationError?> {
override fun serialize(data: BackupCreationError?): Long {
return data?.value ?: -1
}
override fun deserialize(input: Long): BackupCreationError? {
return entries.firstOrNull { it.value == input }
}
}
}
}
}