Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions app/src/main/java/to/bitkit/repositories/BackupRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.datetime.Clock
Expand Down Expand Up @@ -63,7 +67,8 @@ class BackupRepo @Inject constructor(
private val dataListenerJobs = mutableListOf<Job>()
private var periodicCheckJob: Job? = null
private var isObserving = false
private var isRestoring = false
private val _isRestoring = MutableStateFlow(false)
val isRestoring: StateFlow<Boolean> = _isRestoring.asStateFlow()

private var lastNotificationTime = 0L

Expand Down Expand Up @@ -119,7 +124,7 @@ class BackupRepo @Inject constructor(
old.synced == new.synced && old.required == new.required
}
.collect { status ->
if (status.isRequired && !status.running && !isRestoring) {
if (status.isRequired && !status.running && !isRestoring.value) {
scheduleBackup(category)
}
}
Expand All @@ -137,7 +142,7 @@ class BackupRepo @Inject constructor(
.distinctUntilChanged()
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.SETTINGS)
}
}
Expand All @@ -148,7 +153,7 @@ class BackupRepo @Inject constructor(
.distinctUntilChanged()
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.WIDGETS)
}
}
Expand All @@ -160,7 +165,7 @@ class BackupRepo @Inject constructor(
.distinctUntilChanged()
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.WALLET)
}
}
Expand All @@ -172,7 +177,7 @@ class BackupRepo @Inject constructor(
.distinctUntilChanged()
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.METADATA)
}
}
Expand All @@ -185,7 +190,7 @@ class BackupRepo @Inject constructor(
.distinctUntilChanged()
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.METADATA)
}
}
Expand All @@ -196,7 +201,7 @@ class BackupRepo @Inject constructor(
blocktankRepo.blocktankState
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.BLOCKTANK)
}
}
Expand All @@ -207,7 +212,7 @@ class BackupRepo @Inject constructor(
activityRepo.activitiesChanged
.drop(1)
.collect {
if (isRestoring) return@collect
if (isRestoring.value) return@collect
markBackupRequired(BackupCategory.ACTIVITY)
}
}
Expand All @@ -220,7 +225,7 @@ class BackupRepo @Inject constructor(
val lastSync = lightningService.status?.latestLightningWalletSyncTimestamp?.toLong()
?.let { it * 1000 } // Convert seconds to millis
?: return@collect
if (isRestoring) return@collect
if (isRestoring.value) return@collect
cacheStore.updateBackupStatus(BackupCategory.LIGHTNING_CONNECTIONS) {
it.copy(required = lastSync, synced = lastSync, running = false)
}
Expand Down Expand Up @@ -265,7 +270,7 @@ class BackupRepo @Inject constructor(

// Double-check if backup is still needed
val status = cacheStore.backupStatuses.first()[category] ?: BackupItemStatus()
if (status.isRequired && !isRestoring) {
if (status.isRequired && !isRestoring.value) {
triggerBackup(category)
} else {
// Backup no longer needed, reset running flag
Expand Down Expand Up @@ -407,12 +412,13 @@ class BackupRepo @Inject constructor(
): Result<Unit> = withContext(ioDispatcher) {
Logger.debug("Full restore starting", context = TAG)

isRestoring = true
_isRestoring.update { true }

return@withContext try {
performRestore(BackupCategory.METADATA) { dataBytes ->
val parsed = json.decodeFromString<MetadataBackupV1>(String(dataBytes))
cacheStore.update { parsed.cache }
val caches = parsed.cache.copy(onchainAddress = "") // Force onchain address rotation
cacheStore.update { caches }
Logger.debug("Restored caches: ${jsonLogOf(parsed.cache.copy(cachedRates = emptyList()))}", TAG)
onCacheRestored()
db.tagMetadataDao().upsert(parsed.tagMetadata)
Expand Down Expand Up @@ -454,7 +460,7 @@ class BackupRepo @Inject constructor(
Logger.warn("Full restore error", e = e, context = TAG)
Result.failure(e)
} finally {
isRestoring = false
_isRestoring.update { false }
}
}

Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import to.bitkit.models.TransactionSpeed
import to.bitkit.models.toActivityFilter
import to.bitkit.models.toTxType
import to.bitkit.repositories.ActivityRepo
import to.bitkit.repositories.BackupRepo
import to.bitkit.repositories.BlocktankRepo
import to.bitkit.repositories.ConnectivityRepo
import to.bitkit.repositories.ConnectivityState
Expand Down Expand Up @@ -106,6 +107,7 @@ class AppViewModel @Inject constructor(
private val keychain: Keychain,
private val lightningRepo: LightningRepo,
private val walletRepo: WalletRepo,
private val backupRepo: BackupRepo,
private val ldkNodeEventBus: LdkNodeEventBus,
private val settingsStore: SettingsStore,
private val currencyRepo: CurrencyRepo,
Expand Down Expand Up @@ -1578,6 +1580,8 @@ class AppViewModel @Inject constructor(
return
}

if (backupRepo.isRestoring.value) return

timedSheetsScope?.cancel()
timedSheetsScope = CoroutineScope(bgDispatcher + SupervisorJob())
timedSheetsScope?.launch {
Expand Down
Loading