From 72018dc208aef968feddd15a85620b8ea34e2555 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 24 Apr 2024 17:04:13 -0400 Subject: [PATCH] Base support for Relay lists for DMs. --- .../amethyst/model/LocalCache.kt | 9 +++ .../service/NostrAccountDataSource.kt | 4 +- .../ui/screen/loggedIn/AccountViewModel.kt | 33 ++++----- .../events/DirectMessageRelayListEvent.kt | 68 +++++++++++++++++++ .../quartz/events/EventFactory.kt | 1 + 5 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/events/DirectMessageRelayListEvent.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 295872dc6..82346fcef 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -63,6 +63,7 @@ import com.vitorpamplona.quartz.events.CommunityListEvent import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent import com.vitorpamplona.quartz.events.ContactListEvent import com.vitorpamplona.quartz.events.DeletionEvent +import com.vitorpamplona.quartz.events.DirectMessageRelayListEvent import com.vitorpamplona.quartz.events.DraftEvent import com.vitorpamplona.quartz.events.EmojiPackEvent import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent @@ -699,6 +700,13 @@ object LocalCache { consumeBaseReplaceable(event, relay) } + private fun consume( + event: DirectMessageRelayListEvent, + relay: Relay?, + ) { + consumeBaseReplaceable(event, relay) + } + private fun consume( event: CommunityDefinitionEvent, relay: Relay?, @@ -2265,6 +2273,7 @@ object LocalCache { } is ContactListEvent -> consume(event) is DeletionEvent -> consume(event) + is DirectMessageRelayListEvent -> consume(event, relay) is DraftEvent -> consume(event, relay) is EmojiPackEvent -> consume(event, relay) is EmojiPackSelectionEvent -> consume(event, relay) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index ab99040c1..919e1e37e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -40,6 +40,7 @@ import com.vitorpamplona.quartz.events.CalendarRSVPEvent import com.vitorpamplona.quartz.events.CalendarTimeSlotEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ContactListEvent +import com.vitorpamplona.quartz.events.DirectMessageRelayListEvent import com.vitorpamplona.quartz.events.DraftEvent import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent import com.vitorpamplona.quartz.events.Event @@ -101,7 +102,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { types = COMMON_FEED_TYPES, filter = JsonFilter( - kinds = listOf(AdvertisedRelayListEvent.KIND, StatusEvent.KIND), + kinds = listOf(StatusEvent.KIND, AdvertisedRelayListEvent.KIND, DirectMessageRelayListEvent.KIND), authors = listOf(account.userProfile().pubkeyHex), limit = 5, ), @@ -119,6 +120,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { MetadataEvent.KIND, ContactListEvent.KIND, AdvertisedRelayListEvent.KIND, + DirectMessageRelayListEvent.KIND, MuteListEvent.KIND, PeopleListEvent.KIND, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 1c15b6063..4fedfa8f0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -1409,30 +1409,27 @@ public suspend fun collectSuccessfulSigningOperations( return } - val (value, elapsed) = - measureTimedValue { - coroutineScope { - val jobs = - operationsInput.map { - async { - val result = - withTimeoutOrNull(10000) { - suspendCancellableCoroutine { continuation -> - runRequestFor(it) { result: K -> continuation.resume(result) } - } - } - if (result != null) { - output[it] = result + coroutineScope { + val jobs = + operationsInput.map { + async { + val result = + withTimeoutOrNull(10000) { + suspendCancellableCoroutine { continuation -> + runRequestFor(it) { result: K -> continuation.resume(result) } } } + if (result != null) { + output[it] = result } - - // runs in parallel to avoid overcrowding Amber. - withTimeoutOrNull(15000) { - jobs.joinAll() } } + + // runs in parallel to avoid overcrowding Amber. + withTimeoutOrNull(15000) { + jobs.joinAll() } + } onReady(output) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/DirectMessageRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/DirectMessageRelayListEvent.kt new file mode 100644 index 000000000..b7eb3b451 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/DirectMessageRelayListEvent.kt @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.events + +import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.encoders.HexKey +import com.vitorpamplona.quartz.signers.NostrSigner +import com.vitorpamplona.quartz.utils.TimeUtils + +@Immutable +class DirectMessageRelayListEvent( + id: HexKey, + pubKey: HexKey, + createdAt: Long, + tags: Array>, + content: String, + sig: HexKey, +) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { + override fun dTag() = FIXED_D_TAG + + fun relays(): List { + return tags.mapNotNull { + if (it.size > 1 && it[0] == "relay") { + it[1] + } else { + null + } + } + } + + companion object { + const val KIND = 10050 + const val FIXED_D_TAG = "" + + fun create( + relays: List, + signer: NostrSigner, + createdAt: Long = TimeUtils.now(), + onReady: (DirectMessageRelayListEvent) -> Unit, + ) { + val tags = + relays.map { + arrayOf("relay", it) + }.plusElement(arrayOf("alt", "Relay list for private messages")).toTypedArray() + val msg = "" + + signer.sign(createdAt, KIND, tags, msg, onReady) + } + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/EventFactory.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/EventFactory.kt index d923354c8..ed5346c3d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/EventFactory.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/EventFactory.kt @@ -79,6 +79,7 @@ class EventFactory { CommunityPostApprovalEvent(id, pubKey, createdAt, tags, content, sig) ContactListEvent.KIND -> ContactListEvent(id, pubKey, createdAt, tags, content, sig) DeletionEvent.KIND -> DeletionEvent(id, pubKey, createdAt, tags, content, sig) + DirectMessageRelayListEvent.KIND -> DirectMessageRelayListEvent(id, pubKey, createdAt, tags, content, sig) DraftEvent.KIND -> DraftEvent(id, pubKey, createdAt, tags, content, sig) EmojiPackEvent.KIND -> EmojiPackEvent(id, pubKey, createdAt, tags, content, sig) EmojiPackSelectionEvent.KIND ->