From d5ea5570b63560fadef18fe561bd7c26fc8ddd00 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Sun, 28 Jun 2026 01:28:25 +0000 Subject: [PATCH] chore: improve event syncing (#29) Reviewed-on: https://git.reya.su/reya/coop-mobile/pulls/29 --- composeApp/build.gradle.kts | 2 +- shared/build.gradle.kts | 2 +- .../commonMain/kotlin/su/reya/coop/Nostr.kt | 33 +++++++++---------- .../kotlin/su/reya/coop/NostrViewModel.kt | 8 +++-- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index b6f2e0e..f6be6ff 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -24,7 +24,7 @@ kotlin { implementation(libs.jetbrains.navigation3.ui) implementation(libs.jetbrains.lifecycle.viewmodelNavigation3) implementation(libs.androidx.core.splashscreen) - implementation("su.reya:nostr-sdk-kmp:0.3.1") + implementation("su.reya:nostr-sdk-kmp:0.3.2") implementation("io.coil-kt.coil3:coil-compose:3.4.0") implementation("io.coil-kt.coil3:coil-network-okhttp:3.4.0") implementation("io.github.kalinjul.easyqrscan:scanner:0.7.0") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 89d957d..b9d19bd 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -33,7 +33,7 @@ kotlin { implementation(libs.androidx.lifecycle.runtimeCompose) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.8.0") - implementation("su.reya:nostr-sdk-kmp:0.3.1") + implementation("su.reya:nostr-sdk-kmp:0.3.2") implementation("com.squareup.okio:okio:3.16.2") } androidMain.dependencies { diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt index d5427a0..f6b81ee 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt @@ -57,7 +57,6 @@ import rust.nostr.sdk.extractRelayList import rust.nostr.sdk.initLogger import rust.nostr.sdk.nip17ExtractRelayList import rust.nostr.sdk.nip59MakeGiftWrapAsync -import kotlin.coroutines.cancellation.CancellationException import kotlin.time.Duration object NostrManager { @@ -65,7 +64,8 @@ object NostrManager { val BOOTSTRAP_RELAYS = listOf( "wss://relay.primal.net", - "wss://purplepag.es" + "wss://relay.ditto.pub", + "wss://user.kindpag.es", ) val INDEXER_RELAY = listOf( @@ -286,12 +286,14 @@ class Nostr { launch(Dispatchers.Default) { for (event in giftWrapQueue) { - val rumor = extractRumor(event) ?: continue + val rumor = extractRumor(event) processedCount++ // Trigger new message notification - if (rumor.createdAt().asSecs() >= now.asSecs()) { - onNewMessage(rumor) + if (rumor != null) { + if (rumor.createdAt().asSecs() >= now.asSecs()) { + onNewMessage(rumor) + } } // Update sync state @@ -390,7 +392,7 @@ class Nostr { private suspend fun getMutualContacts(pubkeys: List) { try { val kind = Kind.fromStd(KindStandard.CONTACT_LIST) - val filter = Filter().kind(kind).authors(pubkeys).limit(200u) + val filter = Filter().kind(kind).authors(pubkeys).limit(pubkeys.size.toULong()) val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose) val target = mutableMapOf>() @@ -485,8 +487,6 @@ class Nostr { setCachedRumor(event.id(), unsignedEvent) return unsignedEvent - } catch (e: CancellationException) { - throw e } catch (e: Throwable) { println("Failed to unwrap gift ${event.id().toHex()}: ${e.message}") return null @@ -647,7 +647,7 @@ class Nostr { suspend fun fetchMetadataBatch(keys: List) { try { - val limit = keys.size.toULong() * 4u + val limit = keys.size.toULong() * 2u val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose) // Construct a filter for metadata events @@ -656,16 +656,13 @@ class Nostr { .authors(keys) .limit(limit) - // Construct a target that includes all filters - val target = - ReqTarget.manual( - mapOf( - RelayUrl.parse("wss://purplepag.es") to listOf(filter), - RelayUrl.parse("wss://relay.primal.net") to listOf(filter), - ) - ) + // Construct request target + val target = mutableMapOf>() + NostrManager.BOOTSTRAP_RELAYS.forEach { relay -> + target[RelayUrl.parse(relay)] = listOf(filter) + } - client?.subscribe(target = target, closeOn = opts) + client?.subscribe(target = ReqTarget.manual(target), closeOn = opts) } catch (e: Exception) { throw IllegalStateException("Failed to fetch metadata batch: ${e.message}", e) } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt index ff6e71c..fee7464 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt @@ -82,7 +82,7 @@ class NostrViewModel( val errorEvents = _errorEvents.receiveAsFlow() private val _metadataStore = mutableMapOf>() - + private val metadataRequestChannel = Channel(Channel.UNLIMITED) private val seenPublicKeys = mutableSetOf() @@ -213,16 +213,20 @@ class NostrViewModel( val timeout = 500L // 500ms timeout for batching while (true) { + // Get the first pubkey val firstKey = metadataRequestChannel.receive() batch.add(firstKey) + + // Get current time val lastFlushTime = Clock.System.now().toEpochMilliseconds() while (batch.isNotEmpty()) { + // Get the next pubkey val nextKey = withTimeoutOrNull(timeout.milliseconds) { metadataRequestChannel.receive() } - // Only add the key if it's not null + // Only add the pubkey if it's not null if (nextKey != null) batch.add(nextKey) // Get current time