diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 752c2c6..9c7d9b2 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -26,7 +26,7 @@ kotlin { commonMain.dependencies { implementation("org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - implementation("su.reya:nostr-sdk-kmp:0.1") + implementation("su.reya:nostr-sdk-kmp:0.1.1") } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt index e2c4a35..42d6bb4 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt @@ -30,6 +30,7 @@ import rust.nostr.sdk.Tag import rust.nostr.sdk.Timestamp import rust.nostr.sdk.UnsignedEvent import rust.nostr.sdk.UnwrappedGift +import rust.nostr.sdk.extractMessagingRelayList class Nostr { var client: Client? = null @@ -88,6 +89,14 @@ class Nostr { getUserMetadata() } + suspend fun isSignedByUser(event: Event): Boolean { + return try { + signer?.getPublicKey()?.toBech32() == event.author().toBech32() + } catch (e: Exception) { + false + } + } + suspend fun getUserMetadata() { val userPubkey = signer?.getPublicKey() ?: return @@ -110,9 +119,34 @@ class Nostr { client?.subscribe(target = target, id = "user-metadata", closeOn = opts) } + suspend fun getUserMessages(msgRelayList: Event) { + val userPubkey = signer?.getPublicKey() ?: return + val relays = extractMessagingRelayList(msgRelayList) + + // Ensure relay connections + relays.forEach { relay -> + client?.addRelay(relay, RelayCapabilities.none()) + client?.connectRelay(relay) + } + + // Construct a filter for gift wrap events + val filter = Filter().kind(Kind.fromStd(KindStandard.GIFT_WRAP)).pubkey(userPubkey) + val target = mutableMapOf>() + relays.forEach { relay -> + target[relay] = listOf(filter) + } + + client?.subscribe( + target = ReqTarget.manual(target), + id = "user-messages", + closeOn = null + ) + } + suspend fun handleNotifications(onMetadataUpdate: (PublicKey, Metadata) -> Unit) { val now = Timestamp.now() val notifications = client?.notifications() + val processedEvent = mutableSetOf() while (true) { val notification = notifications?.next() ?: break @@ -126,6 +160,9 @@ class Nostr { is RelayMessageEnum.EventMsg -> { val event = message.event + // Prevent processing duplicate events + if (processedEvent.contains(event.id())) continue + processedEvent.add(event.id()) if (event.kind().asStd() == KindStandard.METADATA) { try { @@ -136,6 +173,12 @@ class Nostr { } } + if (event.kind().asStd() == KindStandard.INBOX_RELAYS) { + if (isSignedByUser(event = event)) { + getUserMessages(msgRelayList = event) + } + } + if (event.kind().asStd() == KindStandard.GIFT_WRAP) { try { val rumor = extractRumor(event)