From 01fe09c86630650fb9ab25a5576cb23ed162a58a Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 26 Apr 2024 09:25:15 -0300 Subject: [PATCH] better connection to relays when using push notifications --- app/build.gradle | 1 + .../greenart7c3/nostrsigner/relays/Client.kt | 11 +++++++ .../nostrsigner/relays/RelayPool.kt | 24 +++++++++++++- .../nostrsigner/service/IntentUtils.kt | 7 ++++- .../service/RelayDisconnectService.kt | 31 +++++++++++++++++++ .../nostrsigner/ui/AccountScreen.kt | 1 + .../nostrsigner/ui/EditPermission.kt | 10 ++++-- .../greenart7c3/nostrsigner/ui/MainScreen.kt | 20 ++++++------ .../ui/components/MultiEventHomeScreen.kt | 22 ++++++------- gradle/libs.versions.toml | 2 ++ 10 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/greenart7c3/nostrsigner/service/RelayDisconnectService.kt diff --git a/app/build.gradle b/app/build.gradle index 27eef173..3140e7ca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,6 +115,7 @@ dependencies { implementation libs.material.icons.extended implementation libs.appcompat + implementation libs.work.runtime.ktx testImplementation libs.junit testImplementation libs.mockk diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/relays/Client.kt b/app/src/main/java/com/greenart7c3/nostrsigner/relays/Client.kt index 640463a9..d12349f8 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/relays/Client.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/relays/Client.kt @@ -40,6 +40,17 @@ object Client : RelayPool.Listener { private var relays = emptyArray() private var subscriptions = mapOf>() + @Synchronized + fun addRelays(relays: Array) { + if (isSameRelaySetConfig(relays)) return + RelayPool.disconnect() + RelayPool.unregister(this) + RelayPool.unloadRelays() + RelayPool.register(this) + RelayPool.loadRelays(relays.toList()) + Client.relays = relays + } + @Synchronized fun reconnect( relays: Array?, diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/relays/RelayPool.kt b/app/src/main/java/com/greenart7c3/nostrsigner/relays/RelayPool.kt index 6edf8b91..8cbd8eee 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/relays/RelayPool.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/relays/RelayPool.kt @@ -24,10 +24,15 @@ import androidx.compose.runtime.Immutable import com.greenart7c3.nostrsigner.checkNotInMainThread import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.EventInterface +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch /** * RelayPool manages the connection to multiple Relays and lets consumers deal with simple events. @@ -91,6 +96,7 @@ object RelayPool : Relay.Listener { return listeners.isNotEmpty() } + @OptIn(DelicateCoroutinesApi::class) fun sendToSelectedRelays( list: List, signedEvent: EventInterface, @@ -100,7 +106,23 @@ object RelayPool : Relay.Listener { list.forEach { relay -> relays.filter { it.url == relay.url }.forEach { it.onLoading = onLoading - it.send(signedEvent, onDone) + if (!it.isConnected()) { + it.connectAndRun { + it.send(signedEvent, onDone) + GlobalScope.launch(Dispatchers.IO) { + delay(60000) + if (relay.isConnected()) { + relay.disconnect() + + if (onDone != null) { + onDone() + } + } + } + } + } else { + it.send(signedEvent, onDone) + } } } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt index ff83ee25..fbf4f004 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.greenart7c3.nostrsigner.LocalPreferences import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.CompressionType import com.greenart7c3.nostrsigner.models.IntentData @@ -23,6 +24,7 @@ import com.greenart7c3.nostrsigner.relays.Relay import com.greenart7c3.nostrsigner.relays.RelayPool import com.greenart7c3.nostrsigner.service.model.AmberEvent import com.greenart7c3.nostrsigner.ui.BunkerResponse +import com.greenart7c3.nostrsigner.ui.NotificationType import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.encoders.toNpub @@ -172,7 +174,10 @@ object IntentUtils { } } } - Client.reconnect(savedRelays.toTypedArray()) + Client.addRelays(relays.toTypedArray()) + if (LocalPreferences.getNotificationType() == NotificationType.DIRECT) { + Client.reconnect(relays.toTypedArray()) + } delay(1000) } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/RelayDisconnectService.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/RelayDisconnectService.kt new file mode 100644 index 00000000..7f91f7ed --- /dev/null +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/RelayDisconnectService.kt @@ -0,0 +1,31 @@ +package com.greenart7c3.nostrsigner.service + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.greenart7c3.nostrsigner.relays.RelayPool +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking + +class RelayDisconnectService(ctx: Context, params: WorkerParameters) : Worker(ctx, params) { + private val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + + override fun doWork(): Result { + val job = ioScope.launch { + val url = inputData.getString("relay") + delay(60000) + url?.let { + val relay = RelayPool.getRelay(it) + if (relay != null && relay.isConnected()) { + relay.disconnect() + } + } + } + runBlocking { job.join() } + return Result.success() + } +} diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt index ccd580aa..e53fb8ab 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt @@ -80,6 +80,7 @@ fun AccountScreen( } } delay(1000) + Client.addRelays(relays.toTypedArray()) if (LocalPreferences.getNotificationType() == NotificationType.DIRECT && BuildConfig.FLAVOR != "offline") { nostrsigner.instance.applicationContext.startService(Intent(nostrsigner.instance.applicationContext, ConnectivityService::class.java)) Client.reconnect(relays.toTypedArray()) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt index dc75792d..511d1132 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt @@ -274,7 +274,10 @@ fun EditPermission( } } } - Client.reconnect(relays.toTypedArray()) + Client.addRelays(relays.toTypedArray()) + if (LocalPreferences.getNotificationType() == NotificationType.DIRECT) { + Client.reconnect(relays.toTypedArray()) + } } scope.launch(Dispatchers.Main) { @@ -509,7 +512,10 @@ fun EditPermission( } } } - Client.reconnect(relays.toTypedArray()) + Client.addRelays(relays.toTypedArray()) + if (LocalPreferences.getNotificationType() == NotificationType.DIRECT) { + Client.reconnect(relays.toTypedArray()) + } scope.launch(Dispatchers.Main) { navController.popBackStack() diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt index 80b64ae9..e0e437ec 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt @@ -74,6 +74,9 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument +import androidx.work.Data +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager import com.greenart7c3.nostrsigner.BuildConfig import com.greenart7c3.nostrsigner.LocalPreferences import com.greenart7c3.nostrsigner.R @@ -87,12 +90,13 @@ import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.ReturnType import com.greenart7c3.nostrsigner.models.SignerType +import com.greenart7c3.nostrsigner.nostrsigner import com.greenart7c3.nostrsigner.relays.Relay import com.greenart7c3.nostrsigner.relays.RelayPool import com.greenart7c3.nostrsigner.service.EventNotificationConsumer import com.greenart7c3.nostrsigner.service.IntentUtils -import com.greenart7c3.nostrsigner.service.NotificationDataSource import com.greenart7c3.nostrsigner.service.PushNotificationUtils +import com.greenart7c3.nostrsigner.service.RelayDisconnectService import com.greenart7c3.nostrsigner.service.getAppCompatActivity import com.greenart7c3.nostrsigner.service.toShortenHex import com.greenart7c3.nostrsigner.ui.actions.AccountsBottomSheet @@ -103,7 +107,6 @@ import com.vitorpamplona.quartz.encoders.toNpub import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.io.ByteArrayOutputStream import java.util.Base64 @@ -139,14 +142,11 @@ fun sendResult( RelayPool.getAll().forEach { relay -> if (!relay.isConnected()) { relay.connectAndRun { - if (!NotificationDataSource.isActive()) { - GlobalScope.launch(Dispatchers.IO) { - delay(60000) - if (relay.isConnected()) { - relay.disconnect() - } - } - } + val builder = OneTimeWorkRequest.Builder(RelayDisconnectService::class.java) + val inputData = Data.Builder() + inputData.putString("relay", relay.url) + builder.setInputData(inputData.build()) + WorkManager.getInstance(nostrsigner.instance).enqueue(builder.build()) } } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt index 90063b6c..169b90d8 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt @@ -39,6 +39,9 @@ import androidx.compose.ui.text.toLowerCase import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.work.Data +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager import com.google.gson.GsonBuilder import com.greenart7c3.nostrsigner.LocalPreferences import com.greenart7c3.nostrsigner.R @@ -47,6 +50,7 @@ import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.SignerType +import com.greenart7c3.nostrsigner.nostrsigner import com.greenart7c3.nostrsigner.relays.Relay import com.greenart7c3.nostrsigner.relays.RelayPool import com.greenart7c3.nostrsigner.service.AmberUtils @@ -54,6 +58,7 @@ import com.greenart7c3.nostrsigner.service.ApplicationNameCache import com.greenart7c3.nostrsigner.service.EventNotificationConsumer import com.greenart7c3.nostrsigner.service.IntentUtils import com.greenart7c3.nostrsigner.service.NotificationDataSource +import com.greenart7c3.nostrsigner.service.RelayDisconnectService import com.greenart7c3.nostrsigner.service.getAppCompatActivity import com.greenart7c3.nostrsigner.service.model.AmberEvent import com.greenart7c3.nostrsigner.service.toShortenHex @@ -64,8 +69,6 @@ import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.LnZapRequestEvent import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay import kotlinx.coroutines.launch @OptIn(DelicateCoroutinesApi::class) @@ -141,16 +144,13 @@ fun MultiEventHomeScreen( val results = mutableListOf() if (intents.any { it.bunkerRequest != null }) { RelayPool.getAll().forEach { relay -> - if (!relay.isConnected()) { + if (!relay.isConnected() && !NotificationDataSource.isActive()) { relay.connectAndRun { - if (!NotificationDataSource.isActive()) { - GlobalScope.launch(Dispatchers.IO) { - delay(60000) - if (relay.isConnected()) { - relay.disconnect() - } - } - } + val builder = OneTimeWorkRequest.Builder(RelayDisconnectService::class.java) + val inputData = Data.Builder() + inputData.putString("relay", relay.url) + builder.setInputData(inputData.build()) + WorkManager.getInstance(nostrsigner.instance).enqueue(builder.build()) } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8519a3ac..f27e0590 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,7 @@ securityCryptoKtx = "1.1.0-alpha06" zxingAndroidEmbedded = "4.3.0" okhttp = "5.0.0-alpha.14" kotlin = "1.9.23" +workRuntimeKtx = "2.9.0" [libraries] activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" } @@ -63,6 +64,7 @@ ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose_ui" } zxing-android-embedded = { module = "com.journeyapps:zxing-android-embedded", version.ref = "zxingAndroidEmbedded" } okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workRuntimeKtx" } [plugins] jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }