feat: add history sync worker
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package com.bitcointxoko.gudariwallet.sync
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.bitcointxoko.gudariwallet.data.HistoricalSyncStore
|
||||
import com.bitcointxoko.gudariwallet.data.PaymentCacheRepository
|
||||
import com.bitcointxoko.gudariwallet.data.WalletRepository
|
||||
import com.bitcointxoko.gudariwallet.util.NotificationHelper
|
||||
|
||||
private const val TAG = "HistoricalSyncWorker"
|
||||
private const val PAGE_SIZE = 100
|
||||
|
||||
class HistoricalSyncWorker(
|
||||
appContext : Context,
|
||||
params : WorkerParameters,
|
||||
private val repo : WalletRepository,
|
||||
private val paymentCache : PaymentCacheRepository,
|
||||
private val syncStore : HistoricalSyncStore
|
||||
) : CoroutineWorker(appContext, params) {
|
||||
|
||||
companion object {
|
||||
const val KEY_FETCHED = "fetched"
|
||||
const val KEY_TOTAL = "total"
|
||||
}
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
// Guard: already completed — safe if WorkManager ever retries a success
|
||||
if (syncStore.isComplete()) {
|
||||
Log.d(TAG, "Already complete — skipping")
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
Log.d(TAG, "Starting historical payment sync")
|
||||
var offset = 0
|
||||
var total = -1
|
||||
|
||||
while (true) {
|
||||
val page = runCatching {
|
||||
repo.getPaymentsPaginated(offset = offset, limit = PAGE_SIZE)
|
||||
}.getOrElse { e ->
|
||||
Log.w(TAG, "Network error on offset=$offset: ${e.message} — scheduling retry")
|
||||
return Result.retry() // WorkManager applies exponential backoff automatically
|
||||
}
|
||||
|
||||
// First page: learn the real total from the server
|
||||
if (total == -1) {
|
||||
total = page.total
|
||||
Log.d(TAG, "Server reports $total total payments")
|
||||
if (total == 0) {
|
||||
syncStore.markComplete()
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
// Full overwrite — mergePayments uses INSERT OR REPLACE, no skip logic
|
||||
paymentCache.mergePayments(page.data)
|
||||
offset += page.data.size
|
||||
|
||||
Log.d(TAG, "Progress: $offset / $total")
|
||||
setProgress(workDataOf(
|
||||
KEY_FETCHED to offset,
|
||||
KEY_TOTAL to total
|
||||
))
|
||||
|
||||
// Stop if server returned a short page (end of data) or we've reached total
|
||||
if (page.data.size < PAGE_SIZE || offset >= total) break
|
||||
}
|
||||
|
||||
syncStore.markComplete()
|
||||
Log.d(TAG, "Historical sync complete — $offset payments stored")
|
||||
NotificationHelper.notifySyncComplete(applicationContext, offset)
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.bitcointxoko.gudariwallet.sync
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.ListenableWorker
|
||||
import androidx.work.WorkerFactory
|
||||
import androidx.work.WorkerParameters
|
||||
import com.bitcointxoko.gudariwallet.data.HistoricalSyncStore
|
||||
import com.bitcointxoko.gudariwallet.data.PaymentCacheRepository
|
||||
import com.bitcointxoko.gudariwallet.data.WalletRepository
|
||||
|
||||
class HistoricalSyncWorkerFactory(
|
||||
private val repo : WalletRepository,
|
||||
private val paymentCache : PaymentCacheRepository,
|
||||
private val syncStore : HistoricalSyncStore
|
||||
) : WorkerFactory() {
|
||||
|
||||
override fun createWorker(
|
||||
appContext : Context,
|
||||
workerClassName : String,
|
||||
workerParameters : WorkerParameters
|
||||
): ListenableWorker? =
|
||||
if (workerClassName == HistoricalSyncWorker::class.java.name)
|
||||
HistoricalSyncWorker(appContext, workerParameters, repo, paymentCache, syncStore)
|
||||
else
|
||||
null // return null to delegate to the next factory in the chain
|
||||
}
|
||||
Reference in New Issue
Block a user