Skip to content

Commit c545630

Browse files
authored
Merge pull request #358 from synonymdev/feat/fcm-newtoken-register
feat: register for lsp notifications on new token
2 parents 97db5f5 + fedfa94 commit c545630

File tree

13 files changed

+47
-109
lines changed

13 files changed

+47
-109
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ android {
8484
keyPassword = "android"
8585
}
8686
create("release") {
87-
val keystoreFile = keystoreProperties.getProperty("storeFile").takeIf { it.isNotBlank() }
87+
val keystoreFile = keystoreProperties.getProperty("storeFile").takeIf { it.isNotEmpty() }
8888
?.let { rootProject.file(it) }
8989
storeFile = if (keystoreFile?.exists() == true) keystoreFile else null
9090
// storeFile = rootProject.file(keystoreProperties.getProperty("storeFile"))
@@ -201,7 +201,6 @@ dependencies {
201201
// Firebase
202202
implementation(platform(libs.firebase.bom))
203203
implementation(libs.firebase.messaging)
204-
implementation(libs.firebase.analytics)
205204
// Lifecycle
206205
implementation(libs.lifecycle.viewmodel.ktx)
207206
implementation(libs.lifecycle.viewmodel.compose) // ViewModel utils for Compose

app/src/androidTest/java/to/bitkit/services/BlocktankTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class BlocktankTest {
3838
Env.initAppStoragePath(testDbPath)
3939
initDb(testDbPath)
4040
runBlocking {
41-
updateBlocktankUrl(Env.blocktankClientServer)
41+
updateBlocktankUrl(Env.blocktankApiUrl)
4242
}
4343
}
4444

app/src/main/java/to/bitkit/data/SettingsStore.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.datastore.dataStore
66
import dagger.hilt.android.qualifiers.ApplicationContext
77
import kotlinx.coroutines.flow.Flow
88
import kotlinx.serialization.Serializable
9+
import org.lightningdevkit.ldknode.Network
910
import to.bitkit.data.serializers.SettingsSerializer
1011
import to.bitkit.env.Env
1112
import to.bitkit.models.BitcoinDisplayUnit
@@ -88,7 +89,7 @@ data class SettingsData(
8889
val isBiometricEnabled: Boolean = false,
8990
val isPinOnIdleEnabled: Boolean = false,
9091
val isPinForPaymentsEnabled: Boolean = false,
91-
val isDevModeEnabled: Boolean = false,
92+
val isDevModeEnabled: Boolean = Env.network != Network.BITCOIN,
9293
val showWidgets: Boolean = true,
9394
val showWidgetTitles: Boolean = false,
9495
val lastUsedTags: List<String> = emptyList(),

app/src/main/java/to/bitkit/env/Env.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@ internal object Env {
6363
get() = when (network) {
6464
Network.REGTEST -> "https://api.stag0.blocktank.to"
6565
Network.TESTNET -> "https://api.stag0.blocktank.to"
66+
Network.BITCOIN -> "https://api1.blocktank.to/"
6667
else -> TODO("${network.name} network not implemented")
6768
}
69+
val blocktankApiUrl get() = "$blocktankBaseUrl/blocktank/api/v2"
70+
val blocktankNotificationApiUrl
71+
get() = when (network) {
72+
Network.BITCOIN -> "$blocktankBaseUrl/api/notifications"
73+
else -> "$blocktankBaseUrl/notifications/api"
74+
}
6875

69-
val blocktankClientServer get() = "$blocktankBaseUrl/blocktank/api/v2"
70-
val blocktankPushNotificationServer get() = "$blocktankBaseUrl/notifications/api"
71-
72-
// const val btcRatesServer = "https://blocktank.synonym.to/fx/rates/btc/"
7376
const val btcRatesServer = "https://api1.blocktank.to/api/fx/rates/btc"
7477
const val geoCheckUrl = "https://api1.blocktank.to/api/geocheck"
7578
const val chatwootUrl = "https://synonym.to/api/chatwoot"
@@ -158,7 +161,7 @@ internal object Env {
158161
host = "electrum.blockstream.info",
159162
tcp = 60001, // or 50001
160163
ssl = 60002, // or 50002
161-
protocol = ElectrumProtocol.TCP,
164+
protocol = ElectrumProtocol.SSL,
162165
)
163166
val REGTEST = ElectrumServer(
164167
host = "34.65.252.32",

app/src/main/java/to/bitkit/fcm/FcmService.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import to.bitkit.env.Env.DERIVATION_NAME
1717
import to.bitkit.ext.fromBase64
1818
import to.bitkit.ext.fromHex
1919
import to.bitkit.models.BlocktankNotificationType
20+
import to.bitkit.repositories.LightningRepo
2021
import to.bitkit.ui.pushNotification
2122
import to.bitkit.utils.Crypto
2223
import to.bitkit.utils.Logger
@@ -25,6 +26,10 @@ import javax.inject.Inject
2526

2627
@AndroidEntryPoint
2728
class FcmService : FirebaseMessagingService() {
29+
companion object {
30+
private const val TAG = "FcmService"
31+
}
32+
2833
private var notificationType: BlocktankNotificationType? = null
2934
private var notificationPayload: JsonObject? = null
3035

@@ -34,6 +39,9 @@ class FcmService : FirebaseMessagingService() {
3439
@Inject
3540
lateinit var keychain: Keychain
3641

42+
@Inject
43+
lateinit var lightningRepo: LightningRepo
44+
3745
/**
3846
* Act on received messages. [Debug](https://goo.gl/39bRNJ)
3947
*/
@@ -137,14 +145,14 @@ class FcmService : FirebaseMessagingService() {
137145
val decoded = json.decodeFromString<T>(encoded)
138146
block(decoded)
139147
true
140-
} catch (e: SerializationException) {
148+
} catch (_: SerializationException) {
141149
false
142150
}
143151
}
144152

145153
override fun onNewToken(token: String) {
146-
// this.token = token
147-
// TODO call blocktankService.registerDevice(token)
154+
Logger.debug("Got new FCM token via FirebaseMessagingService.onNewToken: '$token'", context = TAG)
155+
lightningRepo.registerForNotificationsAsync(token)
148156
}
149157
}
150158

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ import com.synonym.bitkitcore.createWithdrawCallbackUrl
99
import com.synonym.bitkitcore.decode
1010
import com.synonym.bitkitcore.lnurlAuth
1111
import kotlinx.coroutines.CoroutineDispatcher
12+
import kotlinx.coroutines.CoroutineScope
13+
import kotlinx.coroutines.SupervisorJob
1214
import kotlinx.coroutines.delay
1315
import kotlinx.coroutines.flow.Flow
1416
import kotlinx.coroutines.flow.MutableStateFlow
1517
import kotlinx.coroutines.flow.asStateFlow
1618
import kotlinx.coroutines.flow.first
1719
import kotlinx.coroutines.flow.update
20+
import kotlinx.coroutines.launch
1821
import kotlinx.coroutines.tasks.await
1922
import kotlinx.coroutines.withContext
2023
import kotlinx.coroutines.withTimeout
@@ -42,13 +45,13 @@ import to.bitkit.models.NodeLifecycleState
4245
import to.bitkit.models.TransactionSpeed
4346
import to.bitkit.models.toCoinSelectAlgorithm
4447
import to.bitkit.models.toCoreNetwork
45-
import to.bitkit.services.BlocktankNotificationsService
4648
import to.bitkit.services.CoreService
4749
import to.bitkit.services.LdkNodeEventBus
4850
import to.bitkit.services.LightningService
4951
import to.bitkit.services.LnurlChannelResponse
5052
import to.bitkit.services.LnurlService
5153
import to.bitkit.services.LnurlWithdrawResponse
54+
import to.bitkit.services.LspNotificationsService
5255
import to.bitkit.services.NodeEventHandler
5356
import to.bitkit.utils.Logger
5457
import to.bitkit.utils.ServiceError
@@ -67,7 +70,7 @@ class LightningRepo @Inject constructor(
6770
private val ldkNodeEventBus: LdkNodeEventBus,
6871
private val settingsStore: SettingsStore,
6972
private val coreService: CoreService,
70-
private val blocktankNotificationsService: BlocktankNotificationsService,
73+
private val lspNotificationsService: LspNotificationsService,
7174
private val firebaseMessaging: FirebaseMessaging,
7275
private val keychain: Keychain,
7376
private val lnurlService: LnurlService,
@@ -76,6 +79,8 @@ class LightningRepo @Inject constructor(
7679
private val _lightningState = MutableStateFlow(LightningState())
7780
val lightningState = _lightningState.asStateFlow()
7881

82+
private val scope = CoroutineScope(bgDispatcher + SupervisorJob())
83+
7984
private var cachedEventHandler: NodeEventHandler? = null
8085

8186
/**
@@ -698,25 +703,26 @@ class LightningRepo @Inject constructor(
698703
fun hasChannels(): Boolean =
699704
_lightningState.value.nodeLifecycleState.isRunning() && lightningService.channels?.isNotEmpty() == true
700705

701-
// Notification handling
702-
suspend fun registerForNotifications(): Result<Unit> = executeWhenNodeRunning("Register for notifications") {
706+
suspend fun registerForNotifications(token: String? = null) = executeWhenNodeRunning("registerForNotifications") {
703707
return@executeWhenNodeRunning try {
704-
val token = firebaseMessaging.token.await()
708+
val token = token ?: firebaseMessaging.token.await()
705709
val cachedToken = keychain.loadString(Keychain.Key.PUSH_NOTIFICATION_TOKEN.name)
706710

707711
if (cachedToken == token) {
708712
Logger.debug("Skipped registering for notifications, current device token already registered")
709713
return@executeWhenNodeRunning Result.success(Unit)
710714
}
711715

712-
blocktankNotificationsService.registerDevice(token)
716+
lspNotificationsService.registerDevice(token)
713717
Result.success(Unit)
714718
} catch (e: Throwable) {
715719
Logger.error("Register for notifications error", e)
716720
Result.failure(e)
717721
}
718722
}
719723

724+
fun registerForNotificationsAsync(token: String) = scope.launch { registerForNotifications(token) }
725+
720726
suspend fun bumpFeeByRbf(
721727
originalTxId: Txid,
722728
satsPerVByte: UInt,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class CoreService @Inject constructor(
103103
}
104104

105105
try {
106-
val blocktankUrl = Env.blocktankClientServer
106+
val blocktankUrl = Env.blocktankApiUrl
107107
updateBlocktankUrl(newUrl = blocktankUrl)
108108
Logger.info("Blocktank URL updated to: $blocktankUrl")
109109
} catch (e: Exception) {

app/src/main/java/to/bitkit/services/BlocktankNotificationsService.kt renamed to app/src/main/java/to/bitkit/services/LspNotificationsService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import javax.inject.Inject
1717
import javax.inject.Singleton
1818

1919
@Singleton
20-
class BlocktankNotificationsService @Inject constructor(
20+
class LspNotificationsService @Inject constructor(
2121
@BgDispatcher private val bgDispatcher: CoroutineDispatcher,
2222
private val lightningService: LightningService,
2323
private val keychain: Keychain,
@@ -51,7 +51,7 @@ class BlocktankNotificationsService @Inject constructor(
5151
nodeId = nodeId,
5252
isoTimestamp = "$timestamp",
5353
signature = signature,
54-
customUrl = Env.blocktankPushNotificationServer,
54+
customUrl = Env.blocktankNotificationApiUrl,
5555
isProduction = null,
5656
)
5757
}

app/src/main/java/to/bitkit/ui/components/InfoTextField.kt

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

app/src/main/java/to/bitkit/ui/settings/BlocktankRegtestScreen.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.padding
99
import androidx.compose.foundation.rememberScrollState
1010
import androidx.compose.foundation.text.KeyboardOptions
1111
import androidx.compose.foundation.verticalScroll
12-
import androidx.compose.material3.MaterialTheme
1312
import androidx.compose.material3.OutlinedTextField
1413
import androidx.compose.material3.Text
1514
import androidx.compose.material3.TextButton
@@ -29,12 +28,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
2928
import androidx.navigation.NavController
3029
import kotlinx.coroutines.launch
3130
import to.bitkit.R
32-
import to.bitkit.env.Env
3331
import to.bitkit.models.Toast
3432
import to.bitkit.ui.appViewModel
3533
import to.bitkit.ui.components.ButtonSize
34+
import to.bitkit.ui.components.Caption
3635
import to.bitkit.ui.components.Caption13Up
37-
import to.bitkit.ui.components.InfoTextField
3836
import to.bitkit.ui.components.PrimaryButton
3937
import to.bitkit.ui.components.VerticalSpacer
4038
import to.bitkit.ui.navigateToHome
@@ -68,7 +66,6 @@ fun BlocktankRegtestScreen(
6866
.verticalScroll(rememberScrollState())
6967
.imePadding()
7068
) {
71-
// State variables for form inputs
7269
var depositAddress by remember { mutableStateOf(uiState.onchainAddress) }
7370
var depositAmount by remember { mutableStateOf("123000") }
7471
var mineBlockCount by remember { mutableStateOf("1") }
@@ -78,15 +75,11 @@ fun BlocktankRegtestScreen(
7875
var vout by remember { mutableStateOf("0") }
7976
var forceCloseAfter by remember { mutableStateOf("86400") }
8077

81-
// Flags for loading states
8278
var isDepositing by remember { mutableStateOf(false) }
8379
var isMining by remember { mutableStateOf(false) }
8480

85-
InfoTextField(value = Env.blocktankBaseUrl, label = "Service")
86-
Text(
87-
text = "These actions are executed on the staging Blocktank server node.",
88-
style = MaterialTheme.typography.bodySmall,
89-
)
81+
VerticalSpacer(16.dp)
82+
Caption(text = "These actions are executed on the staging Blocktank server node.")
9083

9184
// Deposit Section
9285
Caption13Up("DEPOSIT", color = Colors.White64, modifier = Modifier.padding(top = 20.dp))

0 commit comments

Comments
 (0)