From 0719a48f747c21c5eecc7e55aa04dfc1b40fa6da Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Sat, 4 Jul 2026 02:51:23 +0200 Subject: [PATCH] More marmot handling --- .../compose/database/dao/ChatMessageDao.kt | 6 +- .../compose/database/dao/MarmotOutboundDao.kt | 73 ++++++++++++++----- .../repository/DatabaseChatRepository.kt | 4 +- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/ChatMessageDao.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/ChatMessageDao.kt index 78e83f68..4490e849 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/ChatMessageDao.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/ChatMessageDao.kt @@ -4,6 +4,7 @@ import androidx.room3.Dao import androidx.room3.Query import androidx.room3.Transaction import androidx.room3.Upsert +import at.torch.compose.database.model.ChatMessage import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.flow.Flow @@ -18,7 +19,10 @@ interface ChatMessageDao { fun getChatMessagesByChatRoomId(chatRoomId: String): List @Query("SELECT * FROM ChatMessage WHERE giftWrapPayloadId = :giftWrapPayloadId ORDER BY createdAt DESC") - fun getChatMessagesByGiftWrapPayloadId(giftWrapPayloadId: HexKey): at.torch.compose.database.model.ChatMessage? + fun getChatMessagesByGiftWrapPayloadId(giftWrapPayloadId: HexKey): ChatMessage? + + @Query("SELECT * FROM ChatMessage WHERE marmotInnerEventId = :marmotInnerEventId ORDER BY createdAt DESC") + fun getChatMessagesByMarmotInnerEventId(marmotInnerEventId: HexKey): ChatMessage? @Upsert suspend fun upsert(chatMessage: at.torch.compose.database.model.ChatMessage): Long diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotOutboundDao.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotOutboundDao.kt index c1d7a02a..d24e083a 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotOutboundDao.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotOutboundDao.kt @@ -4,11 +4,14 @@ import androidx.room3.Dao import androidx.room3.Transaction import at.torch.compose.database.TorchDatabase import at.torch.compose.database.model.BroadcastNostrEventRequest +import at.torch.compose.database.model.ChatMessageBroadcastNostrEventRequestRelation +import at.torch.compose.database.model.ChatMessageNostrEventRelation import at.torch.compose.database.model.MarmotGroupEvent import at.torch.compose.database.model.MarmotInnerEvent.Companion.disappearingExpiration import at.torch.compose.database.model.NostrEvent import at.torch.compose.database.model.intermdiate.LocalChatRoom import at.torch.compose.extensions.exporterSecret +import at.torch.compose.extensions.toHex import at.torch.compose.nostr.Relays import co.touchlab.kermit.Logger import com.vitorpamplona.quartz.marmot.mip03GroupMessages.GroupEvent @@ -63,6 +66,13 @@ abstract class MarmotOutboundDao( // Step 4: Sign with a fresh ephemeral keypair val ephemeralSigner = NostrSignerInternal(KeyPair()) val groupEvent: GroupEvent = ephemeralSigner.sign(template) + logger.d("groupEvent: $groupEvent") + + database.chatRoomDao().upsert( + localChatRoom.chatRoom.copy( + mlsGroupState = mlsGroup.saveState().encodeTls().toHex() + ) + ) database.nostrEventDao().upsert( NostrEvent( @@ -75,30 +85,57 @@ abstract class MarmotOutboundDao( pubKey = groupEvent.pubKey ) ) - database.marmotGroupEventDao().upsert( - MarmotGroupEvent( - id = groupEvent.id, - createdAt = Instant.fromEpochSeconds(groupEvent.createdAt), - encryptedContent = groupEvent.encryptedContent(), - chatRoomId = localChatRoom.chatRoom.id, - nostrEventId = groupEvent.id, - userPublicKey = nostrSignerSync.pubKey, - publicKey = nostrSignerSync.pubKey - ) - ) - // Sync broadcast to all the required relays... - database.broadcastNostrEventRequestDao().insert( - Relays.DefaultDMRelayList.map { // TODO: Get these from localChatRoom... - BroadcastNostrEventRequest( + val chatMessageOrNull = database.chatMessageDao().getChatMessagesByMarmotInnerEventId(innerEvent.id) + + logger.d("encryptAndSendMarmotInnerEvent: $chatMessageOrNull") + chatMessageOrNull?.let { chatMessage -> + database.chatMessageNostrEventRelationDao().upsert( + ChatMessageNostrEventRelation( + chatMessageId = chatMessage.id, + nostrEventId = groupEvent.id + ) + ) + + database.marmotGroupEventDao().upsert( + MarmotGroupEvent( + id = groupEvent.id, + createdAt = Instant.fromEpochSeconds(groupEvent.createdAt), + encryptedContent = groupEvent.encryptedContent(), + chatRoomId = localChatRoom.chatRoom.id, nostrEventId = groupEvent.id, - relayURL = it.url + userPublicKey = nostrSignerSync.pubKey, + publicKey = nostrSignerSync.pubKey + ) + ) + database.chatMessageDao().upsert( + chatMessage.copy( + marmotGroupEventId = groupEvent.id + ) + ) + + // Sync broadcast to all the required relays... + val broadcastNostrEventRequestIds = database.broadcastNostrEventRequestDao().insert( + Relays.DefaultDMRelayList.map { // TODO: Get these from localChatRoom... + BroadcastNostrEventRequest( + nostrEventId = groupEvent.id, + relayURL = it.url + ) + } + ) + + broadcastNostrEventRequestIds.forEach { broadcastNostrEventRequestId -> + database.chatMessageBroadcastNostrEventRequestRelationDao().upsert( + ChatMessageBroadcastNostrEventRequestRelation( + chatMessageId = chatMessage.id, + broadcastNostrEventRequestId = broadcastNostrEventRequestId + ) ) } - ) + } } companion object { - const val TAG = "NostrNip17Dao" + const val TAG = "MarmotOutboundDao" } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt index c9fa721e..91c109f3 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt @@ -205,12 +205,12 @@ class DatabaseChatRepository( return null } - override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow { + override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow { return database.giftWrapPayloadDao().observeUnsealedGiftWrapPayloads(publicKey) } override suspend fun sealGiftWrapPayload( - giftWrapPayload: at.torch.compose.database.model.GiftWrapPayload, + giftWrapPayload: GiftWrapPayload, nostrSignerSync: NostrSignerSync ) { database.participantDao().findParticipantsByChatRoomId(giftWrapPayload.chatRoomId).forEachIndexed { index, participant ->