zcash-android-wallet-zcon1/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/data/ReceivedTransactionReposito...

89 lines
3.0 KiB
Kotlin

package cash.z.android.wallet.data
import androidx.room.Room
import androidx.room.RoomDatabase
import cash.z.android.wallet.ZcashWalletApplication
import cash.z.android.wallet.vo.WalletTransaction
import cash.z.android.wallet.vo.WalletTransactionStatus
import cash.z.wallet.sdk.dao.BlockDao
import cash.z.wallet.sdk.dao.NoteDao
import cash.z.wallet.sdk.dao.TransactionDao
import cash.z.wallet.sdk.db.DerivedDataDb
import cash.z.wallet.sdk.vo.NoteQuery
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import java.math.BigDecimal
class ReceivedTransactionRepository(val scope: CoroutineScope) : TransactionRepository {
private var db = injectDb()
private lateinit var transactions: TransactionDao
private lateinit var blocks: BlockDao
private lateinit var notes: NoteDao
private var existingTransactions = linkedSetOf<WalletTransaction>()
private var existingBalance = BigDecimal.ZERO
private var balanceChannel = BroadcastChannel<BigDecimal>(100)
private fun injectDb() = Room
.databaseBuilder(ZcashWalletApplication.instance, DerivedDataDb::class.java, "tmp")
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
.fallbackToDestructiveMigration()
.build()
.apply {
transactions = transactionDao()
blocks = blockDao()
notes = noteDao()
}
/**
* Just send a sample stream of balances, every so often
*/
override fun balance() = balanceChannel.openSubscription()
/**
* Just send a sample stream of transactions, every so often
*/
override fun transactions(): ReceiveChannel<WalletTransaction> = scope.produce {
while (isActive) {
delay(1500L)
val newTransactions = checkForNewTransactions()
newTransactions?.forEach {
existingTransactions.add(it)
send(it)
updateBalance(it)
}
}
}
private suspend fun updateBalance(tx: WalletTransaction) {
val multiplier = when (tx.status) {
WalletTransactionStatus.SENT -> -1.0
WalletTransactionStatus.RECEIVED -> 1.0
}
existingBalance += tx.amount.multiply(BigDecimal(multiplier))
balanceChannel.send(existingBalance)
}
private fun checkForNewTransactions(): Set<WalletTransaction>? {
val count = notes.count()
if(count == existingTransactions.size) return null
val notes = notes.getAll().map { toWalletTransaction(it) }
return notes.subtract(existingTransactions)
}
private fun toWalletTransaction(note: NoteQuery): WalletTransaction {
return WalletTransaction(
height = note.height,
status = WalletTransactionStatus.RECEIVED,
amount = BigDecimal(note.value / 1e8),
timestamp = note.time
)
}
}