Skip to content

Commit a48f42e

Browse files
committed
refactor: expose node events from LightningRepo
1 parent 85c1e5a commit a48f42e

File tree

13 files changed

+120
-103
lines changed

13 files changed

+120
-103
lines changed

app/src/main/java/to/bitkit/androidServices/LightningNodeService.kt

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ import android.content.Intent
77
import android.os.IBinder
88
import androidx.core.app.NotificationCompat
99
import dagger.hilt.android.AndroidEntryPoint
10+
import kotlinx.coroutines.CoroutineDispatcher
1011
import kotlinx.coroutines.CoroutineScope
11-
import kotlinx.coroutines.Dispatchers
1212
import kotlinx.coroutines.SupervisorJob
1313
import kotlinx.coroutines.cancel
1414
import kotlinx.coroutines.launch
1515
import org.lightningdevkit.ldknode.Event
1616
import to.bitkit.App
1717
import to.bitkit.R
1818
import to.bitkit.data.CacheStore
19+
import to.bitkit.di.UiDispatcher
1920
import to.bitkit.domain.commands.NotifyPaymentReceived
2021
import to.bitkit.domain.commands.NotifyPaymentReceivedHandler
2122
import to.bitkit.models.NewTransactionSheetDetails
2223
import to.bitkit.models.NotificationDetails
2324
import to.bitkit.repositories.LightningRepo
2425
import to.bitkit.repositories.WalletRepo
25-
import to.bitkit.services.LdkNodeEventBus
2626
import to.bitkit.ui.MainActivity
2727
import to.bitkit.ui.pushNotification
2828
import to.bitkit.utils.Logger
@@ -31,17 +31,18 @@ import javax.inject.Inject
3131
@AndroidEntryPoint
3232
class LightningNodeService : Service() {
3333

34-
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
34+
@Inject
35+
@UiDispatcher
36+
lateinit var uiDispatcher: CoroutineDispatcher
37+
38+
private val serviceScope by lazy { CoroutineScope(SupervisorJob() + uiDispatcher) }
3539

3640
@Inject
3741
lateinit var lightningRepo: LightningRepo
3842

3943
@Inject
4044
lateinit var walletRepo: WalletRepo
4145

42-
@Inject
43-
lateinit var ldkNodeEventBus: LdkNodeEventBus
44-
4546
@Inject
4647
lateinit var notifyPaymentReceivedHandler: NotifyPaymentReceivedHandler
4748

@@ -56,26 +57,24 @@ class LightningNodeService : Service() {
5657

5758
private fun setupService() {
5859
serviceScope.launch {
59-
launch {
60-
lightningRepo.start(
61-
eventHandler = { event ->
62-
walletRepo.refreshBip21ForEvent(event)
63-
handlePaymentReceived(event)
64-
}
65-
).onSuccess {
66-
val notification = createNotification()
67-
startForeground(NOTIFICATION_ID, notification)
68-
69-
walletRepo.setWalletExistsState()
70-
walletRepo.refreshBip21()
71-
walletRepo.syncBalances()
60+
lightningRepo.start(
61+
eventHandler = { event ->
62+
Logger.debug("LDK-node event received in $TAG: $event", context = TAG)
63+
handlePaymentReceived(event)
7264
}
65+
).onSuccess {
66+
val notification = createNotification()
67+
startForeground(NOTIFICATION_ID, notification)
68+
69+
walletRepo.setWalletExistsState()
70+
walletRepo.refreshBip21()
71+
walletRepo.syncBalances()
7372
}
7473
}
7574
}
7675

7776
private suspend fun handlePaymentReceived(event: Event) {
78-
if (event !in listOf(Event.PaymentReceived, Event.OnchainTransactionReceived)) return
77+
if (event !is Event.PaymentReceived && event !is Event.OnchainTransactionReceived) return
7978
val command = NotifyPaymentReceived.Command.from(event, includeNotification = true) ?: return
8079

8180
notifyPaymentReceivedHandler(command).onSuccess { result ->

app/src/main/java/to/bitkit/domain/commands/NotifyPaymentReceived.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package to.bitkit.domain.commands
33
import org.lightningdevkit.ldknode.Event
44
import to.bitkit.models.NewTransactionSheetDetails
55
import to.bitkit.models.NotificationDetails
6-
import to.bitkit.utils.Logger
76

87
sealed interface NotifyPaymentReceived {
98

app/src/main/java/to/bitkit/domain/commands/NotifyPaymentReceivedHandler.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ class NotifyPaymentReceivedHandler @Inject constructor(
4141
activityRepo.handleOnchainTransactionReceived(command.event.txid, command.event.details)
4242
if (command.event.details.amountSats > 0) {
4343
delay(DELAY_FOR_ACTIVITY_SYNC_MS)
44-
activityRepo.shouldShowReceivedSheet(command.event.txid, command.event.details.amountSats.toULong())
44+
activityRepo.shouldShowReceivedSheet(
45+
command.event.txid,
46+
command.event.details.amountSats.toULong()
47+
)
4548
} else {
4649
false
4750
}

app/src/main/java/to/bitkit/repositories/LightningRepo.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import kotlinx.coroutines.CoroutineDispatcher
1414
import kotlinx.coroutines.CoroutineScope
1515
import kotlinx.coroutines.SupervisorJob
1616
import kotlinx.coroutines.delay
17+
import kotlinx.coroutines.flow.MutableSharedFlow
1718
import kotlinx.coroutines.flow.MutableStateFlow
19+
import kotlinx.coroutines.flow.asSharedFlow
1820
import kotlinx.coroutines.flow.asStateFlow
1921
import kotlinx.coroutines.flow.filter
2022
import kotlinx.coroutines.flow.first
@@ -51,7 +53,6 @@ import to.bitkit.models.TransactionSpeed
5153
import to.bitkit.models.toCoinSelectAlgorithm
5254
import to.bitkit.models.toCoreNetwork
5355
import to.bitkit.services.CoreService
54-
import to.bitkit.services.LdkNodeEventBus
5556
import to.bitkit.services.LightningService
5657
import to.bitkit.services.LnurlChannelResponse
5758
import to.bitkit.services.LnurlService
@@ -73,7 +74,6 @@ import kotlin.time.Duration.Companion.seconds
7374
class LightningRepo @Inject constructor(
7475
@BgDispatcher private val bgDispatcher: CoroutineDispatcher,
7576
private val lightningService: LightningService,
76-
private val ldkNodeEventBus: LdkNodeEventBus,
7777
private val settingsStore: SettingsStore,
7878
private val coreService: CoreService,
7979
private val lspNotificationsService: LspNotificationsService,
@@ -86,6 +86,9 @@ class LightningRepo @Inject constructor(
8686
private val _lightningState = MutableStateFlow(LightningState())
8787
val lightningState = _lightningState.asStateFlow()
8888

89+
private val _nodeEvents = MutableSharedFlow<Event>(extraBufferCapacity = 64)
90+
val nodeEvents = _nodeEvents.asSharedFlow()
91+
8992
private val scope = CoroutineScope(bgDispatcher + SupervisorJob())
9093

9194
private var _eventHandler: NodeEventHandler? = null
@@ -263,7 +266,7 @@ class LightningRepo @Inject constructor(
263266
private suspend fun onEvent(event: Event) {
264267
handleLdkEvent(event)
265268
_eventHandler?.invoke(event)
266-
ldkNodeEventBus.emit(event)
269+
_nodeEvents.emit(event)
267270
}
268271

269272
fun setRecoveryMode(enabled: Boolean) {

app/src/main/java/to/bitkit/repositories/WalletRepo.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ class WalletRepo @Inject constructor(
5656
private val _balanceState = MutableStateFlow(BalanceState())
5757
val balanceState = _balanceState.asStateFlow()
5858

59+
init {
60+
repoScope.launch {
61+
lightningRepo.nodeEvents.collect { event ->
62+
if (!walletExists()) return@collect
63+
refreshBip21ForEvent(event)
64+
}
65+
}
66+
}
67+
5968
fun loadFromCache() {
6069
// TODO try keeping in sync with cache if performant and reliable
6170
repoScope.launch {
@@ -151,6 +160,8 @@ class WalletRepo @Inject constructor(
151160
}
152161

153162
suspend fun observeLdkWallet() = withContext(bgDispatcher) {
163+
// TODO:Refactor: when a sync event is emitted by ldk-node, do the sync, and
164+
// get rid of the entire polling mechanism.
154165
lightningRepo.getSyncFlow()
155166
.collect {
156167
runCatching {
@@ -189,6 +200,7 @@ class WalletRepo @Inject constructor(
189200
when (event) {
190201
is Event.ChannelReady -> {
191202
// Only refresh bolt11 if we can now receive on lightning
203+
Logger.debug("refreshBip21ForEvent: $event", context = TAG)
192204
if (lightningRepo.canReceive()) {
193205
lightningRepo.createInvoice(
194206
amountSats = _walletState.value.bip21AmountSats,
@@ -202,14 +214,16 @@ class WalletRepo @Inject constructor(
202214

203215
is Event.ChannelClosed -> {
204216
// Clear bolt11 if we can no longer receive on lightning
217+
Logger.debug("refreshBip21ForEvent: $event", context = TAG)
205218
if (!lightningRepo.canReceive()) {
206219
setBolt11("")
207220
updateBip21Url()
208221
}
209222
}
210223

211-
is Event.PaymentReceived -> {
224+
is Event.PaymentReceived, is Event.OnchainTransactionReceived -> {
212225
// Check if onchain address was used, generate new one if needed
226+
Logger.debug("refreshBip21ForEvent: $event", context = TAG)
213227
refreshAddressIfNeeded()
214228
updateBip21Url()
215229
}

app/src/main/java/to/bitkit/services/LdkNodeEventBus.kt

Lines changed: 0 additions & 17 deletions
This file was deleted.

app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalNodeViewModel.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import to.bitkit.models.formatToModernDisplay
2727
import to.bitkit.repositories.LightningRepo
2828
import to.bitkit.repositories.PreActivityMetadataRepo
2929
import to.bitkit.repositories.WalletRepo
30-
import to.bitkit.services.LdkNodeEventBus
3130
import to.bitkit.ui.screens.transfer.external.ExternalNodeContract.SideEffect
3231
import to.bitkit.ui.screens.transfer.external.ExternalNodeContract.UiState
3332
import to.bitkit.ui.shared.toast.ToastEventBus
@@ -38,7 +37,6 @@ import javax.inject.Inject
3837
@HiltViewModel
3938
class ExternalNodeViewModel @Inject constructor(
4039
@ApplicationContext private val context: Context,
41-
private val ldkNodeEventBus: LdkNodeEventBus,
4240
private val walletRepo: WalletRepo,
4341
private val lightningRepo: LightningRepo,
4442
private val settingsStore: SettingsStore,
@@ -210,7 +208,7 @@ class ExternalNodeViewModel @Inject constructor(
210208
}
211209

212210
private suspend fun awaitChannelPendingEvent(userChannelId: UserChannelId): Result<Event.ChannelPending> {
213-
return ldkNodeEventBus.events.watchUntil { event ->
211+
return lightningRepo.nodeEvents.watchUntil { event ->
214212
when (event) {
215213
is Event.ChannelClosed -> if (event.userChannelId == userChannelId) {
216214
WatchResult.Complete(Result.failure(Exception("${event.reason}")))

app/src/main/java/to/bitkit/ui/settings/lightning/LightningConnectionsViewModel.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import to.bitkit.repositories.BlocktankRepo
3737
import to.bitkit.repositories.LightningRepo
3838
import to.bitkit.repositories.LogsRepo
3939
import to.bitkit.repositories.WalletRepo
40-
import to.bitkit.services.LdkNodeEventBus
4140
import to.bitkit.ui.shared.toast.ToastEventBus
4241
import to.bitkit.utils.Logger
4342
import javax.inject.Inject
@@ -50,7 +49,6 @@ class LightningConnectionsViewModel @Inject constructor(
5049
private val lightningRepo: LightningRepo,
5150
internal val blocktankRepo: BlocktankRepo,
5251
private val logsRepo: LogsRepo,
53-
private val ldkNodeEventBus: LdkNodeEventBus,
5452
private val walletRepo: WalletRepo,
5553
private val activityRepo: ActivityRepo,
5654
) : ViewModel() {
@@ -129,7 +127,7 @@ class LightningConnectionsViewModel @Inject constructor(
129127

130128
private fun observeLdkEvents() {
131129
viewModelScope.launch {
132-
ldkNodeEventBus.events.collect { event ->
130+
lightningRepo.nodeEvents.collect { event ->
133131
if (event is Event.ChannelPending || event is Event.ChannelReady || event is Event.ChannelClosed) {
134132
Logger.debug("Channel event received: ${event::class.simpleName}, triggering refresh")
135133
refreshObservedState()

app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ import to.bitkit.repositories.LightningRepo
9494
import to.bitkit.repositories.PreActivityMetadataRepo
9595
import to.bitkit.repositories.WalletRepo
9696
import to.bitkit.services.AppUpdaterService
97-
import to.bitkit.services.LdkNodeEventBus
9897
import to.bitkit.ui.Routes
9998
import to.bitkit.ui.components.Sheet
10099
import to.bitkit.ui.components.TimedSheetType
@@ -116,7 +115,6 @@ class AppViewModel @Inject constructor(
116115
private val lightningRepo: LightningRepo,
117116
private val walletRepo: WalletRepo,
118117
private val backupRepo: BackupRepo,
119-
private val ldkNodeEventBus: LdkNodeEventBus,
120118
private val settingsStore: SettingsStore,
121119
private val currencyRepo: CurrencyRepo,
122120
private val activityRepo: ActivityRepo,
@@ -227,9 +225,10 @@ class AppViewModel @Inject constructor(
227225
@Suppress("CyclomaticComplexMethod")
228226
private fun observeLdkNodeEvents() {
229227
viewModelScope.launch {
230-
ldkNodeEventBus.events.collect { event ->
228+
lightningRepo.nodeEvents.collect { event ->
231229
if (!walletRepo.walletExists()) return@collect
232-
230+
Logger.debug("LDK-node event received in $TAG: $event", context = TAG)
231+
// TODO maybe use launch
233232
runCatching {
234233
when (event) {
235234
is Event.BalanceChanged -> handleBalanceChanged()
@@ -1112,6 +1111,7 @@ class AppViewModel @Inject constructor(
11121111
)
11131112
)
11141113
lightningRepo.sync()
1114+
activityRepo.syncActivities()
11151115
}.onFailure { e ->
11161116
Logger.error(msg = "Error sending onchain payment", e = e, context = TAG)
11171117
toast(
@@ -1291,7 +1291,7 @@ class AppViewModel @Inject constructor(
12911291
): Result<PaymentId> {
12921292
return lightningRepo.payInvoice(bolt11 = bolt11, sats = amount).onSuccess { hash ->
12931293
// Wait until matching payment event is received
1294-
val result = ldkNodeEventBus.events.watchUntil { event ->
1294+
val result = lightningRepo.nodeEvents.watchUntil { event ->
12951295
when (event) {
12961296
is Event.PaymentSuccessful -> {
12971297
if (event.paymentHash == hash) {

app/src/main/java/to/bitkit/viewmodels/QuickPayViewModel.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ import org.lightningdevkit.ldknode.PaymentId
1212
import to.bitkit.ext.WatchResult
1313
import to.bitkit.ext.watchUntil
1414
import to.bitkit.repositories.LightningRepo
15-
import to.bitkit.services.LdkNodeEventBus
1615
import to.bitkit.utils.Logger
1716
import javax.inject.Inject
1817

1918
@HiltViewModel
2019
class QuickPayViewModel @Inject constructor(
2120
private val lightningRepo: LightningRepo,
22-
private val ldkNodeEventBus: LdkNodeEventBus,
2321
) : ViewModel() {
2422

2523
private val _uiState = MutableStateFlow(QuickPayUiState())
@@ -80,7 +78,7 @@ class QuickPayViewModel @Inject constructor(
8078
.getOrDefault("")
8179

8280
// Wait until matching payment event is received
83-
val result = ldkNodeEventBus.events.watchUntil { event ->
81+
val result = lightningRepo.nodeEvents.watchUntil { event ->
8482
when (event) {
8583
is Event.PaymentSuccessful -> {
8684
if (event.paymentHash == hash) {

0 commit comments

Comments
 (0)