chore: improve event syncing (#29)

Reviewed-on: #29
This commit was merged in pull request #29.
This commit is contained in:
2026-06-28 01:28:25 +00:00
parent 26f9e577f4
commit d5ea5570b6
4 changed files with 23 additions and 22 deletions

View File

@@ -24,7 +24,7 @@ kotlin {
implementation(libs.jetbrains.navigation3.ui) implementation(libs.jetbrains.navigation3.ui)
implementation(libs.jetbrains.lifecycle.viewmodelNavigation3) implementation(libs.jetbrains.lifecycle.viewmodelNavigation3)
implementation(libs.androidx.core.splashscreen) 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-compose:3.4.0")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.4.0") implementation("io.coil-kt.coil3:coil-network-okhttp:3.4.0")
implementation("io.github.kalinjul.easyqrscan:scanner:0.7.0") implementation("io.github.kalinjul.easyqrscan:scanner:0.7.0")

View File

@@ -33,7 +33,7 @@ kotlin {
implementation(libs.androidx.lifecycle.runtimeCompose) implementation(libs.androidx.lifecycle.runtimeCompose)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.8.0") 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") implementation("com.squareup.okio:okio:3.16.2")
} }
androidMain.dependencies { androidMain.dependencies {

View File

@@ -57,7 +57,6 @@ import rust.nostr.sdk.extractRelayList
import rust.nostr.sdk.initLogger import rust.nostr.sdk.initLogger
import rust.nostr.sdk.nip17ExtractRelayList import rust.nostr.sdk.nip17ExtractRelayList
import rust.nostr.sdk.nip59MakeGiftWrapAsync import rust.nostr.sdk.nip59MakeGiftWrapAsync
import kotlin.coroutines.cancellation.CancellationException
import kotlin.time.Duration import kotlin.time.Duration
object NostrManager { object NostrManager {
@@ -65,7 +64,8 @@ object NostrManager {
val BOOTSTRAP_RELAYS = listOf( val BOOTSTRAP_RELAYS = listOf(
"wss://relay.primal.net", "wss://relay.primal.net",
"wss://purplepag.es" "wss://relay.ditto.pub",
"wss://user.kindpag.es",
) )
val INDEXER_RELAY = listOf( val INDEXER_RELAY = listOf(
@@ -286,12 +286,14 @@ class Nostr {
launch(Dispatchers.Default) { launch(Dispatchers.Default) {
for (event in giftWrapQueue) { for (event in giftWrapQueue) {
val rumor = extractRumor(event) ?: continue val rumor = extractRumor(event)
processedCount++ processedCount++
// Trigger new message notification // Trigger new message notification
if (rumor.createdAt().asSecs() >= now.asSecs()) { if (rumor != null) {
onNewMessage(rumor) if (rumor.createdAt().asSecs() >= now.asSecs()) {
onNewMessage(rumor)
}
} }
// Update sync state // Update sync state
@@ -390,7 +392,7 @@ class Nostr {
private suspend fun getMutualContacts(pubkeys: List<PublicKey>) { private suspend fun getMutualContacts(pubkeys: List<PublicKey>) {
try { try {
val kind = Kind.fromStd(KindStandard.CONTACT_LIST) 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 opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose)
val target = mutableMapOf<RelayUrl, List<Filter>>() val target = mutableMapOf<RelayUrl, List<Filter>>()
@@ -485,8 +487,6 @@ class Nostr {
setCachedRumor(event.id(), unsignedEvent) setCachedRumor(event.id(), unsignedEvent)
return unsignedEvent return unsignedEvent
} catch (e: CancellationException) {
throw e
} catch (e: Throwable) { } catch (e: Throwable) {
println("Failed to unwrap gift ${event.id().toHex()}: ${e.message}") println("Failed to unwrap gift ${event.id().toHex()}: ${e.message}")
return null return null
@@ -647,7 +647,7 @@ class Nostr {
suspend fun fetchMetadataBatch(keys: List<PublicKey>) { suspend fun fetchMetadataBatch(keys: List<PublicKey>) {
try { try {
val limit = keys.size.toULong() * 4u val limit = keys.size.toULong() * 2u
val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose) val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose)
// Construct a filter for metadata events // Construct a filter for metadata events
@@ -656,16 +656,13 @@ class Nostr {
.authors(keys) .authors(keys)
.limit(limit) .limit(limit)
// Construct a target that includes all filters // Construct request target
val target = val target = mutableMapOf<RelayUrl, List<Filter>>()
ReqTarget.manual( NostrManager.BOOTSTRAP_RELAYS.forEach { relay ->
mapOf( target[RelayUrl.parse(relay)] = listOf(filter)
RelayUrl.parse("wss://purplepag.es") to listOf(filter), }
RelayUrl.parse("wss://relay.primal.net") to listOf(filter),
)
)
client?.subscribe(target = target, closeOn = opts) client?.subscribe(target = ReqTarget.manual(target), closeOn = opts)
} catch (e: Exception) { } catch (e: Exception) {
throw IllegalStateException("Failed to fetch metadata batch: ${e.message}", e) throw IllegalStateException("Failed to fetch metadata batch: ${e.message}", e)
} }

View File

@@ -213,16 +213,20 @@ class NostrViewModel(
val timeout = 500L // 500ms timeout for batching val timeout = 500L // 500ms timeout for batching
while (true) { while (true) {
// Get the first pubkey
val firstKey = metadataRequestChannel.receive() val firstKey = metadataRequestChannel.receive()
batch.add(firstKey) batch.add(firstKey)
// Get current time
val lastFlushTime = Clock.System.now().toEpochMilliseconds() val lastFlushTime = Clock.System.now().toEpochMilliseconds()
while (batch.isNotEmpty()) { while (batch.isNotEmpty()) {
// Get the next pubkey
val nextKey = withTimeoutOrNull(timeout.milliseconds) { val nextKey = withTimeoutOrNull(timeout.milliseconds) {
metadataRequestChannel.receive() 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) if (nextKey != null) batch.add(nextKey)
// Get current time // Get current time