ensure relay disconnect on background

This commit is contained in:
2026-06-06 15:46:13 +07:00
parent 6bd4c53445
commit 550fd3e527
2 changed files with 65 additions and 16 deletions

View File

@@ -38,6 +38,7 @@ import rust.nostr.sdk.PublicKey
import rust.nostr.sdk.RelayCapabilities
import rust.nostr.sdk.RelayMessageEnum
import rust.nostr.sdk.RelayMetadata
import rust.nostr.sdk.RelayStatus
import rust.nostr.sdk.RelayUrl
import rust.nostr.sdk.ReqExitPolicy
import rust.nostr.sdk.ReqTarget
@@ -59,6 +60,18 @@ import kotlin.time.Duration.Companion.milliseconds
object NostrManager {
val instance = Nostr()
val BOOTSTRAP_RELAYS = listOf(
"wss://relay.primal.net",
"wss://user.kindpag.es",
"wss://purplepag.es"
)
val INDEXER_RELAY = listOf(
"wss://indexer.coracle.social",
)
val ALL_RELAYS = BOOTSTRAP_RELAYS + INDEXER_RELAY
}
class Nostr {
@@ -75,7 +88,6 @@ class Nostr {
private val isInitialized = MutableStateFlow(false)
// Add these to the Nostr class
private val _newEvents = MutableSharedFlow<UnsignedEvent>(extraBufferCapacity = 100)
val newEvents = _newEvents.asSharedFlow()
@@ -144,24 +156,43 @@ class Nostr {
}
suspend fun connectBootstrapRelays() {
// Bootstrap relays
client?.addRelay(RelayUrl.parse("wss://relay.primal.net"))
client?.addRelay(RelayUrl.parse("wss://user.kindpag.es"))
client?.addRelay(RelayUrl.parse("wss://purplepag.es"))
// Indexer relay for NIP-65 discovery
NostrManager.BOOTSTRAP_RELAYS.forEach { url ->
client?.addRelay(RelayUrl.parse(url))
}
NostrManager.INDEXER_RELAY.forEach { url ->
client?.addRelay(
url = RelayUrl.parse("wss://indexer.coracle.social"),
url = RelayUrl.parse(url),
capabilities = RelayCapabilities.gossip()
)
}
// Connect to all bootstrap relays
client?.connect()
}
// Connect to all bootstrap relays and wait for all connections to be established
client?.connect(Duration.parse("2s"))
suspend fun reconnect() {
NostrManager.ALL_RELAYS.forEach { url ->
try {
client?.relay(RelayUrl.parse(url)).let { relay ->
if (relay != null) {
if (relay.status() != RelayStatus.CONNECTED) {
relay.connect()
}
}
}
} catch (e: Exception) {
println("Failed to reconnect relay: ${e.message}")
}
}
}
suspend fun disconnect() {
client?.shutdown()
NostrManager.ALL_RELAYS.forEach { url ->
try {
client?.disconnectRelay(RelayUrl.parse(url))
} catch (e: Exception) {
println("Failed to disconnect relay: ${e.message}")
}
}
}
suspend fun exit() {

View File

@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import io.ktor.client.HttpClient
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -15,6 +16,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.json.Json
import rust.nostr.sdk.AsyncNostrSigner
@@ -85,6 +87,9 @@ class NostrViewModel(
// Check local stored secret (secret key or bunker)
login()
// Automatically reconnect bootstrap relays
reconnect()
// Observe the signer state and verify the relay list
observeSignerAndCheckRelays()
@@ -100,7 +105,13 @@ class NostrViewModel(
override fun onCleared() {
super.onCleared()
// TODO: optimize relay connection
// Disconnect to all bootstrap relays
viewModelScope.launch {
withContext(NonCancellable) {
nostr.disconnect()
}
}
}
private fun showError(message: String) {
@@ -116,6 +127,13 @@ class NostrViewModel(
}
}
private fun reconnect() {
viewModelScope.launch {
nostr.waitUntilInitialized()
nostr.reconnect()
}
}
private fun runObserver() {
viewModelScope.launch {
// Observe new messages