Handle participants and chat rooms

This commit is contained in:
Kgothatso Ngako
2026-06-02 19:25:57 +02:00
parent 29f4df66f2
commit c6c21db9fc
3 changed files with 66 additions and 15 deletions

View File

@@ -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")
}
}
}
}

View File

@@ -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<PublicKey> = 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<HexKey> = 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"
}
}

View File

@@ -93,6 +93,7 @@ class NavigationViewModel(
init {
observeUnsignedNostrEvents()
// TODO: observePendingUnsignedChatMessages
observePendingBroadcastNostrEventRequests()
observeProfile()
observePendingSyncNostrEventRequests()