From c6c21db9fc479168cd01b0ce673370477f681ba9 Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Tue, 2 Jun 2026 19:25:57 +0200 Subject: [PATCH] Handle participants and chat rooms --- .../compose/database/dao/NostrDao.kt | 37 ++++++++++------ .../compose/database/model/GiftWrapPayload.kt | 43 +++++++++++++++++-- .../ui/view/model/NavigationViewModel.kt | 1 + 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt index dabcfd08..4884fe8c 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt @@ -10,6 +10,7 @@ import ac.cord.auxiliary.compose.database.model.Mention import ac.cord.auxiliary.compose.database.model.NegentropySynchronizeRequest import ac.cord.auxiliary.compose.database.model.NostrEvent import ac.cord.auxiliary.compose.database.model.NostrEventRelay +import ac.cord.auxiliary.compose.database.model.Participant import ac.cord.auxiliary.compose.database.model.Post import ac.cord.auxiliary.compose.database.model.Profile import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent @@ -24,7 +25,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent -import fr.acinq.bitcoin.crypto.musig2.Musig2 import kotlin.time.Clock import kotlin.time.Instant @@ -352,14 +352,10 @@ abstract class NostrDao( giftWrapPayload ) - val receiverPublicKeys = giftWrapPayload.receiverPublicKeys() - logger.d("receiverPublicKeys: $receiverPublicKeys") - - if (receiverPublicKeys.isNotEmpty()) { - val chatRoomId = Musig2.aggregateKeys( - giftWrapPayload.receiverPublicKeys() - ).value.toHex() - // Process chatMessage and chatRoom stuff... + val musig2AggregatedPublicKey = giftWrapPayload.aggregateParticipantsPublicKeys() + if (musig2AggregatedPublicKey != null) { + val chatRoomId = musig2AggregatedPublicKey.value.toHex() + logger.d("ChatRoomId: $chatRoomId") // Find or create chatRoom val localChatRoom = database.chatRoomDao().findChatRoomById( chatRoomId @@ -375,11 +371,27 @@ abstract class NostrDao( initialGiftWrapUnsignedId = giftWrapPayload.id ) ) + + // Add participants... + database.participantDao().upsert( + giftWrapPayload.receiverPubKeys().map { + Participant( + participantPublicKey = it, + chatRoomId = chatRoomId + ) + } + ) } else { - // TODO: Update subject from tags... + giftWrapPayload.parseSubject()?.let { subject -> + database.chatRoomDao().upsert( + localChatRoom.chatRoom.copy( + subject = subject, + updatedAt = giftWrapPayload.createdAt + ) + ) + } } - // Save chatMessage database.chatMessageDao().upsert( ChatMessage( giftWrapPayloadId = giftWrapPayload.id, @@ -390,8 +402,9 @@ abstract class NostrDao( content = giftWrapPayload.content, ) ) + } else { + logger.w("Failed to setup chatRoom for message") } - } } } diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/GiftWrapPayload.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/GiftWrapPayload.kt index 427602de..0365f021 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/GiftWrapPayload.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/GiftWrapPayload.kt @@ -7,10 +7,15 @@ import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity import androidx.room3.Entity import androidx.room3.ForeignKey import androidx.room3.PrimaryKey +import co.touchlab.kermit.Logger import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Kind +import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers +import com.vitorpamplona.quartz.nip14Subject.subject import fr.acinq.bitcoin.PublicKey +import fr.acinq.bitcoin.XonlyPublicKey +import fr.acinq.bitcoin.crypto.musig2.Musig2 import kotlin.time.Clock import kotlin.time.Instant @@ -73,17 +78,45 @@ data class GiftWrapPayload( // TODO: Rename this to GiftWrapPayload... override val viewedAt: Instant? = null, override val deletedAt: Instant? = null, // Who this message should be seen by (used to derive conversationId) ): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity { + val logger = Logger.withTag(TAG) - fun receiverPublicKeys(): List = try { - tags.taggedUsers().map { + fun aggregateParticipantsPublicKeys(): XonlyPublicKey? = try { + logger.d("aggregateParticipantsPublicKeys") + val hexKeys = tags.taggedUsers().map { + it.pubKey + } + + logger.d("HexKeys: $hexKeys") + val publicKeys = hexKeys.map { PublicKey( - it.pubKey.hexToByteArray() + PublicKey.compress(it.hexToByteArray()) ) } + logger.d("PublicKeys: $publicKeys") + + val chatRoomXOnlyPublicKey = Musig2.aggregateKeys( + publicKeys + ) + logger.d("ChatRoomXOnly: $chatRoomXOnlyPublicKey") + + return chatRoomXOnlyPublicKey + } catch (e: Throwable) { + logger.e("Failed to aggregate participants publicKeys", e) + return null + } + + fun receiverPubKeys(): List = try { + tags.taggedUsers().map { + it.pubKey + } } catch (e: Throwable) { return emptyList() } + fun parseSubject(): String? { + return tags.subject() + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -121,4 +154,8 @@ data class GiftWrapPayload( // TODO: Rename this to GiftWrapPayload... result = 31 * result + (deletedAt?.hashCode() ?: 0) return result } + + companion object { + const val TAG = "GiftWrapPayload" + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt index f5bd441d..154be87b 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt @@ -93,6 +93,7 @@ class NavigationViewModel( init { observeUnsignedNostrEvents() + // TODO: observePendingUnsignedChatMessages observePendingBroadcastNostrEventRequests() observeProfile() observePendingSyncNostrEventRequests()